diff --git a/Courses/Default/Jupiter.crs b/Courses/Default/Jupiter.crs new file mode 100644 index 0000000000..85dbbc9cf5 --- /dev/null +++ b/Courses/Default/Jupiter.crs @@ -0,0 +1,8 @@ +#COURSE:Jupiter; +#SCRIPTER:Midiman; + +#GAINSECONDS:120; +#SONG:*:Hard; + +#GAINSECONDS:25; +#SONG:*:Hard; \ No newline at end of file diff --git a/Data/AI.ini b/Data/AI.ini index c2584caf8f..421c8757b7 100644 --- a/Data/AI.ini +++ b/Data/AI.ini @@ -39,17 +39,17 @@ WeightW2=30 WeightW1=50 [Skill5] -WeightMiss= -WeightW5=1 -WeightW4=1 +WeightMiss=2 +WeightW5=3 +WeightW4=5 WeightW3=5 WeightW2=30 WeightW1=55 [Skill6] -WeightMiss= -WeightW5= -WeightW4= +WeightMiss=2 +WeightW5=3 +WeightW4=5 WeightW3=5 WeightW2=30 -WeightW1=70 +WeightW1=55 diff --git a/Docs/Changelog_SSCformat.txt b/Docs/Changelog_SSCformat.txt index ee7909d2ed..75c9fe55ec 100644 --- a/Docs/Changelog_SSCformat.txt +++ b/Docs/Changelog_SSCformat.txt @@ -9,6 +9,34 @@ change to JSON, but it is unsure if this will be done. Implement .ssc at your own risk. ________________________________________________________________________________ +[v0.77] - Wolfman2000 +* Add the cache tag #STEPFILENAME to gain access to the proper #NOTES when + required. + +[v0.76] - Wolfman2000 +* Expand the #COMBOS tag to allow for Miss Combos. Anyone that is crazy enough + to put in a 51 miss combo in their tags should be...oh wait: it's already + been done. + +[v0.75] - Wolfman2000 +* Add Step based #DISPLAYBPM for those songs that have...very varied syncing. + +[v0.74] - Wolfman2000 +* Add #CHARTNAME tag for the title of the chart. +* Older files will have their #DESCRIPTION tag content copied to #CHARTNAME + on load. + +[v0.73] - Wolfman2000 +* Use #FIRSTSECOND, #LASTSECOND, and #LASTSECONDHINT instead of the BEAT + equivalents. +* Move #LASTSECONDHINT to after the Timing tags. + +[v0.72] - Wolfman2000 +* Have #OFFSET come before #ATTACKS in the Step data. + +[v0.71] - Wolfman2000 +* Have #ATTACKS work per step as well. + [v0.7] - theDtTvB, Wolfman2000 * Split Timing officially implemented. * #SPEEDS tag for modified scroll speeds. diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 6dc057dfb3..ce445d891e 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -5,9 +5,255 @@ from StepMania 4 alpha 5 to sm-ssc v1.2.5, see Changelog_sm-ssc.txt. ________________________________________________________________________________ ================================================================================ -StepMania 5.0 Preview 2 | 20110??? +StepMania 5.0 ????????? | 20110??? -------------------------------------------------------------------------------- +2011/07/19 +---------- +* [LoadingWindow] Added the ability for themes to have custom splash banners. + (Currently Windows-only.) [AJ] + +2011/07/17 +---------- +* [Cache] No longer store #NOTES in the cache. This should speed things up + on the first load if there is not much to write. (General note: this was + taken from another branch, but results at that point were great.) + [Wolfman2000] + +2011/07/13 +---------- +* [Difficulty] Allow ALL StepsTypes to use CustomDifficulty properly. + There was some unfair targeting of Couple and Routine. [Wolfman2000] +* [Steps] Calculate accurate radar values for Couple charts. [Wolfman2000] +* [ScreenEdit] Display more accurate chart data for Couple and Routine charts + for the future. No more having (almost) every row as a jump! [Wolfman2000] + +2011/07/12 +---------- +* [OptionRowHandler] Add a new metric to ScreenOptionsMaster: + StepsUseChartName. Use this if you want your charts to have a unique name + in the options menu. If there is no #CHARTNAME or it is "Blank", it reverts + to the original behavior. This metric is false by default. [Wolfman2000] +* [ScreenEdit] Fixed a bug involving #ATTACKS. Now when you set an attack, + the mods are reverted back to how they were prior to the attack being set. + [Wolfman2000] + +2011/07/09 +---------- +* [NotesTheUsual] Update the #COMBOS tag to allow for a Miss Combo attribute. + Any files that only use the Combo attribute will have that value copied to + miss combo on next launch. [Wolfman2000] +* [ScoreKeeperNormal] Better match #COMBOS with eval. Scoring formulas should + not be affected, but it may require more testing. [Wolfman2000] +* [Metrics] Have Pump mode lump the checkpoint judgments with Flawless and + Miss judgments on eval. Of course, this goes down to Perfect and Miss if + that is disabled. [Wolfman2000] + +2011/07/07 +---------- +* [ScreenEdit] Fix the NoMines transformation bug, issue 363. [Wolfman2000] +* [CourseLoaderCRS] Don't load BEST# and WORST# where # is greater than the + number of songs installed. Fixes issue 373. [AJ] +* [NotesAllSSC] Add the #CHARTNAME tag to the Steps. #DESCRIPTION is now for + more detailed descriptions, or perhaps some short hand lingo. All files + that used #DESCRIPTION will have their values moved to #CHARTNAME on + load. [Wolfman2000] +* [ScreenEdit] Add a Steps Data menu for getting numerical step data on the + chart. This is a read only menu. Edit Steps Information contains writable + information. [Wolfman2000] +* [NotesAllSSC] Add the Steps version of #DISPLAYBPM. The Song version is + still there, so themes should not have to worry about breakage. + [Wolfman2000] + +2011/07/06 +---------- +* [ScreenEdit] Fix the bug where hitting Enter during playing wouldn't take + the user back to the editor. [Wolfman2000] +* [Gameplay] Fix Fail mods being dishonored. [Midiman] + +2011/07/05 +---------- +* [ScreenEdit] Restore dance-couple and pump-couple for editing purposes. + Saving should still work, but this was never tested yet. [Wolfman2000] +* [ScreenOptions] Mini is now ITG Mini, and Tiny is now Pump Pro Mini. + This will prevent many prior courses from breaking. [sharksoda, Wolfman2000] +* [CharacterManager] Add a lua function to check how many characters you have. + For an example of how this is used, check the default theme's scripts + folder, specifically 03 ThemePrefs.lua. [Wolfman2000] + +2011/07/04 +---------- +* [ScreenEdit] Add a function to switch the notes the routine players have to + hit. In simple terms, Player 1's notes are now Player 2's and vice~versa. + Check it out in the Alter Menu. [Wolfman2000] +* [ScreenEdit] Add two routine mirroring functions. Now you can build sections + of a chart for one player, and mirror the effect for the other player when + finished. For Pump players, it is not a straight mirror, but is more akin + to what is found via normal routine charts. In other words, you'll be happy. + Check it out in the Alter Menu. [Wolfman2000] + +2011/07/03 +---------- +* [ScreenEdit] Fix a crash if one tries to remove an attack that doesn't + exist at that time. [Wolfman2000] + +================================================================================ +StepMania 5.0 Preview 2 | 20110703 +-------------------------------------------------------------------------------- + +2011/07/03 +---------- +* [Player] Bring mMods from OpenITG over. Also, a metric was added, + "MModHighCap", to cap the speed mod if required for playing songs like + Tsuhsuixamush. Set the metric to 0 or less to remove the cap. [AJ, sharksoda, + Wolfman2000] + +2011/07/02 +---------- +* [ScreenEdit] Fixed a crash when hitting Enter in the F1 help menu. [AJ] + +2011/06/30 +---------- +* [NotesAll] Use #FIRSTSECOND, #LASTSECOND, and #LASTSECONDHINT instead of the + former BEAT equivalents. Split Timing has made this a necessity thanks to + certain files that abuse Stops/Delays more than usual. [Wolfman2000] +* [ScreenEdit] Add a function in the Area Menu to designate the current beat + as the last second of the song. Please try to be smart and not use this too + early. [Wolfman2000] + +2011/06/28 +---------- +* [ScreenEdit] Add a function to copy/paste the TimingData of a player's + choice. Remember to be in the appropriate mode when copying and pasting. + By default, the song timing is already located in the clipboard, ready for + use. [Wolfman2000] + +2011/06/27 +---------- +* [Steps] Make sure #ATTACKS are copied when requested. [Wolfman2000] +* [ScreenEdit] Have Step Author up front instead of Chart Style. This is + probably going to be better overall. [Wolfman2000] +* [TimingData] Preserve the length of time for Speed Segment scaling when using + beats. [Wolfman2000] +* [NotesLoader/WriterSSC] #OFFSET is to be before #ATTACKS. This is required if + we pursue beat based attacks and not just second based. [Wolfman2000] + +2011/06/26 +---------- +* [UnlockManager] New metric: AutoLockEditSteps. Use this to hide bonus charts + until the Expert steps are beaten. No guarantee that this works with no + challenge steps in the song. This defaults to false. [Wolfman2000] +* [UnlockManager] New metric: SongsNotAdditional. Set to true to keep the + default behavior, false to have the AdditionalSongs folder contain + unlockable material. This is set to true to start. [Wolfman2000] +* [ScreenEdit] Allow jumping between all segments, not just Label segments. + You still use Ctrl + ,/. to jump, but now you use Ctrl + N/M to cycle the + segments. By default, it starts with Label. [Wolfman2000] +* [PlayerOptions] No longer display StepAttacks in the player's list. + Instead, show NoAttacks if attacks are disabled. [Wolfman2000] + +2011/06/24 +---------- +* [Actor] Implement compound(length,tweens) in _fallback/02 Actor.lua. [AJ] +* [UnlockManager] Add a new unlock reward: StepsType. This is similar to + unlocking Steps, but it is targeted for one step in one stepstype rather + than one step in all stepstypes. This needs testing. [Wolfman2000] +* [ScreenEdit] Add the option to convert delays to beats. Just find a better + song to use this on besides Uprock. [Wolfman2000] +* [ScreenEdit] Fix a crash if you don't save any steps on a new song. + [Wolfman2000] +* [NotesLoader/WriterSSC] Add support for Step #ATTACKS. Furthermore, Song + Attacks (or rather, Step Attacks as it should be called now) are turned on + by default instead of off. [Wolfman2000] + +2011/06/19 +---------- +* [EditMenu] Allow all songs to work in Practice Mode, regardless of folder + location. This fixes a crash if everyone had songs in AdditionalSongs. + [Wolfman2000] + +2011/06/17 +---------- +* [LifeMeterBattery] Fixed a bug where MinesSubtractLives was not being honored. + Also added LifeChanged message to changing of life on holds. [AJ] + +2011/06/15 +---------- +* [TimingData] Added many lua bindings for the other timing segments. GetWarps, + GetCombos, GetTimeSignatures, GetTickcounts, GetFakes, GetScrolls, GetSpeeds. + This should cover all of them now. [Wolfman2000] + +2011/06/13 +---------- +* [InputHandler_DirectInput] Fixed MouseWheel input not resetting. [AJ] +* [ScreenTextEntry] Make it so only the keyboard's Enter key can finish the + screen. Should fix issues with buttons whose secondary function is MenuStart. [AJ] +* [InputMapper] Modify default mappings. Use the Hyphen key instead of the + Numlock key for Player 2's GAME_BUTTON_BACK. This should address some + issues with Player 2 being unable to back out if they use a laptop. + [Wolfman2000] +* [NoteDisplay] Add two new metrics. + * DrawRollHeadForTapsOnSameRow: bool, similar to DrawHoldHeadForTapsOnSameRow + * TapHoldRollOnRowMeansHold: bool, true means hold and false means roll + * No noteskins should require updating, as these were placed in common/common + for ease of use. [Wolfman2000] +* [LifeMeterBattery] Added ChangeLives(int) Lua binding. [AJ] +* [LifeMeterBattery] Added DangerThreshold metric. [AJ] +* [LifeMeterBattery] Added some important metrics. [AJ] + * MinScoreToKeepLife='TapNoteScore_*' - any score below this = loss of life. + * SubtractLives=1 - how many lives are lost when going below MinScoreToKeepLife. + * MinesSubtractLives=1 - how many lives are lost when hitting a mine. + * HeldAddLives=0 - how many lives are gained when a hold is completed. + * LetGoSubtractLives=1 - how many lives are lost on a dropped hold. + +2011/06/12 +---------- +* [ScreenNetSelectMusic] Add PlayerOptionsScreen metric. [AJ] +* [ScreenEdit] Restore the old PageUp/PageDown behavior, added Control + + PageUp/PageDown to use recent time signature behavior. Laptop users, that + includes you guys too: semicolon and apostrophe are still good. [Wolfman2000] + +2011/06/11 +---------- +* [ScreenEdit] Allow setting the Music Preview via the Alter Menu. Just select + your area, enter the menu, and choose "Designate as Music Preview". No more + math calculations needed! [Wolfman2000] +* [SongUtil] Added GetPlayableSteps(Song) Lua binding. [AJ] +* [Steps] Allow 255 characters for all chart descriptions, including edits. + We are no longer bound by In The Groove I think. [Wolfman2000] +* [Player] Add GetPlayerTimingData() Lua binding. [Wolfman2000] + +2011/06/10 +---------- +* [ScreenEdit] Split the Area Menu into the Area Menu and Alter Menu. Use the + "A" key to enter the Alter Menu when a selection of notes/rows are + highlighted. Use the Enter key to enter the old Area Menu for the options that + do not depend on selecting NoteData. [Wolfman2000] +* [ScreenEdit] Allow converting selections to Delays, Warps, or Fakes as well + as Stops. Remember, use the Alter Menu for this. [Wolfman2000] + +2011/06/09 +---------- +* [ScreenSyncOverlay] Ensure that F11 / F12 work with all charts due to Split + Timing. [Wolfman2000] + +2011/06/08 +---------- +* Any notes in a fake segment or warp segment are completely ignored for + scoring purposes. Now you can get 100% on your warping goodness! + [Wolfman2000] + +2011/06/06 +---------- +* [PlayerOptions] Removed the ScoreDisplay mod choices. Use lua to make your + own scoring formulas that work in reverse instead. [Wolfman2000] +* [ScreenGameplay] Fix an assist tick bug if there was no Player 1. Note that + this changes the behavior slightly: it is the first enabled player, or + master player, that gets the ticks now. A better solution will be looked at + in the future. [Wolfman2000] +* [NoteDataUtil] Fix a radar issue involving hands. Unfortunately, this means + yet another cache reload for accuracy purposes. [Wolfman2000] + 2011/06/04 ---------- * Changed default MusicWheelSwitchSpeed to 15 (was 10). [AJ] diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index 201f0b6312..bbb1e57e54 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -3,6 +3,7 @@ + @@ -39,11 +40,8 @@ - - - @@ -57,6 +55,7 @@ + @@ -130,7 +129,6 @@ - @@ -143,6 +141,8 @@ + + @@ -153,6 +153,7 @@ + @@ -322,6 +323,7 @@ + @@ -578,6 +580,7 @@ + @@ -823,6 +826,7 @@ + @@ -889,6 +893,7 @@ + @@ -929,6 +934,7 @@ + @@ -956,6 +962,7 @@ + @@ -1026,6 +1033,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1093,6 +1146,15 @@ + + + + + + + + + @@ -1185,9 +1247,11 @@ + + @@ -1318,6 +1382,7 @@ + @@ -1327,6 +1392,7 @@ + @@ -1377,10 +1443,17 @@ + + + + + + + @@ -1408,6 +1481,7 @@ + @@ -1421,6 +1495,7 @@ + @@ -1470,6 +1545,7 @@ + @@ -2024,8 +2100,9 @@ - - + + + @@ -2060,6 +2137,6 @@ - StepMania 5 v5.0 Preview 1a - 2011-06-04 + StepMania 5 v5.0 Preview 2 + 2011-07-04 diff --git a/Docs/Luadoc/Lua.xsl b/Docs/Luadoc/Lua.xsl index 2861185f63..72271aec39 100644 --- a/Docs/Luadoc/Lua.xsl +++ b/Docs/Luadoc/Lua.xsl @@ -395,7 +395,13 @@ $type='bool' or $type='table' or $type='color' or - $type='Enum'"> + $type='Enum' or + $type='ThreadVariable' or + $type='LuaOptionRow' or + $type='ActorDef' or + $type='chunk' or + $type='unsigned' or + $type='various'"> diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index b0bd9a2393..7de1cc82a3 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -23,6 +23,9 @@ + + [03 HSV.lua] Returns a color with the specified alpha. + [02 StageMods.lua] @@ -36,10 +39,10 @@ Returns the base name of file path. - [02 Colors.lua] + [02 Colors.lua] Boosts the specified color by multiplying its values by fBoost. - [03 HSV.lua] + [03 HSV.lua] Modifies the brightness of the specified color. [03 ProductivityHelpers.lua] Returns true if Center 1P is being used. @@ -48,7 +51,8 @@ [03 Gameplay.lua] - CLAMP is an all-female Japanese mangaka group that formed in the mid 1980s. Erm, I mean... Clamps fValue between fLow and fHigh. + CLAMP is an all-female Japanese mangaka group that formed in the mid 1980s. + Erm, I mean... Clamps fValue between fLow and fHigh. Closes any connection to an online server. @@ -59,6 +63,21 @@ Returns a color from a string. color can be in hex ("#FFFFFFFF") or 0..1 values ("1.0,1.0,1.0,1.0"), in RGBA order. + + [02 Colors.lua] Returns a darker tone of the color. (Specifically c[1]/2, c[2]/2, c[3]/2, c[4]) + + + [02 Colors.lua] Returns a lighter tone of the color. (Specifically c[1]+(c[1]/2), c[2]+(c[2]/2), c[3]+(c[3]/2), c[4]) + + + [02 Colors.lua] Returns a midtone of the color. (Specifically c[1]/1.5, c[2]/1.5, c[3]/1.5, c[4]) + + + [03 HSV.lua] Returns a hex representation for the specified color. + + + [03 HSV.lua] Takes in a color and returns a table with the HSV values. + [03 Gameplay.lua] Determines what TapNoteScore allows for continuing the combo. @@ -68,6 +87,12 @@ [03 Gameplay.lua] Determines if combo should be per row (Jump = 1) or per column (Jump = 2). + + [02 Other.lua] The combo trasform command. + + + [03 Gameplay.lua] Returns the UserPrefComboUnderField user preference value. + Tries to connect to the server at sAddress. @@ -77,14 +102,23 @@ Returns the current day of the year. + + [02 Serialize] Recursively deep-copy a table. + [01 base.lua] "Override Lua's dofile to use our loadfile." + + [02 Utilities.lua] + + + [02 Utilities.lua] Return the index of a true value in list. + [02 Utilities.lua] Find a key in tab with the given value. - - [02 Utilities.lua] Return the index of a true value in list. + + func takes a key and a value. Returns the number passed to the function followed by its suffix ("th", "nd", and so on). @@ -98,6 +132,12 @@ Returns the corresponding CustomDifficulty string for a StepsType/Difficulty (/optional CourseType) combination. + + [04 Scoring.lua] "Get the radar values directly. The individual steps aren't used much." + + + [02 Other.lua] Returns a string with the Edit Mode SubScreens. + [03 EnvUtils2.lua] Returns the value of name from the Env table. @@ -113,21 +153,45 @@ Returns a string representing the name of the operating system being used. (e.g. "Windows", "Linux", "Mac, "Unknown") + + [03 ProductivityHelpers.lua] "This returns a profile, preferably a player one. If there isn't one, [it falls] back on the machine profile." + [03 ThemePrefs.lua] Returns true if player pn is using ProTiming. [02 Utilities.lua] Returns a path to a random song background. + + [03 ProductivityHelpers.lua] + + + [03 ProductivityHelpers.lua] + + + Returns the display aspect ratio. + Returns the name of the currently connected server. [02 Utilities.lua] Returns a path to the current songs background. + + [03 Gameplay.lua] + Returns the theme's aspect ratio. + + [03 ThemePrefs.lua] (Alias for .) + + + Returns the current Timing difficulty. + + + [04 Scoring.lua] "Retrieve the amount of taps/holds/rolls involved." Used in some scoring formulas. + [03 UserPreferences2.lua] Themer-facing function for getting a user preference. @@ -140,9 +204,38 @@ [03 UserPreferences2.lua] Themer-facing function for getting a user preference as a number. + + [03 HSV.lua] Returns the color's alpha if it has any, otherwise returns 1. + + + [03 Gameplay.lua] Returns the value to start showing the combo at. + + + [03 Gameplay.lua] Returns true if you need to step on hold heads to activate them. + + + [03 Gameplay.lua] Returns 0 in pump mode, TimingWindowSecondsHold preference value in any other game mode. + Returns the current hour. + + [03 HSV.lua] Converts a color from HSV values to something StepMania can understand. + hue is from 0-360, saturation and value are 0..1 + + + [03 HSV.lua] Converts a color from HSV values with alpha to something StepMania can understand. + hue is from 0-360, saturation, value, and alpha are 0..1 + + + [03 HSV.lua] "Converts a set of HSV values to a color." + + + [03 HSV.lua] "Takes in a normal color and returns the hex representation. (Adapted from code in LuaBit)" + + + [03 HSV.lua] Changes the hue of the input color. + [03 ThemePrefs.lua] Initializes various user preferences. @@ -206,6 +299,12 @@ Returns the current Minute. + + [03 Gameplay.lua] Returns the value to start showing the miss combo at. + + + Creates a module. See the Lua manual for more details. + Returns the current month of the year. @@ -215,6 +314,20 @@ Returns Month m as a string. + + "Allows a program to traverse all fields of a table. Its first argument is a + table and its second argument is an index in this table. + next returns the next index of the table and its associated value." + See the Lua manual for more details. + + + [03 ThemePrefs.lua] Returns a Lua option row for ProTiming. + + + "Returns three values: the function, the table t, and nil, + so that the construction for k,v in pairs(t) do body end + will iterate over all key–value pairs of table t." + [03 ProductivityHelpers.lua] Converts a PlayerNumber into a short string (e.g. "P1", "P2"). @@ -233,6 +346,16 @@ Returns the product version. + + "Checks whether v1 is equal to v2, without invoking any metamethod." + + + "Gets the real value of t[index], without invoking any metamethod." + + + "Sets the real value of t[index] to value, without invoking any metamethod." + The modified t is then returned. + [02 ActorDef.lua] @@ -242,12 +365,27 @@ [03 UserPreferences2.lua] (internal) Reads the specified user preference from its config file. + + Sends the current style to the server. + + + Loads the specified module. See the Lua manual for more information. + [02 Utilities.lua] Round a number. + + [03 HSV.lua] Modifies the saturation of the specified color + [03 Gameplay.lua] Returns the primary ScoreKeeper class to use. + + [00 alias.lua, 02 Other.lua] alias for . + + + [00 alias.lua, 02 Other.lua] alias for . + Returns the current second. @@ -269,12 +407,20 @@ Converts fSecs to Minutes:Seconds.Milliseconds format using two digits for each section except Milliseconds (uses 3). + + "If index is a number, returns all arguments after argument + number index. Otherwise, index must be the string + "#", and [it] returns the total number of extra arguments it received." + [02 Branches.lua] Determines the correct music/course selection screen to use and returns it. [03 Gameplay.lua] (soon to be deprecated) Returns a list of codes to use on ScreenSelectProfile. + + [02 Serialize.lua] Serialize the table t. + [03 EnvUtils2.lua] Sets the value of name to value in the Env table. @@ -299,6 +445,12 @@ [02 ActorDef.lua] + + [02 Utilities.lua] Returns a shuffled version of t. + + + [02 Utilities.lua] Returns a slice of the specified table of size num. + [02 Utilities.lua] Look up each value in a table, returning a table with the resulting strings. @@ -308,42 +460,64 @@ [03 ProductivityHelpers.lua] Converts a string or number to a bool. + + Tries to convert e to a number. Returns nil if + it can't convert the input to a number. (base is optional.) + + + Converts e to a string. + [02 Enum.lua] Returns a string representing an enum starting from '_'. For example, passing PlayerNumber_P1 to this function will return P1. [00 init.lua] Alias for . + + Returns the type of the object as a string. See the Lua manual for valid return values. + + + "Returns the elements from the given table. + This function is equivalent to return list[i], list[i+1], ···, list[j]" + (i and j are optional; "by default, i is 1 and j is the length of the list.") + Returns a string with characters escaped for URLs. (e.g. a space becomes '%20') [01 base.lua] Alias for lua.GetThreadVariable. + + Returns the current version's build date. + + + Returns the current version's build time. + [00 init.lua] Alias for . [04 WidescreenHelpers.lua] Depending on the screen width, scales between ar43 (4:3; 640px) and ar169 (16:9; 854px). + + [02 Utilities.lua] + [02 ActorDef.lua] Wraps the children in an ActorFrame. [04 FileUtils.lua] Writes buf to the file at path. + + [03 GamePreferences.lua] + [03 UserPreferences2.lua] (internal) Writes user preference prefName to its config file with value being tostring'd. Returns the current year. - - - - [03 ThemePrefs.lua] Returns a Lua option row for ProTiming. - [03 ThemePrefs.lua] Returns a Lua option row for toggling AutoSetStyle. @@ -367,9 +541,16 @@ + + Returns the for the file at sPath. + Returns true if sClassName is a registered Class. + + Loads all commands and sets X and Y for the specified Actor. + + @@ -414,6 +595,20 @@ + + Returns true if the type of v is sType. + + + Flushes log files to disk. + + + + Tries to read the file at sPath. If successful, it returns the file's contents. + If unsuccessful, it returns two values: nil and "error". + + + Calls func(...) with two LuaThreadVariables set, and returns the return values of func(). + Writes sString to log.txt. Aliased by . @@ -422,9 +617,6 @@ Writes sString to info.txt and log.txt as a warning. Aliased by . - - Flushes log files to disk. - @@ -437,6 +629,9 @@ + + Gets the playable Steps for the present Song based on the present Game. + Returns true if the song's steps (st) are playable. @@ -560,7 +755,21 @@ [02 Actor.lua] - [02 Actor.lua] Centers an Actor. + [02 Actor.lua] Centers an Actor on the screen. (equivalent to x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y) + + + [03 ProductivityHelpers.lua] Centers an Actor on the X axis. (equivalent to x,SCREEN_CENTER_X) + + + [03 ProductivityHelpers.lua] Centers an Actor on the y axis. (equivalent to y,SCREEN_CENTER_Y) + + + Determines if the z-buffer should be cleared or not. + + + [02 Actor.lua] Combines multiple interpolators for complex tweens. tweens + can either be a string like "linear,0.25,accelerate,0.75" or + a table with tween information { {Type="linear", Percent=0.25, Bezier=nil}, {Type="accelerate", Percent=0.75, Bezier=nil} } Crops percent of the Actor from the bottom, where percent is in the range 0..1. @@ -853,6 +1062,9 @@ Stops any effect the Actor has. + + Stops any tweening. + Stretches the Actor to a rectangle of a specific size. @@ -877,6 +1089,12 @@ Set the z position of the Actor to zPos. + + Sets the z bias to fBias. + + + Enables/disables z-buffer depending on bUse. + Zooms the Actor to zoom scale. @@ -898,19 +1116,19 @@ Zooms the Actor to zoom scale on the Z axis. + + Sets the z testing mode to write on pass if true, turns it off if false + + + Sets the z testing mode to testMode. + + + Sets z writing to true or false based on bWrite. + [02 Actor.lua] - - [02 Actor.lua] Centers an Actor on the screen. (equivalent to x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y) - - - [03 ProductivityHelpers.lua] Centers an Actor on the X axis. (equivalent to x,SCREEN_CENTER_X) - - - [03 ProductivityHelpers.lua] Centers an Actor on the y axis. (equivalent to y,SCREEN_CENTER_Y) - [02 Actor.lua] Stretches an Actor to cover the screen. (equivalent to stretchto,0,0,SCREEN_WIDTH,SCREEN_HEIGHT) @@ -1163,7 +1381,7 @@ Loads the card image from the specified Character. - + Loads the banner from the cache based on sPath (typically or ). Loads a Banner from a specified Course. @@ -1322,6 +1540,9 @@ Returns a random character. + + Returns the number of characters available. + @@ -1452,6 +1673,9 @@ Returns the MD5 hash for s. + + Returns the SHA-1 hash for the file at sPath. + Returns the SHA-1 hash for s. @@ -2004,6 +2228,9 @@ + + Changes the player's life by iNumLives. (Negative values subtract lives.) + Returns the number of lives remaining. @@ -2347,6 +2574,9 @@ + This function is deprecated. Please use GetStepAttacks() instead. + + @@ -2701,7 +2931,9 @@ - + + Returns the Profile for the specified profile ID. + @@ -2723,6 +2955,9 @@ Returns true if Song s has never been played before (according to the machine profile). + + Returns true if pn's Profile was loaded from a memory card. + Returns true if the last load of player pn's profile was a LastGood copy of the profile. @@ -2858,12 +3093,21 @@ Returns the name of the previous Screen. + + Returns the ScreenType for this Screen. + Locks input for f seconds. + + [02 Other.lua] Gets a metric from the current Screen. + Posts a message with the text sScreenMsg to the Screen. + + [02 Other.lua] Gets a string from the current Screen in the current language. + @@ -3078,6 +3322,9 @@ Returns the first beat of the song. + + Returns the first second of the song. + Returns the genre of the song. @@ -3087,6 +3334,9 @@ Returns the last beat of the song. + + Returns the last second of the song. + Gets the path to the lyrics. @@ -3328,6 +3578,9 @@ Load the song banner texture at sPath. + + [02 Sprite.lua] Loads the background from the current Song or the first Trail entry. + [02 Sprite.lua] Load the texture for song's background. @@ -3340,6 +3593,9 @@ Set the to mode. + + Sets the number of seconds into the animation to fSeconds. + Set the texture to texture. @@ -3445,6 +3701,9 @@ Returns the author that made that particular Steps pattern. + + Returns the Steps chart name. + Returns the Chart Style for this Steps. @@ -3463,8 +3722,11 @@ Returns the numerical difficulty of the Steps. + + Returns true if the Steps has any attacks. + - returns true if the song has significant timing changes. + Returns true if the Steps pattern has significant timing changes. Returns the complete list of RadarValues for player pn. Use to grab a specific value. @@ -3608,6 +3870,27 @@ Returns a table of the Labels and the times they happen as strings with the format "beat=label name." + + Returns a table of the Warps and the times they happen as strings with the format "beat=number of beats warped over." + + + Returns a table of the Combos and the times they happen as strings with the format "beat=combo value." + + + Returns a table of the Time Signatures and the times they happen as strings with the format "beat=beats per measure (numerator)=denominator." + + + Returns a table of the Tickcountss and the times they happen as strings with the format "beat=number of ticks per beat." + + + Returns a table of the Fakes and the times they happen as strings with the format "beat=number of beats to not judge." + + + Returns a table of the Scrolls and the times they happen as strings with the format "beat=scroll rate ratio." + + + Returns a table of the Speeds and the times they happen as strings with the format "beat=scroll rate ratio=length of time to fully activate=unit of activation (0 for beats, 1 for seconds)." + Returns true if the TimingData contains BPM changes. @@ -3690,6 +3973,9 @@ Returns true if the UnlockEntry requires you to pass Hard steps. + + Returns true if the UnlockEntry requires you to pass Challenge steps. + Returns the Song related to the UnlockEntry. @@ -3720,6 +4006,9 @@ Sets the UnlockEntry to unlock a specified song's steps.
Example: steps,"In The Groove/Pandemonium","expert"
+ + Sets the UnlockEntry to unlock a specified song's stepstype. +
@@ -3755,7 +4044,9 @@ Returns the UnlockEntry index to celebrate. - + + Sets the preferred Song/Course to the specified sUnlockEntryID + Unlocks an entry by ID. diff --git a/Docs/SimfileFormats/ssc_msd5.txt b/Docs/SimfileFormats/ssc_msd5.txt index 845844fbc6..b8e5a2aea3 100644 --- a/Docs/SimfileFormats/ssc_msd5.txt +++ b/Docs/SimfileFormats/ssc_msd5.txt @@ -21,19 +21,19 @@ #DELAYS:; #LABELS:; #TIMESIGNATURES:; -#LASTBEATHINT:; #SAMPLESTART:; #SAMPLELENGTH:; #DISPLAYBPM:[xxx][xxx:xxx]|[*]; #SELECTABLE:; +#LASTSECONDHINT:; #BGCHANGES:; #FGCHANGES:; #KEYSOUNDS:; #ATTACKS:; // stored in cache -#FIRSTBEAT:; // calculated -#LASTBEAT:; // calculated +#FIRSTSECOND:; // calculated +#LASTSECOND:; // calculated #SONGFILENAME:; #MUSICBYTES:; // ignored by loader #HASMUSIC:; @@ -42,6 +42,7 @@ // begin #NOTEDATA# // marks a new note data section // information from #NOTES moved here +#CHARTNAME:; #STEPSTYPE:; #DESCRIPTION:; #CHARTSTYLE:; @@ -51,6 +52,7 @@ #CREDIT:; // steps-based timingdata +#OFFSET:; #BPMS:; #STOPS:; #DELAYS:; @@ -61,8 +63,11 @@ #SCROLLS:; #FAKES:; #LABELS:; -#ATTACKS:; // Not yet in use. -#OFFSET:; +#ATTACKS:; +#DISPLAYBPM:; -// actual step data +// only in cache files +#STEPFILENAME:; + +// actual step data (not in cache files) #NOTES:; diff --git a/Installer/custom-sm5.bmp b/Installer/custom-sm5.bmp index 4d4a4490d8..17c427c6b4 100644 Binary files a/Installer/custom-sm5.bmp and b/Installer/custom-sm5.bmp differ diff --git a/Installer/header-sm5.bmp b/Installer/header-sm5.bmp index 8b5662310f..73a0be357f 100644 Binary files a/Installer/header-sm5.bmp and b/Installer/header-sm5.bmp differ diff --git a/Installer/install.ico b/Installer/install.ico index 6a5de183f0..60a8122e56 100644 Binary files a/Installer/install.ico and b/Installer/install.ico differ diff --git a/Installer/welcome-sm5.bmp b/Installer/welcome-sm5.bmp index e460d85781..08b7d503bf 100644 Binary files a/Installer/welcome-sm5.bmp and b/Installer/welcome-sm5.bmp differ diff --git a/NoteSkins/common/common/metrics.ini b/NoteSkins/common/common/metrics.ini index 619f75b3f6..6c9f3f4e31 100644 --- a/NoteSkins/common/common/metrics.ini +++ b/NoteSkins/common/common/metrics.ini @@ -1,5 +1,7 @@ [NoteDisplay] DrawHoldHeadForTapsOnSameRow=1 +DrawRollHeadForTapsOnSameRow=1 +TapHoldRollOnRowMeansHold=1 AnimationIsBeatBased=1 TapNoteAnimationLength=1 TapMineAnimationLength=1 diff --git a/NoteSkins/dance/midi-note/Down Tap Explosion Bright.png b/NoteSkins/dance/midi-note/Down Tap Explosion Bright.png index bd54411afb..251b65f913 100644 Binary files a/NoteSkins/dance/midi-note/Down Tap Explosion Bright.png and b/NoteSkins/dance/midi-note/Down Tap Explosion Bright.png differ diff --git a/NoteSkins/dance/midi-note/NoteSkin.lua b/NoteSkins/dance/midi-note/NoteSkin.lua index d821c2740b..0d596ec4ef 100644 --- a/NoteSkins/dance/midi-note/NoteSkin.lua +++ b/NoteSkins/dance/midi-note/NoteSkin.lua @@ -20,14 +20,14 @@ ret.Redir = function(sButton, sElement) if sElement == "Hold Head Active" or sElement == "Roll Head Active" then - sElement = "Hold Head Active"; + sElement = "Tap Note"; end -- Test if sElement == "Hold Head Inactive" or sElement == "Roll Head Inactive" then - sElement = "Hold Head Inactive"; + sElement = "Tap Note"; end if sElement == "Tap Fake" diff --git a/NoteSkins/dance/midi-note/metrics.ini b/NoteSkins/dance/midi-note/metrics.ini index 4969099512..d315c3ab14 100644 --- a/NoteSkins/dance/midi-note/metrics.ini +++ b/NoteSkins/dance/midi-note/metrics.ini @@ -3,7 +3,8 @@ FallbackNoteSkin=default [NoteDisplay] TapNoteAnimationIsVivid=0 -DrawHoldHeadForTapsOnSameRow=1 +HoldHeadAnimationIsVivid=0 +DrawHoldHeadForTapsOnSameRow=0 TapNoteAnimationLength=4 TapAdditionAnimationLength=4 TapMineAnimationLength=1 @@ -34,8 +35,14 @@ TapNoteNoteColorTextureCoordSpacingY=0.125 TapFakeNoteColorTextureCoordSpacingX=0 TapFakeNoteColorTextureCoordSpacingY=0.125 +HoldHeadAdditionTextureCoordOffsetX=0 +HoldHeadAdditionTextureCoordOffsetY=0 HoldHeadNoteColorTextureCoordSpacingX=0 HoldHeadNoteColorTextureCoordSpacingY=0 +HoldTopCapAdditionTextureCoordOffsetX=0 +HoldTopCapAdditionTextureCoordOffsetY=0 +HoldTopCapNoteColorTextureCoordSpacingX=0 +HoldTopCapNoteColorTextureCoordSpacingY=0 [GhostArrowDim] NoneCommand= @@ -62,8 +69,8 @@ LetGoCommand=blend,'BlendMode_Add'; HeldCommand=blend,'BlendMode_Add';diffuse,1.0,1.0,0.3,0.875;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0 [HoldGhostArrow] -HoldingOnCommand=visible,true -HoldingOffCommand=visible,false +HoldingOnCommand=blend,'BlendMode_Add';pulse;effectmagnitude,1,1.125,1;effectperiod,0.05;effectclock,'beatnooffset';visible,true +HoldingOffCommand=blend,'BlendMode_Add';stopeffect;visible,false [ReceptorArrow] W3Command=stoptweening;zoom,0.85;linear,0.12;zoom,1 diff --git a/NoteSkins/dance/midi-solo/metrics.ini b/NoteSkins/dance/midi-solo/metrics.ini index cc79f5539f..698d307fb4 100644 --- a/NoteSkins/dance/midi-solo/metrics.ini +++ b/NoteSkins/dance/midi-solo/metrics.ini @@ -1,9 +1,9 @@ [Global] -FallbackNoteSkin=default +FallbackNoteSkin=midi-note [NoteDisplay] TapNoteAnimationIsVivid=0 -DrawHoldHeadForTapsOnSameRow=1 +DrawHoldHeadForTapsOnSameRow=0 TapNoteAnimationLength=4 TapAdditionAnimationLength=4 TapMineAnimationLength=1 @@ -35,7 +35,7 @@ TapFakeNoteColorTextureCoordSpacingX=0 TapFakeNoteColorTextureCoordSpacingY=0.125 HoldHeadNoteColorTextureCoordSpacingX=0 -HoldHeadNoteColorTextureCoordSpacingY=0.125 +HoldHeadNoteColorTextureCoordSpacingY=0 [GhostArrowDim] NoneCommand= diff --git a/NoteSkins/dance/retro/Down Hold Explosion.redir b/NoteSkins/dance/retro/Down Hold Explosion.redir deleted file mode 100644 index 9bef57edb4..0000000000 --- a/NoteSkins/dance/retro/Down Hold Explosion.redir +++ /dev/null @@ -1 +0,0 @@ -Down Tap Explosion Bright \ No newline at end of file diff --git a/NoteSkins/kb7/retrobar-iidx/metrics.ini b/NoteSkins/kb7/retrobar-iidx/metrics.ini index 3e010e338c..9a306a981e 100644 --- a/NoteSkins/kb7/retrobar-iidx/metrics.ini +++ b/NoteSkins/kb7/retrobar-iidx/metrics.ini @@ -4,7 +4,12 @@ DrawHoldHeadForTapsOnSameRow=0 StartDrawingHoldBodyOffsetFromHead=0 StopDrawingHoldBodyOffsetFromTail=-32 +TapNoteAnimationIsVivid=0 + # control the vertical +TapNoteNoteColorTextureCoordSpacingX=0 +TapNoteNoteColorTextureCoordSpacingY=0 + TapNoteAdditionTextureCoordOffsetX=0 TapNoteAdditionTextureCoordOffsetY=0.5 diff --git a/NoteSkins/kb7/retrobar-o2jam/metrics.ini b/NoteSkins/kb7/retrobar-o2jam/metrics.ini index 3e010e338c..9a306a981e 100644 --- a/NoteSkins/kb7/retrobar-o2jam/metrics.ini +++ b/NoteSkins/kb7/retrobar-o2jam/metrics.ini @@ -4,7 +4,12 @@ DrawHoldHeadForTapsOnSameRow=0 StartDrawingHoldBodyOffsetFromHead=0 StopDrawingHoldBodyOffsetFromTail=-32 +TapNoteAnimationIsVivid=0 + # control the vertical +TapNoteNoteColorTextureCoordSpacingX=0 +TapNoteNoteColorTextureCoordSpacingY=0 + TapNoteAdditionTextureCoordOffsetX=0 TapNoteAdditionTextureCoordOffsetY=0.5 diff --git a/NoteSkins/kb7/retrobar-razor_o2/noteskin.ini b/NoteSkins/kb7/retrobar-razor_o2/metrics.ini similarity index 100% rename from NoteSkins/kb7/retrobar-razor_o2/noteskin.ini rename to NoteSkins/kb7/retrobar-razor_o2/metrics.ini diff --git a/NoteSkins/pump/default/UpLeft Explosion.lua b/NoteSkins/pump/default/UpLeft Explosion.lua index 9127b0764b..a6e9d779ee 100644 --- a/NoteSkins/pump/default/UpLeft Explosion.lua +++ b/NoteSkins/pump/default/UpLeft Explosion.lua @@ -15,10 +15,9 @@ return Def.ActorFrame { --tap NOTESKIN:LoadActor(Var "Button", "Ready Receptor")..{ Name="Tap"; - Frames = { { Frame = 2 } }; + --Frames = { { Frame = 2 ; Delay = 1 } }; TapCommand=cmd(finishtweening;diffusealpha,1;zoom,1;linear,0.2;diffusealpha,0;zoom,1.2); - - InitCommand=cmd(playcommand,"Tap"); + InitCommand=cmd(pause;setstate,2;playcommand,"Tap"); HeldCommand=cmd(playcommand,"Tap"); ColumnJudgmentMessageCommand=cmd(playcommand,"Tap"); --TapNoneCommand=cmd(playcommand,"Tap"); diff --git a/NoteSkins/pump/default/UpLeft Receptor.lua b/NoteSkins/pump/default/UpLeft Receptor.lua index cde7525919..86a2238fa1 100644 --- a/NoteSkins/pump/default/UpLeft Receptor.lua +++ b/NoteSkins/pump/default/UpLeft Receptor.lua @@ -1,12 +1,16 @@ local function Beat(self) + -- too many locals local this = self:GetChildren() + local player = GAMESTATE:GetMasterPlayerNumber() + local playerstate = GAMESTATE:GetPlayerState( player ) + local songposition = playerstate:GetSongPosition() -- GAMESTATE:GetSongPosition() - local beat = GAMESTATE:GetSongBeat() + local beat = songposition:GetSongBeat() -- GAMESTATE:GetSongBeat() local part = beat%1 part = clamp(part,0,0.5) local eff = scale(part,0,0.5,1,0) - if (GAMESTATE:GetSongPosition():GetDelay() or false) and part == 0 then eff = 0 end + if (songposition:GetDelay() or false) and part == 0 then eff = 0 end if beat < 0 then eff = 0 end diff --git a/NoteSkins/pump/pad/Center Hold Body Active 6x1.png b/NoteSkins/pump/pad/Center Hold Body Active 6x1.png new file mode 100644 index 0000000000..ddac269215 Binary files /dev/null and b/NoteSkins/pump/pad/Center Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/pad/Center Hold BottomCap Active 6x1.png b/NoteSkins/pump/pad/Center Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..cf2637fa80 Binary files /dev/null and b/NoteSkins/pump/pad/Center Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/pad/Center Outline Receptor.png b/NoteSkins/pump/pad/Center Outline Receptor.png new file mode 100644 index 0000000000..bfca6a1c11 Binary files /dev/null and b/NoteSkins/pump/pad/Center Outline Receptor.png differ diff --git a/NoteSkins/pump/pad/Center Ready Receptor 1x3.png b/NoteSkins/pump/pad/Center Ready Receptor 1x3.png new file mode 100644 index 0000000000..0adc5259af Binary files /dev/null and b/NoteSkins/pump/pad/Center Ready Receptor 1x3.png differ diff --git a/NoteSkins/pump/pad/Center Roll Head Active 3x2.png b/NoteSkins/pump/pad/Center Roll Head Active 3x2.png new file mode 100644 index 0000000000..5979f36db4 Binary files /dev/null and b/NoteSkins/pump/pad/Center Roll Head Active 3x2.png differ diff --git a/NoteSkins/pump/pad/Center Tap Note 3x2.png b/NoteSkins/pump/pad/Center Tap Note 3x2.png new file mode 100644 index 0000000000..40bb96963e Binary files /dev/null and b/NoteSkins/pump/pad/Center Tap Note 3x2.png differ diff --git a/NoteSkins/pump/pad/DownLeft Hold Body Active 6x1.png b/NoteSkins/pump/pad/DownLeft Hold Body Active 6x1.png new file mode 100644 index 0000000000..79408710df Binary files /dev/null and b/NoteSkins/pump/pad/DownLeft Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/pad/DownLeft Hold BottomCap Active 6x1.png b/NoteSkins/pump/pad/DownLeft Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..d28860440a Binary files /dev/null and b/NoteSkins/pump/pad/DownLeft Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/pad/DownLeft Ready Receptor 1x3.png b/NoteSkins/pump/pad/DownLeft Ready Receptor 1x3.png new file mode 100644 index 0000000000..3fd92f6f23 Binary files /dev/null and b/NoteSkins/pump/pad/DownLeft Ready Receptor 1x3.png differ diff --git a/NoteSkins/pump/pad/DownLeft Roll Head Active 3x2.png b/NoteSkins/pump/pad/DownLeft Roll Head Active 3x2.png new file mode 100644 index 0000000000..56bc2b2411 Binary files /dev/null and b/NoteSkins/pump/pad/DownLeft Roll Head Active 3x2.png differ diff --git a/NoteSkins/pump/pad/DownLeft Tap Note 3x2.png b/NoteSkins/pump/pad/DownLeft Tap Note 3x2.png new file mode 100644 index 0000000000..73d1ae0082 Binary files /dev/null and b/NoteSkins/pump/pad/DownLeft Tap Note 3x2.png differ diff --git a/NoteSkins/pump/pad/DownRight Hold Body Active 6x1.png b/NoteSkins/pump/pad/DownRight Hold Body Active 6x1.png new file mode 100644 index 0000000000..59300a1e1d Binary files /dev/null and b/NoteSkins/pump/pad/DownRight Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/pad/DownRight Hold BottomCap Active 6x1.png b/NoteSkins/pump/pad/DownRight Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..34c6762d44 Binary files /dev/null and b/NoteSkins/pump/pad/DownRight Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/pad/DownRight Roll Head Active 3x2.png b/NoteSkins/pump/pad/DownRight Roll Head Active 3x2.png new file mode 100644 index 0000000000..23e3979aed Binary files /dev/null and b/NoteSkins/pump/pad/DownRight Roll Head Active 3x2.png differ diff --git a/NoteSkins/pump/pad/UpLeft Hold Body Active 6x1.png b/NoteSkins/pump/pad/UpLeft Hold Body Active 6x1.png new file mode 100644 index 0000000000..217d9cfc26 Binary files /dev/null and b/NoteSkins/pump/pad/UpLeft Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/pad/UpLeft Hold BottomCap Active 6x1.png b/NoteSkins/pump/pad/UpLeft Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..796e029122 Binary files /dev/null and b/NoteSkins/pump/pad/UpLeft Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/pad/UpLeft Ready Receptor 1x3.png b/NoteSkins/pump/pad/UpLeft Ready Receptor 1x3.png new file mode 100644 index 0000000000..c50fcbca7c Binary files /dev/null and b/NoteSkins/pump/pad/UpLeft Ready Receptor 1x3.png differ diff --git a/NoteSkins/pump/pad/UpLeft Roll Head Active 3x2.png b/NoteSkins/pump/pad/UpLeft Roll Head Active 3x2.png new file mode 100644 index 0000000000..1740406c46 Binary files /dev/null and b/NoteSkins/pump/pad/UpLeft Roll Head Active 3x2.png differ diff --git a/NoteSkins/pump/pad/UpLeft Tap Note 3x2.png b/NoteSkins/pump/pad/UpLeft Tap Note 3x2.png new file mode 100644 index 0000000000..bbe39eeceb Binary files /dev/null and b/NoteSkins/pump/pad/UpLeft Tap Note 3x2.png differ diff --git a/NoteSkins/pump/pad/UpRight Hold Body Active 6x1.png b/NoteSkins/pump/pad/UpRight Hold Body Active 6x1.png new file mode 100644 index 0000000000..57ad1b1cd6 Binary files /dev/null and b/NoteSkins/pump/pad/UpRight Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/pad/UpRight Hold BottomCap Active 6x1.png b/NoteSkins/pump/pad/UpRight Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..c45d1d4149 Binary files /dev/null and b/NoteSkins/pump/pad/UpRight Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/pad/UpRight Roll Head Active 3x2.png b/NoteSkins/pump/pad/UpRight Roll Head Active 3x2.png new file mode 100644 index 0000000000..fe3c63d2b5 Binary files /dev/null and b/NoteSkins/pump/pad/UpRight Roll Head Active 3x2.png differ diff --git a/Songs/StepMania 5/MechaTribe Assault/Mecha-Tribe Assault.ogg b/Songs/StepMania 5/MechaTribe Assault/Mecha-Tribe Assault.ogg new file mode 100644 index 0000000000..24464c899f Binary files /dev/null and b/Songs/StepMania 5/MechaTribe Assault/Mecha-Tribe Assault.ogg differ diff --git a/Songs/StepMania 5/MechaTribe Assault/Mecha-Tribe Assault.ssc b/Songs/StepMania 5/MechaTribe Assault/Mecha-Tribe Assault.ssc new file mode 100644 index 0000000000..48cc7a4d43 --- /dev/null +++ b/Songs/StepMania 5/MechaTribe Assault/Mecha-Tribe Assault.ssc @@ -0,0 +1,8527 @@ +#VERSION:0.77; +#TITLE:Mecha-Tribe Assault; +#SUBTITLE:; +#ARTIST:Kommisar; +#TITLETRANSLIT:; +#SUBTITLETRANSLIT:; +#ARTISTTRANSLIT:; +#GENRE:; +#ORIGIN:; +#CREDIT:Graphics - Noon; +#BANNER:mechatribeassaultbn.png; +#BACKGROUND:mechatribeassaultbg.png; +#LYRICSPATH:; +#CDTITLE:wyde cd-tital.png; +#MUSIC:Mecha-Tribe Assault.ogg; +#OFFSET:-0.028000; +#SAMPLESTART:48.018002; +#SAMPLELENGTH:16.040001; +#SELECTABLE:YES; +#BPMS:0.000000=180.000000; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4; +#TICKCOUNTS:0.000000=4; +#COMBOS:0.000000=1; +#SPEEDS:0.000000=1.000000=0.000000=0; +#SCROLLS:0.000000=1.000000; +#LABELS:0.000000=Song Start, +16.000000=Verse 1A, +32.000000=Verse 1B, +48.000000=Verse 2A, +64.000000=Verse 2B, +80.000000=Verse 3A, +96.000000=Verse 3B, +112.000000=Verse 4A, +128.000000=Verse 4B, +144.000000=Verse 5A, +160.000000=Verse 5B, +176.000000=Verse 6A, +192.000000=Verse 6B, +208.000000=Verse 7A, +224.000000=Verse 7B, +240.000000=Verse 8A, +256.000000=Verse 8B, +272.000000=Verse 9A, +288.000000=Verse 9B, +304.000000=Fin; +#BGCHANGES:; +#KEYSOUNDS:; +#ATTACKS:; + +//---------------dance-single - ---------------- +#NOTEDATA:; +#CHARTNAME:Wyde; +#STEPSTYPE:dance-single; +#DESCRIPTION:; +#CHARTSTYLE:; +#DIFFICULTY:Challenge; +#METER:11; +#RADARVALUES:0.954,1.000,0.629,0.600,0.500,572.000,66.000,63.000,128.000,0.000,0.000,0.000,0.000,0.954,1.000,0.629,0.600,0.500,572.000,66.000,63.000,128.000,0.000,0.000,0.000,0.000; +#CREDIT:Wyde; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +1000 +1100 +000M +1010 +000M +0110 +M000 +1001 +, +00M0 +1001 +0M00 +0011 +M000 +0101 +0100 +0001 +, +1000 +1010 +0M00 +0101 +00M0 +1001 +0M00 +0110 +, +M000 +0110 +000M +1001 +00M0 +1100 +1000 +0100 +, +0010 +0011 +M000 +0101 +00M0 +1001 +0M00 +1010 +, +000M +1010 +000M +1100 +00M0 +0110 +0010 +0100 +, +1000 +1001 +00M0 +0101 +M000 +1010 +000M +1100 +, +00M0 +1100 +000M +0011 +0M00 +1001 +0001 +0010 +, +0100 +1000 +0001 +0100 +0001 +1000 +0100 +0010 +, +0001 +0000 +0010 +0000 +0100 +0000 +1000 +0000 +0001 +0000 +0100 +0000 +0001 +1000 +0100 +0010 +, +0001 +1000 +0001 +0010 +0100 +1000 +0001 +0100 +, +0010 +0000 +0100 +0000 +0001 +0000 +1000 +0000 +0100 +0000 +0010 +0000 +0001 +1000 +0010 +0100 +, +0001 +1000 +0100 +0010 +0001 +1000 +0001 +0010 +, +0100 +0000 +0010 +0000 +0001 +0000 +0100 +0000 +0001 +0000 +1000 +0000 +0100 +1000 +0001 +0010 +, +0100 +0010 +0100 +1000 +0001 +0100 +0010 +1000 +, +210M +0000 +0000 +3020 +000M +0030 +M102 +0000 +0000 +M023 +0000 +0030 +010M +1000 +0100 +0010 +, +0001 +0001 +0100 +0010 +1000 +0100 +0010 +0001 +, +0100 +0000 +0100 +0000 +0001 +0000 +1000 +0000 +0100 +0000 +0010 +0000 +0001 +1000 +0001 +0100 +, +0010 +0000 +1000 +0000 +1000 +0000 +0001 +0100 +0000 +0001 +0000 +1000 +0100 +0000 +0010 +0000 +, +0001 +0000 +1000 +0100 +0000 +0100 +0000 +0010 +0000 +0001 +0010 +0100 +1000 +0100 +0010 +0001 +, +1000 +1000 +0001 +0010 +0100 +1000 +0010 +0100 +, +0001 +0000 +0001 +0000 +0100 +0000 +0010 +0000 +1000 +0000 +0001 +0000 +0010 +0100 +0010 +0001 +, +1000 +0000 +0010 +0000 +0010 +0000 +0100 +0001 +0000 +1000 +0000 +0100 +0010 +0000 +0001 +0000 +, +M102 +0000 +0000 +M023 +0000 +0030 +210M +0000 +0000 +302M +0000 +0000 +M130 +0001 +1000 +0100 +, +1000 +00M0 +1020 +M000 +1030 +000M +1002 +M000 +, +1003 +0M00 +1200 +M000 +1300 +000M +1002 +M000 +, +1003 +00M0 +1020 +M000 +1030 +0M00 +1200 +M000 +, +1300 +0000 +0001 +0000 +00M1 +0000 +0100 +0000 +M100 +0000 +0010 +0000 +001M +0000 +1000 +0010 +, +0100 +M000 +0201 +000M +0301 +M000 +2001 +000M +, +3001 +00M0 +0021 +000M +0031 +M000 +2001 +000M +, +3001 +0M00 +0201 +000M +0301 +00M0 +0021 +000M +, +0031 +0000 +1000 +0000 +1M00 +0000 +0010 +0000 +001M +0000 +0100 +0000 +01M0 +0000 +0001 +1000 +, +0100 +1000 +10M0 +0001 +1000 +1000 +001M +1000 +, +1000 +0001 +1M00 +1000 +0010 +1000 +010M +1000 +, +0001 +1000 +10M0 +0100 +1000 +1000 +001M +1000 +, +1000 +0001 +0010 +0100 +0010 +0100 +1000 +0001 +1000 +0001 +0100 +0010 +0100 +0001 +0100 +0010 +, +1000 +0001 +00M1 +0100 +0001 +0001 +M010 +0001 +, +0001 +0100 +00M1 +0001 +1000 +0001 +0M10 +0001 +, +1000 +0001 +00M1 +0100 +0001 +0001 +M010 +0001 +, +0001 +0100 +0010 +1000 +0010 +1000 +0001 +0010 +0001 +0010 +0100 +1000 +0100 +0010 +0001 +1000 +, +0010 +0100 +0020 +0000 +1030 +0000 +0010 +0100 +0020 +0000 +1030 +0000 +0010 +0100 +0001 +0100 +, +0010 +0100 +0020 +0000 +1030 +0000 +0010 +0100 +0010 +1000 +0001 +1000 +0100 +0010 +0001 +0010 +, +0100 +0010 +0200 +0000 +1300 +0000 +0100 +0010 +0001 +1000 +0001 +1000 +0001 +0010 +0100 +0000 +, +1000 +0100 +0010 +0001 +0010 +0001 +1000 +0010 +1000 +0010 +0100 +0001 +0100 +0010 +1000 +0001 +, +0100 +0010 +0200 +0000 +0301 +0000 +0100 +0010 +0200 +0000 +0301 +0000 +0100 +0010 +1000 +0010 +, +0100 +0010 +0200 +0000 +0301 +0000 +0100 +0010 +0100 +0010 +1000 +0010 +0100 +0001 +1000 +0100 +, +0010 +0100 +0020 +0000 +0031 +0000 +0010 +0100 +1000 +0001 +1000 +0100 +0010 +0001 +1000 +0000 +, +0001 +0100 +0010 +0100 +0010 +0100 +0010 +1000 +0M01 +0010 +0100 +1000 +00M1 +0100 +0010 +1000 +, +0001 +0100 +001M +1000 +010M +0010 +0011 +0001 +, +1001 +0000 +1000 +0000 +00M1 +0000 +0100 +0000 +0110 +0000 +0010 +0000 +1000 +0001 +0010 +0100 +, +1000 +0001 +M010 +0110 +010M +1000 +1001 +0001 +, +0101 +0000 +0100 +0000 +00M1 +0000 +1000 +0000 +0001 +0010 +0100 +1000 +0001 +0000 +0100 +0000 +, +1001 +1000 +00M1 +0100 +00M1 +1000 +00M1 +0100 +, +1001 +0000 +0001 +0000 +10M0 +0000 +0100 +0000 +10M0 +0000 +0001 +0000 +1000 +0100 +0010 +0001 +, +1000 +0001 +1M00 +0010 +1M00 +0001 +1M00 +0010 +, +1001 +0000 +1000 +0000 +010M +0000 +0010 +0000 +0100 +1000 +0001 +1000 +0010 +0100 +0001 +1000 +, +0M20 +0000 +0000 +0000 +0100 +0000 +0000 +0000 +1030 +0000 +0000 +0000 +0022 +0000 +0000 +0033 +, +2100 +0000 +0000 +0000 +3010 +0000 +0000 +0000 +0022 +0000 +0000 +0033 +0220 +0000 +0000 +0330 +, +1002 +0000 +0000 +0000 +0100 +0000 +0000 +0000 +1003 +0000 +0010 +0000 +2020 +0000 +0000 +3030 +, +0201 +0000 +0310 +0000 +2001 +0010 +3010 +0000 +, +012M +1M00 +010M +1M30 +, +21M0 +001M +01M0 +301M +, +M201 +001M +M001 +031M +, +10M2 +0M10 +10M0 +0M10 +, +M2M3 +00M0 +0301 +1000 +0200 +00M0 +1300 +0001 +, +0200 +00M0 +0301 +1000 +0200 +000M +1300 +0001 +, +0020 +M000 +0130 +0010 +0002 +00M0 +1003 +0010 +, +0200 +000M +0310 +1000 +0002 +0M00 +0013 +0100 +, +2000 +00M0 +3001 +0010 +0002 +0M00 +1003 +0100 +, +2000 +00M0 +3001 +0100 +0002 +00M0 +1003 +0010 +, +2000 +000M +3100 +0010 +0200 +000M +1300 +0010 +, +2000 +0M00 +3001 +0100 +0002 +M000 +0013 +0220 +, +0030 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0300 +0000 +0000 +0000 +; + +//---------------dance-single - ---------------- +#NOTEDATA:; +#CHARTNAME:Wyde; +#STEPSTYPE:dance-single; +#DESCRIPTION:; +#CHARTSTYLE:; +#DIFFICULTY:Hard; +#METER:10; +#RADARVALUES:0.805,0.790,0.457,0.695,0.233,471.000,48.000,73.000,25.000,0.000,0.000,0.000,0.000,0.805,0.790,0.457,0.695,0.233,471.000,48.000,73.000,25.000,0.000,0.000,0.000,0.000; +#CREDIT:Wyde; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0001 +0100 +0000 +0010 +0000 +1000 +0000 +0001 +, +0010 +0001 +0000 +1000 +0000 +0100 +0010 +0001 +, +1000 +0001 +0000 +0100 +0000 +0010 +0000 +1000 +, +0100 +1000 +0000 +0001 +0000 +0010 +0100 +1000 +, +0001 +0100 +0000 +0010 +0000 +1000 +0000 +0100 +, +0010 +0100 +0000 +1000 +0000 +0001 +0010 +0001 +, +1000 +0010 +0000 +1000 +0000 +0100 +0000 +0010 +, +0100 +0010 +0000 +0001 +0000 +1000 +0001 +0100 +, +0010 +1000 +0000 +0101 +0000 +1001 +0000 +1100 +, +00M0 +0000 +1100 +0000 +0000 +0000 +0110 +0000 +0000 +0000 +0001 +0000 +1000 +0001 +1000 +0010 +, +1000 +0001 +0000 +0101 +0000 +0110 +0000 +1010 +, +0M00 +0000 +1010 +0000 +0000 +0000 +0011 +0000 +0000 +0000 +1000 +0000 +0001 +1000 +0001 +0010 +, +0001 +1000 +0000 +1010 +0000 +1001 +0000 +0011 +, +M000 +0000 +0011 +0000 +0000 +0000 +0110 +0000 +0000 +0000 +1000 +0000 +0001 +1000 +0001 +0100 +, +0001 +1000 +0000 +1100 +0000 +0110 +0000 +0001 +, +2M00 +0000 +0000 +3020 +0000 +0000 +023M +0000 +0000 +0302 +0000 +0000 +1003 +0010 +1000 +0010 +, +0100 +0100 +0000 +0110 +0000 +0100 +0010 +1000 +, +0100 +0000 +0100 +0000 +0000 +0000 +0110 +0000 +0000 +0000 +0100 +0000 +1000 +0001 +0010 +0001 +, +1000 +0000 +0100 +0000 +1000 +0000 +0000 +0001 +0000 +1000 +0000 +0001 +0100 +0000 +0001 +0000 +, +1000 +0000 +0001 +0010 +0000 +0100 +0000 +0010 +0000 +0100 +1000 +0100 +1000 +0000 +0001 +1000 +, +0001 +0001 +0000 +1001 +0000 +0001 +0100 +0010 +, +1000 +0000 +1000 +0000 +0000 +0000 +1001 +0000 +0000 +0000 +0001 +0000 +0010 +0001 +0010 +0100 +, +1000 +0000 +0001 +0000 +1000 +0000 +0000 +0010 +0000 +0100 +0000 +0010 +0100 +0000 +0001 +0000 +, +20M0 +0000 +0000 +3200 +0000 +0000 +M320 +0000 +0000 +0032 +0000 +0000 +1003 +0010 +0100 +0010 +, +1000 +2001 +3001 +0012 +, +0013 +0120 +0130 +1200 +, +1300 +2010 +3010 +0120 +, +0130 +0000 +0001 +0000 +0001 +0000 +1000 +0000 +1000 +0000 +0100 +0000 +0100 +0000 +0010 +0100 +, +0010 +0021 +0031 +0102 +, +0103 +0210 +0310 +1020 +, +1030 +2001 +3001 +0012 +, +0013 +0000 +0100 +0000 +0100 +0000 +1000 +0000 +1000 +0000 +0001 +0000 +0001 +0000 +1000 +0010 +, +1000 +0200 +0000 +0310 +0002 +0000 +1003 +0020 +, +0000 +0130 +0002 +0000 +1003 +0010 +1000 +0001 +, +0010 +0200 +0000 +1300 +0002 +0000 +0103 +0010 +, +1000 +0001 +0001 +1000 +1000 +0100 +0100 +0010 +, +0001 +0200 +0000 +0310 +2000 +0000 +3100 +0020 +, +0000 +0130 +2000 +0000 +3001 +0100 +0001 +1000 +, +0010 +0200 +0000 +0301 +0020 +0000 +0130 +1000 +, +0001 +0010 +0010 +0001 +0001 +1000 +1000 +0001 +, +0100 +0010 +0100 +0000 +0001 +0000 +0100 +0010 +0100 +0000 +0001 +0000 +1000 +0000 +0100 +0000 +, +0010 +0001 +0010 +0000 +0100 +0000 +0010 +0001 +0010 +0000 +0100 +0000 +1000 +0001 +1000 +0000 +, +0001 +1000 +0001 +0000 +0100 +0000 +0001 +1000 +0001 +0000 +0100 +0000 +0010 +0000 +1000 +0000 +, +0001 +0010 +0010 +0100 +0100 +1000 +1000 +0001 +, +1000 +0010 +1000 +0000 +0001 +0000 +1000 +0010 +1000 +0000 +0001 +0000 +0100 +0000 +0010 +0000 +, +0100 +0001 +0100 +0000 +0010 +0000 +0100 +0001 +0100 +0000 +0010 +0000 +1000 +0001 +1000 +0000 +, +0001 +1000 +0001 +0000 +0010 +0000 +0001 +1000 +0001 +0000 +0010 +0000 +0100 +0000 +1000 +0000 +, +0020 +0000 +0000 +0000 +1030 +0001 +1000 +0001 +, +1002 +1003 +0100 +1000 +0001 +1000 +0020 +0130 +, +0002 +0103 +0010 +1000 +0002 +0013 +0100 +0100 +, +0020 +0130 +1000 +0002 +1003 +0100 +0020 +0031 +, +0200 +0310 +1000 +0001 +0020 +0130 +1000 +1000 +, +0002 +0103 +0001 +0100 +0001 +0100 +0001 +0100 +, +0020 +1030 +0010 +1000 +0010 +1000 +0010 +0010 +, +2000 +3001 +1000 +0001 +1000 +0001 +1000 +0001 +, +0020 +0000 +0130 +0000 +0010 +0000 +0100 +0000 +0010 +0000 +0100 +0000 +1000 +0100 +0010 +0001 +, +2000 +0100 +3001 +0011 +, +0201 +0310 +1010 +1001 +, +0021 +0100 +0031 +1100 +, +2010 +3100 +0102 +1003 +, +201M +0M10 +001M +3M10 +, +M012 +0M10 +M010 +0M13 +, +210M +01M0 +010M +31M0 +, +M102 +0000 +0000 +0000 +01M0 +0000 +0000 +0000 +M100 +0000 +0000 +00M0 +0103 +0000 +0000 +0000 +, +1M2M +0000 +1030 +0001 +2000 +0000 +3001 +1000 +, +0002 +0000 +1003 +0001 +2000 +0000 +3001 +1000 +, +0200 +0000 +0310 +0100 +0020 +0000 +0031 +0010 +, +0200 +0000 +1300 +0100 +0020 +0000 +0031 +1000 +, +0020 +0000 +0130 +0010 +0200 +0000 +0310 +0100 +, +0020 +0000 +1030 +0010 +2000 +0000 +3010 +1000 +, +0020 +0000 +1030 +0001 +2000 +0000 +3001 +1000 +, +0002 +0000 +0013 +0001 +0020 +0000 +0031 +2002 +, +0003 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +3000 +0000 +0000 +0000 +; + +//---------------dance-single - ---------------- +#NOTEDATA:; +#CHARTNAME:Wyde; +#STEPSTYPE:dance-single; +#DESCRIPTION:; +#CHARTSTYLE:; +#DIFFICULTY:Medium; +#METER:8; +#RADARVALUES:0.605,0.602,0.429,0.476,0.019,350.000,45.000,50.000,0.000,0.000,0.000,0.000,0.000,0.605,0.602,0.429,0.476,0.019,350.000,45.000,50.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Wyde; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +1000 +1000 +0001 +0001 +, +1000 +0000 +1000 +0000 +0001 +0000 +0001 +1000 +, +0001 +0001 +0010 +0010 +, +0001 +0000 +0001 +0000 +0010 +0000 +0010 +0001 +, +0010 +0010 +0100 +0100 +, +0010 +0000 +0010 +0000 +0100 +0000 +0100 +0010 +, +0100 +0100 +1000 +1000 +, +0100 +0000 +0100 +0000 +1000 +0000 +1000 +0001 +, +1000 +0010 +0000 +0010 +0000 +0010 +0000 +0010 +, +0000 +0010 +0000 +0010 +0000 +0100 +0001 +0010 +, +0100 +1000 +0000 +1000 +0000 +1000 +0000 +1000 +, +0000 +1000 +0000 +1000 +0000 +0100 +1000 +0010 +, +0100 +0001 +0000 +0001 +0000 +0001 +0000 +0001 +, +0000 +0001 +0000 +0001 +0000 +0010 +0100 +1000 +, +0010 +0100 +0000 +0100 +0000 +0100 +0000 +0100 +, +0002 +0000 +0000 +2003 +0000 +0000 +3002 +0000 +0000 +2003 +0000 +0000 +3100 +0000 +0010 +0000 +, +0001 +1000 +0000 +1000 +0000 +1000 +0010 +0100 +, +0001 +1000 +0000 +1000 +0000 +1000 +0100 +0010 +, +0001 +1000 +0010 +1000 +0000 +1000 +0000 +1000 +, +0100 +1000 +0000 +1000 +0000 +0001 +0100 +0010 +, +1000 +0001 +0000 +0001 +0000 +0001 +0010 +0100 +, +1000 +0001 +0000 +0001 +0000 +0001 +0100 +0010 +, +1000 +0001 +0010 +0001 +0000 +0001 +0000 +0001 +, +0200 +0000 +0000 +0320 +0000 +0000 +0230 +0000 +0000 +0320 +0000 +0000 +1030 +0000 +0001 +0000 +, +1000 +1100 +1000 +1100 +, +1000 +1001 +1000 +1001 +, +1000 +1010 +1000 +1010 +, +1000 +0001 +0010 +0001 +1000 +0001 +1000 +0001 +, +0100 +0101 +0001 +0101 +, +0001 +1001 +0001 +1001 +, +0001 +0011 +0001 +0011 +, +0001 +1000 +0010 +1000 +0001 +1000 +0001 +1000 +, +0100 +0000 +0010 +0001 +0010 +0000 +0110 +0000 +, +0100 +1000 +0100 +0000 +0011 +0000 +1001 +0000 +, +1010 +0000 +1000 +0001 +1000 +0000 +1010 +0000 +, +0010 +0100 +0010 +1000 +0010 +0100 +0001 +1000 +, +0010 +0000 +1000 +0001 +1000 +0000 +1100 +0000 +, +0100 +1000 +0100 +0000 +1001 +0000 +0110 +0000 +, +1001 +0000 +0001 +0100 +0001 +0000 +1001 +0000 +, +1000 +0010 +1000 +0001 +1000 +0100 +0010 +0001 +, +2000 +0000 +3010 +2000 +0000 +3010 +0100 +0001 +, +2000 +0000 +3100 +2000 +0000 +3100 +0010 +0001 +, +2000 +0000 +3001 +1000 +0001 +0001 +1000 +0001 +, +0000 +0100 +0010 +1000 +0001 +0010 +0100 +1000 +, +0002 +0000 +0103 +0002 +0000 +0103 +0010 +1000 +, +0002 +0000 +0013 +0002 +0000 +0013 +0100 +1000 +, +0002 +0000 +1003 +0001 +1000 +1000 +0001 +0010 +, +0200 +0000 +0000 +0000 +1300 +0001 +1000 +0001 +, +0100 +0110 +0101 +1010 +, +0011 +0000 +1001 +0000 +0110 +0000 +0001 +1000 +, +0100 +0000 +0010 +0001 +1000 +0000 +0011 +0000 +, +0101 +0000 +1001 +0000 +0110 +0000 +0001 +1000 +, +0010 +1001 +1010 +1001 +, +0101 +0000 +0110 +0000 +0101 +0000 +0010 +1000 +, +0001 +0011 +1001 +0011 +, +1100 +0000 +0110 +0000 +1100 +0000 +0010 +0001 +, +2000 +0000 +0001 +3020 +, +0230 +0000 +0302 +0023 +, +0230 +0000 +1000 +0320 +, +0032 +0000 +2003 +0000 +, +3020 +0000 +0100 +0000 +, +0230 +0000 +0001 +0000 +, +0302 +0000 +1000 +0000 +, +2003 +0000 +0100 +0000 +, +3002 +0000 +0003 +0001 +2000 +0000 +3000 +1000 +, +0002 +0000 +0003 +0001 +2000 +0000 +3000 +1000 +, +0200 +0000 +0300 +0100 +0020 +0000 +0031 +1000 +, +0020 +0000 +0030 +0010 +0200 +0000 +0300 +0100 +, +0002 +0000 +0003 +0001 +0200 +0000 +0300 +0100 +, +0020 +0000 +0030 +0010 +2000 +0000 +3000 +1000 +, +0002 +0000 +0003 +0001 +0020 +0000 +0030 +0010 +, +0200 +0000 +0300 +0100 +2000 +0000 +3000 +2002 +, +3000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0003 +0000 +0000 +0000 +; + +//---------------dance-single - ---------------- +#NOTEDATA:; +#CHARTNAME:Wyde; +#STEPSTYPE:dance-single; +#DESCRIPTION:; +#CHARTSTYLE:; +#DIFFICULTY:Easy; +#METER:6; +#RADARVALUES:0.484,0.527,0.324,0.495,0.000,270.000,34.000,52.000,0.000,0.000,0.000,0.000,0.000,0.484,0.527,0.324,0.495,0.000,270.000,34.000,52.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Wyde; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +1000 +0001 +1000 +0001 +, +1000 +0000 +0001 +0000 +1000 +0000 +0001 +1000 +, +0001 +1000 +0001 +1000 +, +0001 +0000 +1000 +0000 +0001 +0000 +1000 +0001 +, +1000 +0001 +1000 +0001 +, +1000 +0000 +0001 +0000 +1000 +0000 +0001 +1000 +, +0001 +1000 +0001 +1000 +, +0001 +0000 +1000 +0000 +0001 +0000 +1000 +0001 +, +1000 +0100 +1000 +0100 +, +0010 +0000 +0100 +0000 +0010 +0000 +0001 +0010 +, +0001 +1000 +0001 +1000 +, +0010 +0000 +1000 +0000 +0010 +0000 +0100 +0010 +, +0100 +0001 +0100 +0001 +, +1000 +0000 +0001 +0000 +1000 +0000 +0100 +1000 +, +0100 +0010 +0100 +0010 +, +2002 +0000 +0000 +3003 +0000 +0000 +0220 +0000 +0000 +0330 +0000 +0000 +1001 +0000 +0000 +0000 +, +1000 +0100 +0010 +0001 +, +1000 +0000 +0001 +0000 +0010 +0000 +0100 +1000 +, +0100 +0010 +0001 +1000 +, +0001 +0000 +0010 +0000 +0100 +0000 +1000 +0001 +, +1000 +0010 +0100 +0001 +, +1000 +0000 +0001 +0000 +0100 +0000 +0010 +1000 +, +0010 +0100 +0001 +1000 +, +2002 +0000 +0000 +3003 +0000 +0000 +0220 +0000 +0000 +0330 +0000 +0000 +1001 +0000 +0000 +0000 +, +1000 +0200 +1300 +0002 +, +1003 +0020 +1030 +0002 +, +1003 +0200 +1300 +0002 +, +1003 +0000 +1000 +0000 +0001 +1000 +0001 +1000 +, +0001 +0020 +0031 +2000 +, +3001 +0200 +0301 +2000 +, +3001 +0020 +0031 +2000 +, +3001 +0000 +0001 +0000 +1000 +0001 +1000 +0001 +, +1000 +0000 +0000 +0011 +0000 +0000 +0101 +0000 +, +0000 +1010 +0000 +0000 +1001 +0000 +0110 +0000 +, +1001 +0000 +0000 +0011 +0000 +0000 +1100 +0000 +, +1000 +0000 +0100 +0000 +0010 +0001 +0010 +0001 +, +0010 +0000 +0000 +1010 +0000 +0000 +0101 +0000 +, +0000 +0011 +0000 +0000 +0110 +0000 +1001 +0000 +, +0110 +0000 +0000 +1100 +0000 +0000 +0101 +0000 +, +0001 +0000 +1000 +0000 +0010 +0100 +0010 +0100 +, +0010 +1000 +0100 +0010 +, +0100 +1000 +0010 +0100 +, +0010 +1000 +0100 +0010 +, +0001 +0000 +1000 +0000 +0100 +1000 +0100 +1000 +, +0100 +0010 +0001 +0100 +, +0010 +0100 +0001 +0010 +, +0100 +0010 +0001 +0100 +, +0020 +0000 +0000 +0000 +1030 +0001 +1000 +0001 +, +1000 +0100 +0010 +0110 +, +1100 +1000 +1001 +0101 +, +0110 +0000 +0000 +1010 +0000 +0000 +0011 +0000 +, +1001 +0000 +1000 +0000 +1010 +0000 +0010 +1000 +, +0010 +0100 +0001 +0100 +, +0101 +0000 +0001 +0000 +1000 +0000 +0001 +0010 +, +0001 +1000 +0100 +1000 +, +1100 +0000 +0100 +0000 +0010 +0000 +0001 +1000 +, +0002 +0000 +0000 +0023 +, +0032 +0000 +2003 +3020 +, +0230 +0000 +0000 +0302 +, +2003 +0000 +3200 +0000 +, +0320 +0000 +0000 +0000 +, +0032 +0000 +0000 +0000 +, +2003 +0000 +0000 +0000 +, +3020 +0000 +0000 +0000 +, +0230 +0300 +0200 +0300 +, +0200 +0300 +0200 +0300 +, +0002 +0003 +0002 +0013 +, +0200 +0300 +0020 +0030 +, +0002 +0003 +2000 +3000 +, +0002 +0003 +2000 +3000 +, +0002 +0003 +2000 +3000 +, +0002 +0000 +0003 +0000 +2000 +0000 +3000 +2002 +, +3000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0003 +0000 +0000 +0000 +; + +//---------------dance-single - ---------------- +#NOTEDATA:; +#CHARTNAME:Wyde; +#STEPSTYPE:dance-single; +#DESCRIPTION:; +#CHARTSTYLE:; +#DIFFICULTY:Beginner; +#METER:2; +#RADARVALUES:0.265,0.289,0.181,0.171,0.000,158.000,19.000,18.000,2.000,0.000,0.000,0.000,0.000,0.265,0.289,0.181,0.171,0.000,158.000,19.000,18.000,2.000,0.000,0.000,0.000,0.000; +#CREDIT:Wyde; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0100 +0000 +0000 +0000 +, +1001 +0000 +0000 +0010 +, +0010 +0000 +0000 +0000 +, +1001 +0000 +0000 +0100 +, +0100 +0000 +0000 +0000 +, +1001 +0000 +0000 +0010 +, +0010 +0000 +0000 +0000 +, +1001 +0000 +0000 +0100 +, +0100 +0000 +0010 +0000 +, +1001 +0000 +0000 +0010 +, +0010 +0000 +0100 +0000 +, +1001 +0000 +0000 +0100 +, +0100 +0000 +0010 +0000 +, +1001 +0000 +0000 +0010 +, +0010 +0000 +0100 +0000 +, +0220 +0000 +0330 +0000 +, +0001 +0000 +0100 +0000 +, +1001 +0000 +0100 +0000 +, +1000 +0000 +0100 +0000 +, +1001 +0000 +0010 +0000 +, +1000 +0000 +0010 +0000 +, +1001 +0000 +0010 +0000 +, +0001 +0000 +0010 +0000 +, +0220 +0000 +0330 +0000 +, +1000 +1000 +1000 +1000 +, +1000 +1000 +1000 +1000 +, +1000 +1000 +1000 +1000 +, +1000 +0000 +0000 +0000 +, +0001 +0001 +0001 +0001 +, +0001 +0001 +0001 +0001 +, +0001 +0001 +0001 +0001 +, +0001 +0000 +0000 +0000 +, +0010 +0010 +0010 +0010 +, +0010 +0010 +0010 +0010 +, +0010 +0010 +0010 +0010 +, +0020 +0000 +0030 +0000 +, +0100 +0100 +0100 +0100 +, +0100 +0100 +0100 +0100 +, +0100 +0100 +0100 +0100 +, +0200 +0000 +0300 +0000 +, +1001 +0000 +0010 +0000 +, +1001 +0000 +0010 +0000 +, +1001 +0000 +0010 +0000 +, +1000 +1000 +1000 +0000 +, +1001 +0000 +0100 +0000 +, +1001 +0000 +0100 +0000 +, +1001 +0000 +0100 +0000 +, +0000 +0000 +0001 +0001 +, +0002 +0003 +0000 +1000 +, +1000 +0000 +0100 +0100 +, +0200 +0300 +0000 +0010 +, +0010 +0000 +0001 +0000 +, +2000 +3000 +1000 +0000 +, +0002 +0003 +0001 +0000 +, +0200 +0300 +0100 +0000 +, +0020 +0030 +0010 +0000 +, +2000 +0000 +3000 +1000 +, +1000 +0000 +0001 +0001 +, +0002 +0000 +0003 +0001 +, +0001 +0000 +0010 +0000 +, +0200 +0000 +0300 +0000 +, +2000 +0000 +3000 +0000 +, +0002 +0000 +0003 +0000 +, +0200 +0000 +0300 +0000 +, +1001 +0000 +1000 +0000 +, +1000 +0000 +1000 +0000 +, +0010 +0000 +0100 +0100 +, +0100 +0000 +0001 +0000 +, +0010 +0000 +0100 +0000 +, +0010 +0000 +0100 +0000 +, +0010 +0000 +0100 +0000 +, +0010 +0000 +0000 +0000 +0100 +0000 +0000 +M00M +; + +//---------------dance-solo - ---------------- +#NOTEDATA:; +#CHARTNAME:Hard; +#STEPSTYPE:dance-solo; +#DESCRIPTION:; +#CHARTSTYLE:Pad; +#DIFFICULTY:Hard; +#METER:10; +#RADARVALUES:0.710,0.828,0.229,0.324,0.190,464.000,24.000,34.000,6.000,5.000,8.000,0.000,0.000,0.710,0.828,0.229,0.324,0.190,464.000,24.000,34.000,6.000,5.000,8.000,0.000,0.000; +#CREDIT:Jason Felds; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=4 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +,303.500000=0.250000=12.500000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +000000 +000000 +000000 +000000 +, +000000 +000000 +000000 +000000 +, +000000 +000000 +000000 +000000 +, +000000 +000000 +000000 +000000 +, +000001 +001000 +000000 +000001 +000000 +010000 +000000 +000010 +, +010000 +000100 +000000 +100000 +000000 +000001 +000000 +001000 +, +000010 +010000 +000000 +001000 +000000 +000100 +000000 +000010 +, +000001 +000100 +000000 +001000 +000000 +000010 +000000 +100000 +, +000100 +000001 +000000 +100000 +000000 +001000 +000000 +000001 +, +000010 +001000 +000000 +010000 +000000 +000010 +000000 +001000 +, +000100 +010000 +000000 +000001 +000000 +010000 +000000 +100000 +, +000100 +000010 +000000 +001000 +000000 +000010 +000000 +100000 +, +001000 +000100 +000000 +000101 +000000 +000001 +000000 +010001 +, +000000 +000000 +010000 +000000 +000000 +000000 +011000 +000000 +000000 +000000 +001000 +000000 +100000 +000001 +100000 +000010 +, +010000 +000100 +000000 +001100 +000000 +001000 +000000 +001010 +, +000000 +000000 +000010 +000000 +000000 +000000 +100010 +000000 +000000 +000000 +100000 +000000 +000010 +001000 +000001 +001000 +, +000100 +100000 +000000 +101000 +000000 +001000 +000000 +001010 +, +000000 +000000 +000010 +000000 +000000 +000000 +000011 +000000 +000000 +000000 +000001 +000000 +000100 +100000 +000100 +001000 +, +000010 +000001 +000000 +001001 +000000 +001000 +000000 +001100 +, +000200 +000000 +000000 +200300 +000000 +000000 +000002 +000000 +000000 +020000 +000000 +000000 +330013 +000000 +000000 +000000 +, +100000 +001000 +000000 +011000 +000000 +010000 +000000 +010010 +, +000000 +000000 +000010 +000000 +000000 +000000 +001010 +000000 +000000 +000000 +001000 +000000 +000001 +100000 +000001 +010000 +, +000010 +010000 +000000 +011000 +000000 +001000 +000000 +001010 +, +000000 +000000 +000010 +000000 +000000 +000000 +000011 +000000 +000000 +000000 +000001 +000000 +010000 +000100 +100000 +000100 +, +001000 +000001 +000000 +000101 +000000 +000100 +000000 +001100 +, +000000 +000000 +001000 +000000 +000000 +000000 +101000 +000000 +000000 +000000 +100000 +000000 +000100 +000001 +000100 +001000 +, +010000 +100000 +000000 +100100 +000000 +000100 +000000 +001100 +, +002000 +000000 +000000 +003002 +000000 +000000 +200000 +000000 +000000 +000020 +000000 +000000 +310033 +000000 +000000 +000000 +, +100000 +000010 +010000 +000010 +000100 +000010 +001000 +000010 +, +000001 +000010 +001000 +000010 +010000 +000010 +100000 +000010 +, +010000 +001000 +000100 +000001 +000010 +001000 +010000 +000100 +, +100000 +000000 +100000 +000000 +000010 +000000 +000010 +000000 +010000 +000000 +010000 +000000 +000100 +000000 +000100 +001000 +, +000001 +010000 +000010 +010000 +000100 +010000 +001000 +010000 +, +100000 +010000 +001000 +010000 +000010 +010000 +000001 +010000 +, +000010 +000100 +001000 +100000 +010000 +001000 +000010 +000100 +, +000001 +000000 +000001 +000000 +010000 +000000 +010000 +000000 +000010 +000000 +000010 +000000 +001000 +000000 +001000 +000100 +, +020000 +000010 +030010 +000020 +001000 +001030 +002000 +000001 +, +003001 +000002 +010000 +010003 +010000 +000010 +001000 +000100 +, +200000 +000001 +300001 +000002 +010000 +010003 +020000 +030010 +, +004000 +000004 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +003003 +000000 +, +000020 +010000 +010030 +020000 +000100 +030100 +000200 +100000 +, +100300 +200000 +000010 +300010 +000010 +010000 +000100 +001000 +, +000002 +100000 +100003 +200000 +000010 +300010 +000020 +010030 +, +000400 +400000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +300300 +000000 +, +010000 +000010 +010000 +000000 +001000 +000000 +010000 +000010 +010000 +000000 +000100 +000000 +010000 +000010 +010000 +000000 +, +000001 +001000 +000001 +000000 +000100 +000000 +000001 +001000 +000001 +000000 +000010 +000000 +000001 +001000 +000001 +000000 +, +100000 +010000 +100000 +000000 +001000 +000000 +100000 +010000 +100000 +000000 +000010 +000000 +100000 +010000 +100000 +000000 +, +000040 +004000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +003030 +000000 +, +000010 +010000 +000010 +000000 +000100 +000000 +000010 +010000 +000010 +000000 +001000 +000000 +000010 +010000 +000010 +000000 +, +100000 +000100 +100000 +000000 +001000 +000000 +100000 +000100 +100000 +000000 +010000 +000000 +100000 +000100 +100000 +000000 +, +000001 +000010 +000001 +000000 +000100 +000000 +000001 +000010 +000001 +000000 +010000 +000000 +000001 +000010 +000001 +000000 +, +040000 +000400 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +000000 +030300 +000000 +, +000010 +001000 +000001 +000100 +000010 +010000 +001000 +100000 +, +000100 +001000 +100000 +001000 +000010 +010000 +000001 +000100 +, +000010 +001000 +010000 +001000 +000100 +100000 +000001 +000100 +, +001000 +000100 +100000 +000100 +010000 +000100 +100000 +000100 +, +001000 +010000 +000100 +001000 +000010 +010000 +001000 +100000 +, +000100 +001000 +000001 +000010 +000001 +010000 +001000 +000100 +, +000001 +001000 +000010 +100000 +010000 +100000 +000100 +001000 +, +000010 +010000 +000001 +001000 +010000 +000100 +000010 +001000 +, +000002 +010000 +100000 +010000 +, +002003 +000100 +000010 +000100 +, +023000 +100000 +001000 +100000 +, +030002 +000100 +010000 +000100 +, +000023 +010000 +001000 +010000 +, +000230 +100000 +010000 +100000 +, +002300 +000100 +000010 +000100 +, +203000 +000010 +001000 +300010 +, +000001 +000000 +010000 +001000 +010000 +000000 +000010 +001000 +, +000010 +000000 +100000 +000100 +100000 +000000 +000010 +010000 +, +000010 +000000 +001000 +000001 +001000 +000000 +000010 +000001 +, +000010 +000000 +100000 +000100 +100000 +000000 +010000 +001000 +, +010000 +000000 +100000 +000010 +100000 +000000 +000001 +000100 +, +000001 +000000 +010000 +001000 +010000 +000000 +000010 +100000 +, +000010 +000000 +001000 +000001 +001000 +000000 +000100 +010000 +, +000100 +000000 +001000 +000010 +001000 +000000 +000022 +220000 +, +000000 +000000 +000000 +000000 +, +000000 +000000 +000000 +000000 +, +000000 +000000 +000000 +330033 +, +MMMMMM +000000 +000000 +000000 +; + +//---------------pump-single - ---------------- +#NOTEDATA:; +#CHARTNAME:Vin.il; +#STEPSTYPE:pump-single; +#DESCRIPTION:; +#CHARTSTYLE:Pad; +#DIFFICULTY:Hard; +#METER:19; +#RADARVALUES:1.000,1.000,1.000,0.448,0.538,569.000,106.000,47.000,50.000,16.000,0.000,0.000,0.000,1.000,1.000,1.000,0.448,0.538,569.000,106.000,47.000,50.000,16.000,0.000,0.000,0.000; +#CREDIT:Vin.il; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=4 +,303.500000=16 +; +#COMBOS:0.000000=2 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +,76.000000=0.500000=0.375000=0 +,76.750000=1.000000=0.375000=0 +,77.500000=0.500000=0.375000=0 +,78.250000=1.000000=0.375000=0 +,79.000000=0.500000=0.375000=0 +,79.500000=1.000000=0.375000=0 +,108.000000=0.500000=0.375000=0 +,108.750000=1.000000=0.375000=0 +,109.500000=0.500000=0.375000=0 +,110.250000=1.000000=0.375000=0 +,111.000000=0.500000=0.375000=0 +,111.500000=1.000000=0.375000=0 +,206.000000=1.250000=0.000000=0 +,206.500000=1.500000=0.000000=0 +,207.000000=1.750000=0.000000=0 +,207.500000=2.000000=0.000000=0 +,272.000000=1.500000=0.250000=0 +,272.500000=2.000000=0.250000=0 +,273.000000=1.500000=0.250000=0 +,273.500000=2.000000=0.250000=0 +,274.000000=1.500000=0.250000=0 +,274.500000=2.000000=0.250000=0 +,275.000000=1.500000=0.250000=0 +,275.500000=2.000000=0.250000=0 +,276.000000=1.500000=0.250000=0 +,276.500000=2.000000=0.250000=0 +,277.000000=1.500000=0.250000=0 +,277.500000=2.000000=0.250000=0 +,278.000000=1.500000=0.250000=0 +,278.500000=2.000000=0.250000=0 +,279.000000=1.500000=0.250000=0 +,279.500000=2.000000=0.250000=0 +,280.000000=1.500000=0.250000=0 +,280.500000=2.000000=0.250000=0 +,281.000000=1.500000=0.250000=0 +,281.500000=2.000000=0.250000=0 +,282.000000=1.500000=0.250000=0 +,282.500000=2.000000=0.250000=0 +,283.000000=1.500000=0.250000=0 +,283.500000=2.000000=0.250000=0 +,284.000000=1.000000=0.250000=0 +,284.500000=2.000000=0.250000=0 +,285.000000=1.500000=0.250000=0 +,285.500000=2.000000=0.250000=0 +,286.000000=1.500000=0.250000=0 +,286.500000=2.000000=0.250000=0 +,287.000000=1.500000=0.250000=0 +,287.500000=2.000000=0.250000=0 +,288.000000=1.500000=0.250000=0 +,288.500000=2.000000=0.250000=0 +,289.000000=1.500000=0.250000=0 +,289.500000=2.000000=0.250000=0 +,290.000000=1.500000=0.250000=0 +,290.500000=2.000000=0.250000=0 +,291.000000=1.500000=0.250000=0 +,291.500000=2.000000=0.250000=0 +,292.000000=1.500000=0.250000=0 +,292.500000=2.000000=0.250000=0 +,293.000000=1.500000=0.250000=0 +,293.500000=2.000000=0.250000=0 +,294.000000=1.500000=0.250000=0 +,294.500000=2.000000=0.250000=0 +,295.000000=1.500000=0.250000=0 +,295.500000=2.000000=0.250000=0 +,296.000000=1.500000=0.250000=0 +,296.500000=2.000000=0.250000=0 +,297.000000=1.500000=0.250000=0 +,297.500000=2.000000=0.250000=0 +,298.000000=1.500000=0.250000=0 +,298.500000=2.000000=0.250000=0 +,299.000000=1.500000=0.250000=0 +,299.500000=2.000000=0.250000=0 +,300.000000=1.500000=0.250000=0 +,300.500000=2.000000=0.250000=0 +,301.000000=1.500000=0.250000=0 +,301.500000=2.000000=0.250000=0 +,302.000000=1.500000=0.250000=0 +,302.500000=2.000000=0.250000=0 +,303.000000=1.500000=0.250000=0 +,303.500000=2.000000=12.500000=0 +; +#SCROLLS:0.000000=1.000000 +,204.000000=0.500000 +,272.000000=0.250000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:TIME=101.194664:LEN=7.000000:MODS=*0.2399996928003932 Reverse, Overhead; +#NOTES: +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00110 +00000 +00010 +00100 +00010 +00000 +00010 +10100 +, +00010 +10100 +00010 +00000 +00010 +01100 +00010 +01000 +, +01100 +00000 +01000 +00100 +01000 +00000 +01000 +00101 +, +01000 +00101 +01000 +00000 +01000 +00110 +01000 +00010 +, +10100 +00000 +10000 +00100 +10000 +00000 +10000 +00110 +, +10000 +00110 +10000 +00000 +10000 +00101 +10000 +00001 +, +00101 +00000 +00001 +00100 +00001 +00000 +00001 +01100 +, +00001 +01100 +00001 +00000 +00001 +10100 +00001 +10000 +, +00101 +10000 +00010 +00110 +00010 +01000 +00100 +01001 +, +00100 +00000 +01001 +00000 +00100 +00000 +00010 +00000 +10000 +00000 +00110 +00000 +01000 +00100 +01000 +00100 +, +10000 +10000 +10100 +10000 +00001 +00001 +00101 +00001 +, +01000 +00000 +01000 +00000 +01100 +00000 +01000 +00000 +00010 +00000 +00010 +00000 +00010 +00100 +00010 +00100 +, +00001 +00000 +00100 +00000 +00101 +00000 +00001 +10000 +00100 +00000 +10000 +00000 +10100 +00000 +10000 +00010 +, +00100 +00000 +00010 +00000 +00110 +00000 +00010 +01000 +00100 +00000 +01000 +00000 +01000 +00100 +01000 +00010 +, +00100 +00000 +00001 +00100 +00001 +00000 +01000 +00000 +00100 +00000 +10000 +00100 +10000 +00000 +00001 +00000 +, +01101 +00000 +00000 +01010 +00000 +00000 +10110 +00000 +00000 +10001 +00000 +00000 +01101 +00000 +01010 +00000 +, +10010 +00000 +10000 +00000 +00100 +00000 +10000 +00000 +00100 +00000 +01000 +00000 +00010 +00000 +00100 +00001 +, +01000 +00000 +01000 +00000 +00100 +00000 +01000 +00000 +00100 +00000 +10000 +00000 +00001 +00100 +01000 +10000 +, +00010 +00000 +00010 +00000 +00100 +00000 +00010 +00100 +00000 +00100 +00001 +10000 +00100 +00000 +00100 +01000 +, +00001 +00000 +00001 +00100 +00001 +00100 +00000 +00010 +01000 +00100 +10000 +00010 +01000 +00000 +00010 +00100 +, +00001 +00000 +00001 +00000 +00100 +00000 +00001 +00000 +00100 +00000 +00010 +00000 +01000 +00000 +00100 +10000 +, +00010 +00000 +00010 +00000 +00100 +00000 +00010 +00000 +00100 +00000 +00001 +00000 +10000 +00100 +00010 +00001 +, +01000 +00000 +01000 +00000 +00100 +00000 +01000 +00100 +00000 +00100 +10000 +00001 +00100 +00000 +00100 +00000 +, +10110 +00000 +00000 +01010 +00000 +00000 +01101 +00000 +00000 +10001 +00000 +00000 +10110 +00000 +01010 +00000 +, +01001 +00001 +01101 +00001 +01001 +00001 +01001 +00001 +, +10010 +10000 +10110 +10000 +10010 +10000 +10010 +10000 +, +10010 +00010 +10110 +00010 +10010 +00010 +10010 +00010 +, +01001 +00000 +00100 +00000 +10010 +00000 +00100 +00000 +01000 +00001 +00100 +00001 +01000 +00010 +00100 +00001 +, +10001 +10000 +10101 +10000 +10001 +10000 +10001 +10000 +, +10001 +00001 +10101 +00001 +10001 +00001 +10001 +00001 +, +01010 +01000 +01110 +01000 +01010 +01000 +01010 +01000 +, +01010 +00000 +00100 +00000 +10001 +00000 +00100 +00000 +01000 +00100 +00010 +00001 +00100 +00010 +01000 +00100 +, +10000 +00010 +00110 +10000 +00010 +00110 +10000 +00010 +, +00110 +01000 +00001 +00101 +01000 +00001 +01000 +00001 +, +00101 +01000 +01100 +00001 +01000 +01100 +00001 +01000 +, +01100 +00000 +00010 +00000 +00010 +00000 +01000 +00000 +01000 +00000 +00100 +00000 +00100 +10000 +00001 +01000 +, +00010 +10000 +10100 +00010 +10000 +10100 +00010 +10000 +, +10100 +00001 +01000 +01100 +00001 +01000 +00001 +01000 +, +01100 +00001 +00101 +01000 +00001 +00101 +01000 +00001 +, +00101 +00000 +10000 +00000 +10000 +00000 +00001 +00000 +00001 +00000 +00100 +00000 +00100 +00010 +01000 +00001 +, +10000 +00100 +10000 +00100 +01000 +00000 +00001 +00100 +00001 +00100 +00010 +00000 +10000 +00100 +00001 +00000 +, +00010 +00100 +00010 +00100 +00001 +00000 +01000 +00100 +01000 +00100 +10000 +00000 +01000 +00100 +00010 +00000 +, +10000 +00010 +00100 +00010 +10000 +00000 +00001 +01000 +00100 +00000 +00100 +00000 +10000 +00100 +00010 +00000 +, +00001 +00100 +00001 +00000 +00001 +00000 +10000 +00000 +10000 +00000 +00100 +00000 +01000 +00100 +00010 +00001 +, +01000 +00100 +00010 +00100 +01000 +00000 +00010 +00100 +01000 +00100 +00010 +00000 +01000 +00100 +00010 +00000 +, +00001 +00100 +10000 +00100 +00001 +00000 +10000 +00100 +00001 +00100 +10000 +00000 +00001 +00100 +10000 +00000 +, +00010 +00100 +01000 +00100 +00010 +00000 +00001 +00100 +10000 +00000 +00001 +00000 +10000 +00100 +00001 +00000 +, +00010 +01000 +00010 +01000 +00010 +10000 +00010 +10000 +00001 +10000 +00001 +10000 +00001 +01000 +00001 +01000 +, +00020 +00000 +01130 +00000 +01000 +00100 +02000 +00000 +, +03002 +00000 +00100 +00000 +01103 +00000 +00000 +00000 +01000 +00000 +00010 +00000 +00100 +00010 +01000 +00100 +, +20000 +30101 +00002 +02003 +, +03100 +00000 +00100 +10000 +00020 +00030 +01010 +01010 +, +02010 +00100 +03001 +01000 +02010 +00100 +03001 +01000 +, +01020 +00100 +10030 +00010 +01020 +00100 +10030 +00010 +, +20010 +00100 +30001 +10000 +20010 +00100 +30001 +10000 +, +01002 +00000 +00100 +00000 +10003 +00000 +00001 +00000 +01002 +00000 +00100 +00000 +10003 +00000 +00001 +10000 +, +00020 +00000 +00100 +00000 +00100 +00030 +02000 +00000 +, +03020 +00100 +20030 +30002 +, +02003 +03100 +02000 +03100 +02000 +03100 +20000 +30000 +, +00002 +00103 +00002 +00103 +00020 +00130 +00020 +00130 +, +02001 +00100 +03010 +01000 +02001 +00100 +03010 +01000 +, +10020 +00100 +01030 +00010 +10020 +00100 +01030 +00010 +, +20001 +00100 +30010 +10000 +20001 +00100 +30010 +10000 +, +10002 +00100 +01003 +00001 +10002 +00100 +01003 +00001 +, +20101 +00000 +00000 +00000 +, +30002 +00000 +00000 +00000 +, +02003 +00000 +00000 +03020 +, +00230 +00000 +00320 +00000 +, +20030 +00000 +00000 +00000 +, +30002 +00000 +00000 +00000 +, +02003 +00000 +00000 +00000 +, +03020 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +02000 +M0000 +, +00M00 +0000M +00M00 +M0000 +00M00 +0000M +00M00 +M0000 +00M00 +0000M +00M00 +M0000 +00M00 +0000M +00M00 +M0000 +, +00M00 +0000M +00M00 +M0000 +00M00 +0000M +00M00 +M0000 +00M00 +0000M +00M00 +M0000 +00M00 +0000M +00M00 +M0000 +, +00M00 +0000M +00M00 +M0000 +00M00 +0000M +00M00 +M0000 +00M00 +0000M +00M00 +M0000 +00M00 +0000M +00M00 +M0000 +, +03M30 +00000 +00000 +00000 +; + +//---------------pump-single - ---------------- +#NOTEDATA:; +#CHARTNAME:Vin.il; +#STEPSTYPE:pump-single; +#DESCRIPTION:; +#CHARTSTYLE:Pad; +#DIFFICULTY:Medium; +#METER:13; +#RADARVALUES:0.925,1.000,1.000,0.667,0.195,454.000,156.000,70.000,0.000,0.000,0.000,0.000,0.000,0.925,1.000,1.000,0.667,0.195,454.000,156.000,70.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Vin.il; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=4 +,303.500000=8 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=4.000000=0.000000=0 +,76.000000=2.000000=4.000000=0 +,108.000000=1.000000=4.000000=0 +,206.000000=2.000000=2.000000=0 +,303.500000=0.000000=12.500000=0 +; +#SCROLLS:0.000000=0.250000 +,80.000000=0.500000 +,112.000000=1.000000 +,204.000000=0.500000 +,272.000000=0.250000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00110 +00000 +00010 +10010 +00000 +00000 +10000 +10001 +, +00000 +10001 +00000 +00000 +00000 +01001 +00000 +00000 +, +01100 +00000 +01000 +01001 +00000 +00000 +00001 +10001 +, +00000 +10001 +00000 +00000 +00000 +10010 +00000 +00000 +, +10100 +00000 +10000 +10010 +00000 +00000 +00010 +01010 +, +00000 +01010 +00000 +00000 +00000 +01001 +00000 +00000 +, +00101 +00000 +00001 +01001 +00000 +00000 +01000 +01010 +, +00000 +01010 +00000 +00000 +00000 +10010 +00000 +00000 +, +10100 +10000 +00001 +00101 +00000 +00001 +01000 +01100 +, +00000 +00000 +01010 +00000 +00000 +00000 +00010 +00000 +10000 +00000 +10010 +00000 +00010 +00000 +00100 +00001 +, +01000 +01000 +00010 +00110 +00000 +00010 +10000 +10100 +, +00000 +00000 +10001 +00000 +00000 +00000 +00001 +00000 +01000 +00000 +01001 +00000 +00001 +00000 +00100 +00010 +, +10000 +00100 +10000 +10001 +00000 +00001 +00100 +01001 +, +00100 +00000 +01001 +00000 +00000 +00000 +00100 +00000 +10000 +00000 +10010 +00000 +00010 +00000 +00100 +00001 +, +01000 +00100 +01000 +01010 +00000 +00010 +00100 +10010 +, +01001 +00000 +00000 +00100 +00000 +00000 +10010 +00000 +00000 +00100 +00000 +00000 +01010 +00000 +00100 +00000 +, +10001 +00001 +00000 +01001 +01000 +00010 +00100 +00001 +, +10001 +00000 +10000 +00000 +00000 +00000 +10010 +00000 +00010 +00000 +01000 +00000 +00100 +10000 +00010 +00000 +, +01010 +00000 +01000 +00000 +00010 +00000 +00100 +00001 +00000 +10000 +00000 +00001 +00100 +00000 +00010 +00000 +, +01010 +00000 +00010 +10000 +00000 +10010 +00000 +10000 +00001 +00100 +00001 +00000 +00100 +00010 +01000 +00000 +, +01010 +01000 +00000 +01001 +00001 +10000 +00100 +01000 +, +01010 +00000 +00010 +00000 +00000 +00000 +10010 +00000 +10000 +00000 +00001 +00000 +00100 +00010 +10000 +00000 +, +10001 +00000 +00001 +00000 +10000 +00000 +00100 +01000 +00000 +00010 +00000 +01000 +00100 +00000 +10000 +00000 +, +10001 +00000 +00000 +00100 +00000 +00000 +01010 +00000 +00000 +00100 +00000 +00000 +01001 +00000 +00100 +00000 +, +10010 +10000 +10001 +00001 +01001 +00000 +00100 +00000 +, +10010 +10000 +10001 +00001 +01001 +00000 +00100 +00000 +, +01001 +01000 +01010 +00010 +10010 +00000 +00100 +00000 +, +01001 +00100 +01010 +00100 +10010 +10100 +10001 +00101 +, +10001 +00001 +01001 +01000 +01010 +00000 +00100 +00000 +, +10001 +00001 +01001 +01000 +01010 +00000 +00100 +00000 +, +01010 +00010 +10010 +10000 +10001 +00000 +00100 +00000 +, +01010 +00100 +10010 +00100 +10001 +01001 +01010 +10010 +, +20001 +00100 +30100 +20001 +00100 +30100 +20001 +00100 +, +30100 +20001 +00100 +30100 +20001 +30100 +20001 +30100 +, +10002 +00100 +00103 +10002 +00100 +00103 +10002 +00100 +, +00103 +00000 +00001 +01000 +00001 +00000 +10000 +00010 +10000 +00000 +00010 +01000 +00010 +01000 +00010 +00000 +, +01020 +00100 +00130 +01020 +00100 +00130 +01020 +00100 +, +00130 +01020 +00100 +00130 +01020 +00130 +01020 +00130 +, +02010 +00100 +03100 +02010 +00100 +03100 +02010 +00100 +, +03100 +00000 +01000 +00001 +01000 +00000 +00010 +10000 +00010 +00000 +10000 +00001 +10000 +00001 +10000 +00000 +, +00001 +00100 +00001 +00000 +01000 +00000 +00010 +00000 +10000 +00100 +10000 +00000 +00001 +00000 +10000 +00000 +, +00010 +00100 +00010 +00000 +10000 +00000 +00001 +00000 +01000 +00100 +01000 +00000 +00001 +00000 +10000 +00000 +, +00010 +01000 +00010 +00000 +10000 +00000 +00001 +00000 +01000 +00010 +01000 +00000 +00010 +00000 +10000 +00000 +, +10001 +00001 +00101 +10000 +10100 +00010 +00110 +01010 +, +01000 +00100 +01000 +00000 +00001 +00000 +10000 +00000 +00010 +00100 +00010 +00000 +01000 +00000 +00010 +00000 +, +10000 +00100 +10000 +00000 +00010 +00000 +01000 +00000 +00001 +00100 +00001 +00000 +01000 +00000 +00010 +00000 +, +10000 +00001 +10000 +00000 +00010 +00000 +01000 +00000 +00001 +10000 +00001 +00000 +10000 +00000 +00010 +00000 +, +01010 +01000 +01100 +00010 +00110 +10000 +10100 +10001 +, +00102 +00103 +20100 +30020 +, +02030 +00000 +03100 +00000 +00020 +00000 +10030 +10001 +, +20001 +30000 +10001 +10001 +10002 +00003 +02000 +03000 +, +00020 +00130 +02000 +03100 +, +02010 +00100 +03100 +01010 +01020 +00100 +00130 +10010 +, +20010 +00100 +30100 +10010 +10020 +00100 +00130 +10001 +, +10002 +00100 +00103 +10001 +20001 +00100 +30100 +01001 +, +01002 +00000 +00100 +00000 +00103 +00000 +01001 +00000 +02001 +00000 +00100 +00000 +03100 +00000 +00010 +01000 +, +00100 +10100 +10001 +00101 +, +20002 +00000 +00000 +30003 +10010 +00000 +01010 +00000 +, +02001 +03000 +02001 +03000 +02001 +03000 +01020 +00030 +, +20010 +30000 +20010 +30000 +01002 +00003 +01002 +00003 +, +00200 +00310 +00200 +00301 +00200 +01300 +00200 +10300 +, +00020 +00130 +02000 +03100 +00002 +00103 +20000 +30100 +, +01002 +00103 +00102 +10003 +20001 +30100 +20100 +30010 +, +10020 +00130 +00120 +01030 +02010 +03001 +01002 +00100 +, +20000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00003 +, +00200 +00000 +00000 +00000 +30000 +00000 +02000 +00300 +, +00002 +03000 +20000 +00003 +, +00002 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +30003 +20002 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +30003 +00000 +00000 +00000 +; + +//---------------pump-single - ---------------- +#NOTEDATA:; +#CHARTNAME:Vin.il; +#STEPSTYPE:pump-single; +#DESCRIPTION:; +#CHARTSTYLE:Pad; +#DIFFICULTY:Easy; +#METER:6; +#RADARVALUES:0.456,0.602,0.600,0.181,0.000,253.000,63.000,19.000,0.000,0.000,0.000,0.000,0.000,0.456,0.602,0.600,0.181,0.000,253.000,63.000,19.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Vin.il; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +,204.000000=0 +,206.000000=2 +,240.000000=1 +,248.000000=2 +,256.000000=1 +,303.500000=4 +; +#COMBOS:0.000000=1 +,206.000000=4 +,208.000000=1 +,240.000000=2 +,241.000000=4 +,242.000000=2 +,243.000000=4 +,244.000000=2 +,245.000000=4 +,246.000000=2 +,247.000000=4 +,248.000000=1 +,256.000000=2 +,257.000000=4 +,258.000000=2 +,259.000000=4 +,260.000000=2 +,261.000000=4 +,262.000000=2 +,263.000000=4 +,264.000000=2 +,265.000000=4 +,266.000000=2 +,267.000000=4 +,268.000000=2 +,269.000000=4 +,270.000000=2 +,271.000000=4 +,272.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +,248.000000=0.750000=0.500000=0 +,248.500000=1.000000=0.500000=0 +,249.000000=0.750000=0.500000=0 +,249.500000=1.000000=0.500000=0 +,250.000000=0.750000=0.500000=0 +,250.500000=1.000000=0.500000=0 +,251.000000=0.750000=0.500000=0 +,251.500000=1.000000=0.500000=0 +,252.000000=0.750000=0.500000=0 +,252.500000=1.000000=0.500000=0 +,253.000000=0.750000=0.500000=0 +,253.500000=1.000000=0.500000=0 +,254.000000=0.750000=0.500000=0 +,254.500000=1.000000=0.500000=0 +,255.000000=0.750000=0.500000=0 +,255.500000=1.000000=0.500000=0 +,303.500000=0.000000=12.500000=0 +; +#SCROLLS:0.000000=1.000000 +,76.000000=0.500000 +,80.000000=1.000000 +,108.000000=0.500000 +,112.000000=1.000000 +,204.000000=0.500000 +,208.000000=1.000000 +,272.000000=0.250000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +10000 +00000 +00000 +00001 +00000 +00000 +00000 +01000 +, +00000 +01001 +00000 +00000 +00000 +00001 +00000 +00000 +, +10000 +00000 +00000 +00001 +00000 +00000 +00000 +01000 +, +00000 +01001 +00000 +00000 +00000 +00001 +00000 +00000 +, +10000 +00000 +00000 +10010 +00000 +00000 +00000 +00001 +, +00000 +01001 +00000 +00000 +00000 +00100 +00000 +00000 +, +00001 +00000 +00000 +01001 +00000 +00000 +00000 +10000 +, +00000 +10010 +00000 +00000 +00000 +00100 +00000 +00000 +, +00001 +00100 +00000 +00001 +00000 +10000 +00000 +00001 +, +00000 +00101 +00000 +00000 +00000 +01001 +00000 +00000 +, +10000 +00100 +00000 +10000 +00000 +00001 +00000 +10000 +, +00000 +10100 +00000 +00000 +00000 +10010 +00000 +00000 +, +00010 +00100 +00000 +00010 +00000 +01000 +00000 +00010 +, +00000 +00110 +00000 +00000 +00000 +10010 +00000 +00000 +, +01000 +00100 +00000 +01000 +00000 +00010 +00000 +01000 +, +00001 +00000 +00000 +10001 +00000 +00000 +10000 +00010 +, +01000 +00001 +00000 +01000 +00000 +00010 +00000 +10000 +, +00001 +01000 +00000 +00001 +00000 +10000 +00000 +00010 +, +00100 +00001 +00000 +01000 +00000 +00010 +00000 +10000 +, +00100 +01000 +00000 +00001 +00000 +10000 +00000 +00010 +, +10000 +00010 +00000 +10000 +00000 +00001 +00000 +01000 +, +00010 +10000 +00000 +00010 +00000 +01000 +00000 +00001 +, +00100 +00010 +00000 +10000 +00000 +00001 +00000 +01000 +, +00010 +00000 +00000 +01010 +00000 +00000 +01000 +00001 +, +10000 +10100 +10000 +00001 +, +10000 +10100 +10000 +00001 +, +01000 +01100 +01000 +00001 +, +01000 +01100 +00010 +00110 +, +10000 +10100 +10000 +00001 +, +10000 +10100 +10000 +00001 +, +01000 +01100 +01000 +00001 +, +01000 +01100 +00010 +00110 +, +10000 +00100 +00000 +10000 +00100 +00000 +10000 +00100 +, +00000 +10000 +00100 +00000 +10000 +00001 +00100 +00000 +, +00001 +00100 +00000 +00001 +00100 +00000 +00001 +00100 +, +00001 +01001 +10000 +10010 +, +00010 +00100 +00000 +00010 +00100 +00000 +00010 +00100 +, +00000 +00010 +00100 +00000 +00010 +01000 +00100 +00000 +, +01000 +00100 +00000 +01000 +00100 +00000 +01000 +00100 +, +01000 +01001 +00010 +10010 +, +10000 +00001 +00100 +00000 +00001 +10000 +00100 +00000 +, +10000 +00001 +00100 +00000 +00001 +10000 +00100 +00000 +, +01000 +00010 +00100 +00000 +00010 +01000 +00100 +00000 +, +01010 +00001 +10000 +00001 +, +01000 +00010 +00100 +00000 +00010 +01000 +00100 +00000 +, +01000 +00010 +00100 +00000 +00010 +01000 +00100 +00000 +, +10000 +00001 +00100 +00000 +00001 +10000 +00100 +00000 +, +20002 +00000 +00000 +00000 +00000 +00000 +00000 +30003 +, +10001 +00101 +10001 +10100 +, +10001 +01001 +10001 +10010 +, +01010 +01010 +10001 +10001 +, +01010 +01010 +10001 +10001 +, +01010 +01100 +01010 +00110 +, +01010 +01001 +01010 +10010 +, +10001 +10001 +01010 +01010 +, +10001 +10001 +01010 +01010 +, +20001 +00000 +30002 +00000 +, +20003 +00000 +30020 +00000 +, +02030 +00000 +00000 +00000 +, +03020 +00000 +00000 +00000 +, +20030 +00000 +00000 +00000 +, +30002 +00000 +00000 +00000 +, +02003 +00000 +00000 +00000 +, +03020 +00000 +00000 +00000 +, +20030 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +30002 +00000 +00000 +02003 +, +03020 +00000 +00230 +00000 +, +00302 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +00000 +00000 +00000 +20000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +30003 +00000 +00000 +00000 +; + +//---------------dance-couple - Simple Chart---------------- +#NOTEDATA:; +#CHARTNAME:Small Tribe; +#STEPSTYPE:dance-couple; +#DESCRIPTION:Simple Chart; +#CHARTSTYLE:Pad; +#DIFFICULTY:Easy; +#METER:3; +#RADARVALUES:0.253,0.362,0.095,0.419,0.000,132.000,10.000,44.000,0.000,0.000,0.000,0.000,0.000,0.253,0.362,0.095,0.419,0.000,132.000,10.000,44.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Jason Felds; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +00000000 +00000000 +00000000 +00000000 +, +00000000 +00000000 +00000000 +00000000 +, +00000000 +00000000 +00000000 +00000000 +, +00000000 +00000000 +00000000 +00000000 +, +10000001 +00000000 +00000000 +00000000 +, +01000010 +00000000 +00000000 +00000000 +, +00100100 +00000000 +00000000 +00000000 +, +00011000 +00000000 +00000000 +00000000 +, +01000010 +00000000 +00000000 +00000000 +, +00100100 +00000000 +00000000 +00000000 +, +10000001 +00000000 +00000000 +00000000 +, +00011000 +00000000 +00000000 +00000000 +, +10000001 +00000000 +00100001 +00000000 +, +10000001 +00000000 +00100001 +00000000 +, +01001000 +00000000 +00011000 +00000000 +, +01001000 +00000000 +00011000 +00000000 +, +00100010 +00000000 +01000010 +00000000 +, +00100010 +00000000 +01000010 +00000000 +, +10000100 +00000000 +00010100 +00000000 +, +20020200 +00000000 +00000000 +30030300 +, +10000001 +00000000 +10000100 +00000000 +, +10000001 +00000000 +10000100 +00000000 +, +00010010 +00000000 +00011000 +00000000 +, +00010010 +00000000 +00011000 +00000000 +, +01000100 +00000000 +01000010 +00000000 +, +01000100 +00000000 +01000010 +00000000 +, +00100001 +00000000 +00101000 +00000000 +, +00202002 +00000000 +00000000 +00303003 +, +00000001 +00100000 +00000100 +00010000 +, +00001000 +10000000 +00000100 +00100000 +, +00000001 +01000000 +00000010 +00010000 +, +20000002 +32000203 +03200320 +00322030 +, +10033000 +00000100 +00100000 +00001000 +, +00010000 +00000001 +00100000 +00000100 +, +10000000 +00000010 +01000000 +00001000 +, +20000002 +30200023 +02300230 +03022300 +, +10033010 +00000000 +00011000 +00000000 +, +00100100 +00000000 +01000001 +00000000 +, +10000010 +00000000 +01000100 +00000000 +, +02202000 +00000000 +00000000 +03303000 +, +01000001 +00000000 +00011000 +00000000 +, +00100100 +00000000 +10000010 +00000000 +, +01000001 +00000000 +00100010 +00000000 +, +00020220 +00000000 +00000000 +00030330 +, +10000001 +00001000 +00010100 +00010010 +, +01000100 +00001000 +00100010 +00100100 +, +10000001 +00000010 +01000100 +01000010 +, +00200002 +00000000 +00000000 +00300003 +, +10000001 +00010000 +00101000 +01001000 +, +00100010 +00010000 +01000100 +00100100 +, +10000001 +01000000 +00100010 +01000010 +, +20000200 +00000000 +00000000 +30000300 +, +00022000 +00000000 +00000000 +20033002 +, +30200203 +00000000 +02300320 +00000000 +, +03022030 +00000000 +00000000 +00100100 +, +00233200 +00000000 +00000000 +00000000 +, +02300320 +00000000 +23000032 +00000000 +, +30200203 +00000000 +02300320 +00000000 +, +03022030 +00000000 +20033002 +00000000 +, +32000023 +00000000 +03200230 +00000000 +, +00322300 +00000000 +00000000 +00000000 +, +20033002 +00000000 +00000000 +00000000 +, +30200203 +00000000 +00000000 +01000010 +, +02300320 +00000000 +00000000 +00000000 +, +03022030 +00000000 +20033002 +00000000 +, +30200203 +00000000 +02300320 +00000000 +, +03022030 +00000000 +00233200 +00000000 +, +02300320 +00000000 +23000032 +00000000 +, +30011003 +00000000 +00000000 +00000000 +, +01100110 +00000000 +00000000 +00000000 +, +10011001 +00000000 +00000000 +10011001 +, +10011001 +00000000 +00000000 +00000000 +, +01100110 +00000000 +00000000 +00000000 +, +10011001 +00000000 +00000000 +00000000 +, +01100110 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +20022002 +, +00000000 +00000000 +00000000 +00000000 +, +30033003 +00000000 +00000000 +00000000 +; + +//---------------dance-threepanel - It's a 3 panel chart.---------------- +#NOTEDATA:; +#CHARTNAME:Simple; +#STEPSTYPE:dance-threepanel; +#DESCRIPTION:It's a 3 panel chart.; +#CHARTSTYLE:Pad; +#DIFFICULTY:Easy; +#METER:2; +#RADARVALUES:0.144,0.214,0.105,0.000,0.000,95.000,11.000,0.000,0.000,0.000,0.000,0.000,0.000,0.144,0.214,0.105,0.000,0.000,95.000,11.000,0.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Jason Felds; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +000 +000 +000 +000 +, +000 +000 +000 +000 +, +000 +000 +000 +000 +, +000 +000 +000 +000 +, +100 +000 +000 +000 +, +000 +000 +000 +000 +, +001 +000 +000 +000 +, +000 +000 +000 +000 +, +010 +000 +000 +000 +, +000 +000 +000 +000 +, +001 +000 +000 +000 +, +000 +000 +000 +000 +, +100 +000 +000 +000 +, +010 +000 +000 +000 +, +001 +000 +000 +000 +, +010 +000 +000 +000 +, +100 +000 +000 +000 +, +001 +000 +000 +000 +, +010 +000 +000 +000 +, +001 +000 +000 +000 +, +101 +000 +000 +000 +, +010 +000 +000 +000 +, +100 +000 +000 +000 +, +001 +000 +000 +000 +, +010 +000 +000 +000 +, +001 +000 +000 +000 +, +100 +000 +000 +000 +, +010 +000 +000 +000 +, +101 +000 +100 +000 +, +100 +000 +100 +000 +, +100 +000 +000 +000 +, +110 +000 +000 +000 +, +001 +000 +001 +000 +, +001 +000 +001 +000 +, +001 +000 +000 +000 +, +011 +000 +000 +000 +, +100 +000 +010 +000 +, +100 +000 +001 +000 +, +100 +000 +000 +000 +, +101 +000 +000 +000 +, +001 +000 +010 +000 +, +001 +000 +100 +000 +, +001 +000 +000 +000 +, +101 +000 +000 +000 +, +010 +000 +001 +000 +, +100 +000 +010 +000 +, +100 +000 +001 +000 +, +010 +000 +000 +000 +, +010 +000 +100 +000 +, +001 +000 +010 +000 +, +001 +000 +100 +000 +, +010 +000 +000 +000 +, +011 +000 +000 +000 +, +110 +000 +000 +000 +, +101 +000 +101 +000 +, +101 +000 +000 +000 +, +010 +000 +000 +001 +, +001 +000 +000 +100 +, +100 +000 +000 +010 +, +010 +000 +000 +000 +, +100 +000 +000 +001 +, +001 +000 +000 +010 +, +010 +000 +000 +001 +, +001 +000 +000 +100 +, +100 +000 +001 +000 +, +010 +000 +001 +000 +, +100 +000 +010 +000 +, +100 +000 +001 +000 +, +010 +000 +000 +000 +, +001 +000 +000 +000 +, +100 +000 +000 +010 +, +010 +000 +000 +000 +, +100 +000 +000 +000 +, +001 +000 +000 +000 +, +010 +000 +000 +000 +, +001 +000 +000 +000 +; + +//---------------pump-halfdouble - Community Skype Chart---------------- +#NOTEDATA:; +#CHARTNAME:Steam Pump; +#STEPSTYPE:pump-halfdouble; +#DESCRIPTION:Community Skype Chart; +#CHARTSTYLE:Pad; +#DIFFICULTY:Medium; +#METER:11; +#RADARVALUES:0.589,0.891,0.400,0.610,0.019,333.000,42.000,64.000,0.000,0.000,0.000,6.000,0.000,0.589,0.891,0.400,0.610,0.019,333.000,42.000,64.000,0.000,0.000,0.000,6.000,0.000; +#CREDIT:Jason Felds; +#OFFSET:-0.028000; +#BPMS:0.000000=180.000000 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=4 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +,16.000000=Verse 1A +,32.000000=Verse 1B +,48.000000=Verse 2A +,64.000000=Verse 2B +,80.000000=Verse 3A +,96.000000=Verse 3B +,112.000000=Verse 4A +,128.000000=Verse 4B +,144.000000=Verse 5A +,160.000000=Verse 5B +,176.000000=Verse 6A +,192.000000=Verse 6B +,208.000000=Verse 7A +,224.000000=Verse 7B +,240.000000=Verse 8A +,256.000000=Verse 8B +,272.000000=Verse 9A +,288.000000=Verse 9B +,304.000000=Fin +; +#ATTACKS:; +#NOTES: +// measure 0 +000000 +000000 +000000 +000000 +, // measure 1 +000000 +000000 +000000 +000000 +, // measure 2 +000000 +000000 +000000 +000000 +, // measure 3 +000000 +000000 +000000 +000000 +, // measure 4 +000100 +000000 +000000 +001000 +000000 +000000 +000010 +000000 +, // measure 5 +000100 +000000 +000000 +000001 +000000 +000000 +000010 +000000 +, // measure 6 +000100 +000000 +000000 +000001 +000000 +000000 +000100 +000000 +, // measure 7 +010000 +000000 +000000 +001000 +000000 +000000 +100000 +000000 +, // measure 8 +001000 +000000 +000000 +000010 +000000 +000000 +000001 +000000 +, // measure 9 +000100 +000000 +000000 +000010 +000000 +000000 +010000 +000000 +, // measure 10 +001000 +000000 +000000 +100000 +000000 +000000 +000100 +000000 +, // measure 11 +010000 +000000 +000000 +000010 +000000 +000000 +001000 +000000 +, // measure 12 +000100 +100000 +000000 +101000 +000000 +001000 +000000 +011000 +, // measure 13 +000000 +010000 +000000 +010010 +000000 +000010 +000100 +000001 +, // measure 14 +001000 +000010 +000000 +000110 +000000 +000100 +000000 +000101 +, // measure 15 +000000 +000001 +000000 +001001 +000000 +001000 +000100 +010000 +, // measure 16 +000010 +001000 +000000 +001100 +000000 +000100 +000000 +010100 +, // measure 17 +000000 +010000 +000000 +011000 +000000 +001000 +100000 +000100 +, // measure 18 +001000 +000010 +000000 +010000 +000000 +000001 +000000 +100000 +, // measure 19 +000010 +000000 +000000 +0100L0 +000000 +000000 +0L0010 +000000 +000000 +0100L0 +000000 +000000 +010010 +000000 +000000 +000000 +, // measure 20 +001000 +000001 +000000 +000101 +000000 +000100 +000000 +000110 +, // measure 21 +000000 +000010 +000000 +010010 +000000 +010000 +001000 +100000 +, // measure 22 +000100 +010000 +000000 +011000 +000000 +001000 +000000 +101000 +, // measure 23 +000000 +100000 +000000 +100100 +000000 +000100 +001000 +000010 +, // measure 24 +010000 +000100 +000000 +001100 +000000 +001000 +000000 +001010 +, // measure 25 +000000 +000010 +000000 +000110 +000000 +000100 +000001 +001000 +, // measure 26 +000100 +010000 +000000 +000010 +000000 +100000 +000000 +000001 +, // measure 27 +010000 +000000 +000000 +0L0010 +000000 +000000 +0100L0 +000000 +000000 +0L0010 +000000 +000000 +010010 +000000 +000000 +000000 +, // measure 28 +000100 +010000 +000010 +001000 +, // measure 29 +000001 +100000 +001000 +010000 +, // measure 30 +000100 +001000 +000010 +010000 +, // measure 31 +000001 +000010 +000100 +001000 +010000 +100000 +110000 +000000 +, // measure 32 +001000 +000010 +010000 +000100 +, // measure 33 +100000 +000001 +000100 +000010 +, // measure 34 +001000 +000100 +010000 +000010 +, // measure 35 +100000 +010000 +001000 +000100 +000010 +000001 +000011 +000000 +, // measure 36 +000002 +000100 +000003 +000002 +001000 +000003 +000002 +010000 +, // measure 37 +000003 +000002 +100000 +000003 +000001 +000100 +000010 +001000 +, // measure 38 +000100 +001000 +000000 +000010 +000100 +000000 +000001 +001000 +, // measure 39 +000010 +000100 +000001 +010000 +000100 +001000 +001010 +000000 +, // measure 40 +200000 +001000 +300000 +200000 +000100 +300000 +200000 +000010 +, // measure 41 +300000 +200000 +000001 +300000 +100000 +001000 +010000 +000100 +, // measure 42 +001000 +000100 +000000 +010000 +001000 +000000 +100000 +000100 +, // measure 43 +010000 +001000 +100000 +000010 +001000 +000100 +010100 +000000 +, // measure 44 +200000 +000000 +300200 +002300 +000000 +003020 +020030 +030002 +, // measure 45 +000023 +000000 +000230 +002300 +000000 +003020 +020030 +032000 +, // measure 46 +203000 +000000 +320000 +032000 +000000 +003200 +000320 +000032 +, // measure 47 +010003 +000010 +010000 +000010 +010000 +000010 +010010 +000000 +, // measure 48 +000002 +000000 +020003 +030020 +000000 +002030 +003200 +200300 +, // measure 49 +302000 +000000 +023000 +030020 +000000 +002030 +003200 +000320 +, // measure 50 +000032 +000000 +000203 +000320 +000000 +020030 +032000 +203000 +, // measure 51 +300100 +001000 +000100 +001000 +000100 +001000 +001100 +000000 +, // measure 52 +000002 +000000 +000000 +200003 +, // measure 53 +300200 +000000 +002300 +000000 +, // measure 54 +003010 +010000 +000010 +010000 +, // measure 55 +000100 +001000 +000100 +001000 +, // measure 56 +000020 +001030 +002000 +003100 +, // measure 57 +000200 +010300 +020000 +030001 +, // measure 58 +000002 +100003 +200000 +300100 +, // measure 59 +000200 +010300 +020000 +030010 +, // measure 60 +000020 +000000 +002030 +003200 +, // measure 61 +200300 +000000 +300020 +000230 +, // measure 62 +000301 +100000 +000010 +010000 +, // measure 63 +000100 +001000 +000010 +010000 +, // measure 64 +000001 +000011 +000010 +000110 +, // measure 65 +000100 +001100 +001000 +011000 +, // measure 66 +010000 +110000 +100000 +100001 +, // measure 67 +000100 +010100 +001000 +001010 +, // measure 68 +001100 +000000 +000000 +000100 +010000 +000000 +000000 +010000 +, // measure 69 +001000 +000000 +000000 +001000 +100000 +000000 +000000 +100000 +, // measure 70 +000001 +000000 +000000 +000001 +000100 +000000 +000010 +000000 +, // measure 71 +001000 +000100 +010000 +000010 +, // measure 72 +001100 +000000 +000000 +001000 +000010 +000000 +000000 +000010 +, // measure 73 +000100 +000000 +000000 +000100 +000001 +000000 +000000 +000001 +, // measure 74 +100000 +000000 +000000 +100000 +001000 +000000 +010000 +000000 +, // measure 75 +000100 +000000 +001000 +000000 +000010 +000000 +020000 +002000 +, // measure 76 +000000 +000000 +000000 +000000 +, // measure 77 +000000 +000000 +000000 +000000 +, // measure 78 +033000 +000000 +000000 +000000 +; diff --git a/Songs/StepMania 5/MechaTribe Assault/mechatribeassaultbg.png b/Songs/StepMania 5/MechaTribe Assault/mechatribeassaultbg.png new file mode 100644 index 0000000000..df4e8c9673 Binary files /dev/null and b/Songs/StepMania 5/MechaTribe Assault/mechatribeassaultbg.png differ diff --git a/Songs/StepMania 5/MechaTribe Assault/mechatribeassaultbn.png b/Songs/StepMania 5/MechaTribe Assault/mechatribeassaultbn.png new file mode 100644 index 0000000000..10d3c05490 Binary files /dev/null and b/Songs/StepMania 5/MechaTribe Assault/mechatribeassaultbn.png differ diff --git a/Songs/StepMania 5/MechaTribe Assault/wyde cd-tital.png b/Songs/StepMania 5/MechaTribe Assault/wyde cd-tital.png new file mode 100644 index 0000000000..3f19b252d2 Binary files /dev/null and b/Songs/StepMania 5/MechaTribe Assault/wyde cd-tital.png differ diff --git a/Songs/StepMania 5/Springtime/Kommisar - Springtime.mp3 b/Songs/StepMania 5/Springtime/Kommisar - Springtime.mp3 new file mode 100644 index 0000000000..d680255ec5 Binary files /dev/null and b/Songs/StepMania 5/Springtime/Kommisar - Springtime.mp3 differ diff --git a/Songs/StepMania 5/Springtime/Springtime.ssc b/Songs/StepMania 5/Springtime/Springtime.ssc new file mode 100644 index 0000000000..028d20ca71 --- /dev/null +++ b/Songs/StepMania 5/Springtime/Springtime.ssc @@ -0,0 +1,10608 @@ +#VERSION:0.73; +#TITLE:Springtime; +#SUBTITLE:; +#ARTIST:Kommisar; +#TITLETRANSLIT:; +#SUBTITLETRANSLIT:; +#ARTISTTRANSLIT:; +#GENRE:; +#ORIGIN:; +#CREDIT:; +#BANNER:springbn.png; +#BACKGROUND:spring.png; +#LYRICSPATH:; +#CDTITLE:; +#MUSIC:Kommisar - Springtime.mp3; +#OFFSET:-0.125000; +#SAMPLESTART:105.760086; +#SAMPLELENGTH:9.360000; +#SELECTABLE:YES; +#DISPLAYBPM:181.699997; +#BPMS:0.000000=181.699997 +,304.000000=90.850998 +,311.000000=181.701996 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#LABELS:0.000000=Song Start +; +#BGCHANGES:; +#KEYSOUNDS:; +#ATTACKS:; + +//---------------dance-single - Blank---------------- +#NOTEDATA:; +#STEPSTYPE:dance-single; +#DESCRIPTION:Blank; +#CHARTSTYLE:; +#DIFFICULTY:Challenge; +#METER:12; +#RADARVALUES:1.000,1.000,0.256,0.845,0.980,864.000,33.000,109.000,42.000,0.000,0.000,0.000,0.000,1.000,1.000,0.256,0.845,0.980,864.000,33.000,109.000,42.000,0.000,0.000,0.000,0.000; +#CREDIT:Blank; +#OFFSET:-0.125000; +#BPMS:0.000000=181.699997 +,304.000000=90.850998 +,311.000000=181.701996 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +; +#ATTACKS: +; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0010 +0000 +0010 +1000 +0100 +0000 +1000 +0010 +0100 +0001 +0000 +0000 +0101 +0000 +0101 +0000 +, +0010 +0000 +1000 +0100 +0010 +0000 +0001 +0010 +0100 +1000 +0000 +0000 +0110 +0000 +0110 +0000 +, +0001 +0000 +1000 +0100 +1000 +0000 +0010 +0100 +0001 +0010 +0000 +0000 +1001 +0000 +1001 +0000 +, +0010 +0000 +1000 +0010 +1000 +0000 +0001 +0000 +1100 +0000 +1100 +0000 +0000 +0003 +0000 +0300 +, +0010 +0000 +1000 +0001 +0010 +0000 +0001 +1000 +0010 +0100 +0000 +0000 +0011 +0000 +0011 +0000 +, +1000 +0000 +0010 +0100 +0001 +0000 +0010 +0100 +1000 +0010 +0000 +0000 +1010 +0000 +1010 +0000 +, +0001 +0000 +0100 +0010 +1000 +0000 +0100 +0010 +0001 +1000 +0000 +0000 +0011 +0000 +0011 +0000 +, +1000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +1000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0001 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +1000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0010 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +1100 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +1100 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +1000 +0100 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0100 +2000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +3001 +0100 +0100 +0010 +0000 +0010 +1000 +0000 +, +0001 +0000 +0010 +0000 +0100 +0000 +1000 +0001 +0100 +0000 +0020 +0030 +2000 +3000 +2000 +3000 +, +0010 +0100 +0100 +0001 +0000 +0001 +1000 +0000 +, +0100 +0000 +0010 +0000 +0001 +0000 +1000 +0010 +0100 +0000 +0002 +0003 +0020 +0030 +0020 +0030 +, +0001 +1000 +1000 +0100 +0000 +0100 +1000 +0000 +, +0010 +0000 +0100 +0000 +0001 +0000 +0010 +0100 +1000 +0000 +0020 +0030 +0200 +0300 +0200 +0300 +, +0001 +0100 +0100 +0010 +0000 +0010 +1000 +0000 +, +1000 +0000 +0100 +0000 +0010 +0000 +0100 +0000 +1000 +0001 +0010 +0000 +0001 +0010 +0100 +0000 +, +1000 +0000 +0100 +1000 +0100 +0000 +0100 +1000 +0001 +1000 +0100 +0000 +1000 +0000 +0010 +0000 +, +0100 +0000 +0001 +0010 +0100 +0000 +1000 +0010 +0100 +0010 +2000 +3000 +0002 +0003 +0002 +0003 +, +0100 +0000 +0010 +1000 +0010 +0000 +1000 +0001 +0010 +0100 +1000 +0000 +0010 +0000 +0100 +0000 +, +0001 +0000 +1000 +0100 +0010 +0000 +0001 +0010 +0001 +1000 +0200 +0300 +2000 +3000 +2000 +3000 +, +0010 +0000 +0100 +0001 +0100 +0000 +0010 +1000 +0100 +0010 +0001 +0000 +1000 +0000 +0010 +0000 +, +0100 +0000 +0010 +1000 +0100 +0000 +1000 +0100 +0010 +0001 +2000 +3000 +0020 +0030 +0020 +0030 +, +0100 +0000 +0001 +0010 +0100 +0000 +1000 +0010 +0100 +0001 +0010 +0000 +0001 +0000 +1000 +0000 +, +0001 +0010 +0001 +0010 +0001 +0010 +0001 +0010 +0001 +1000 +0100 +1000 +0000 +0300 +0000 +3000 +, +0010 +0000 +1000 +0000 +0100 +0000 +0020 +0000 +0001 +0000 +0000 +0000 +0130 +0000 +0100 +1000 +, +0020 +0000 +0030 +0200 +0000 +0300 +0001 +0000 +2000 +0000 +0000 +0000 +0001 +0000 +0000 +0000 +, +0010 +0000 +3000 +0000 +1000 +0000 +0100 +0000 +0010 +0100 +1000 +0001 +0010 +0001 +1000 +0100 +, +0020 +0000 +0030 +0000 +0001 +0000 +1000 +0000 +0200 +0000 +0310 +0000 +0001 +3000 +0010 +0300 +, +0010 +0000 +1000 +0000 +0100 +0000 +0020 +0000 +0001 +0000 +0000 +0000 +0130 +0000 +0100 +1000 +, +0020 +0000 +0030 +2000 +0000 +3000 +0010 +0000 +2000 +0000 +0000 +0000 +0001 +0000 +0000 +0000 +, +0010 +0000 +3000 +0000 +1000 +0000 +0100 +0000 +0010 +0100 +1000 +0001 +0100 +0001 +1000 +0010 +, +0100 +0001 +0100 +0001 +0100 +0001 +0100 +0001 +1000 +0010 +1000 +0010 +0000 +3000 +0000 +0300 +, +0010 +1000 +1100 +0010 +0000 +0100 +1001 +0010 +, +0100 +1000 +0101 +0010 +0001 +0000 +1100 +0000 +, +1000 +0100 +0M11 +0100 +0000 +1000 +0110 +1000 +, +0001 +0010 +0001 +0100 +0010 +1000 +0001 +0100 +0010 +1000 +0100 +1000 +0010 +0100 +0001 +0010 +, +0001 +0100 +0011 +1000 +0000 +0001 +0110 +1000 +, +0001 +0010 +0101 +0010 +0001 +0000 +1100 +0000 +, +0010 +0001 +110M +0001 +0000 +0100 +1001 +0010 +, +010M +1000 +0010 +0100 +M001 +0010 +0100 +1000 +001M +0100 +0010 +1000 +0M01 +0010 +0001 +1000 +, +0010 +0000 +1000 +0000 +0100 +0000 +0020 +0000 +0001 +0000 +0000 +0000 +0130 +0000 +0100 +1000 +, +0020 +0000 +0030 +0200 +0000 +0300 +0001 +0000 +2000 +0000 +0000 +0000 +0001 +0000 +0000 +0000 +, +0010 +0000 +3000 +0000 +1000 +0000 +0100 +0000 +0010 +0100 +1000 +0001 +0010 +0001 +1000 +0200 +, +0000 +0000 +0300 +0000 +1000 +0000 +0001 +0000 +0020 +0000 +0130 +0000 +1000 +0003 +0100 +0030 +, +0100 +0000 +0001 +0000 +0010 +0000 +0200 +0000 +1000 +0000 +0000 +0000 +0310 +0000 +0010 +0001 +, +0200 +0000 +0300 +0002 +0000 +0003 +0100 +0000 +0002 +0000 +0000 +0000 +1000 +0000 +0000 +0000 +, +0100 +0000 +0003 +0000 +0001 +0000 +0010 +0000 +0100 +0010 +0001 +1000 +0010 +1000 +0001 +0100 +, +0010 +1000 +0010 +1000 +0010 +1000 +0010 +1000 +0001 +0100 +0001 +0100 +0000 +0003 +0000 +0030 +, +0001 +0000 +1000 +0100 +1000 +0000 +0001 +0100 +0001 +0000 +0100 +0010 +0100 +0000 +0001 +1000 +, +0001 +0000 +0100 +0001 +0100 +0000 +0010 +1000 +0010 +0000 +1000 +0100 +1000 +0000 +0001 +1000 +, +0001 +0000 +0010 +0001 +0010 +0000 +0001 +0100 +0001 +0000 +1000 +0010 +1000 +0000 +0010 +0100 +, +0010 +0000 +0100 +0001 +0100 +0000 +0010 +0100 +0010 +0000 +1000 +0100 +1000 +0000 +0001 +0010 +, +0001 +0000 +1000 +0100 +0010 +0000 +0001 +0010 +0100 +0000 +0010 +0001 +0100 +0000 +0010 +1000 +, +0100 +0000 +0010 +0001 +1000 +0000 +0001 +0010 +0100 +0000 +1000 +0100 +0010 +0000 +0001 +0100 +, +0010 +0000 +1000 +0001 +0010 +0000 +0001 +0100 +0010 +0000 +1000 +0100 +0010 +0000 +0001 +0010 +, +0100 +0000 +0001 +0100 +0010 +0000 +0100 +0010 +1000 +0000 +0001 +0010 +0100 +0000 +1000 +0100 +, +0020 +1030 +0100 +1000 +0020 +0130 +0001 +0100 +0020 +1030 +0001 +1000 +0020 +0130 +0001 +0100 +, +0020 +1030 +0100 +1000 +0020 +1030 +0001 +1000 +0020 +0130 +0001 +0100 +0020 +1030 +0100 +1000 +, +0020 +0130 +0001 +0100 +0020 +1030 +0001 +1000 +0020 +0130 +0001 +0100 +0020 +1030 +0001 +1000 +, +0020 +0130 +0001 +0100 +0020 +1030 +0100 +1000 +0020 +0130 +0001 +0100 +0020 +1030 +0100 +1000 +, +0020 +0130 +0001 +0100 +0020 +1030 +0001 +0100 +0020 +0130 +0001 +0100 +0020 +1030 +0100 +1000 +, +0020 +0130 +0001 +1000 +0020 +0130 +0001 +0100 +0020 +1030 +0001 +1000 +0020 +0130 +0001 +0100 +, +0020 +1030 +0100 +1000 +0020 +0130 +0001 +1000 +0020 +0130 +0001 +0100 +0020 +1030 +0001 +0100 +, +0020 +1030 +0100 +1000 +0020 +0130 +0001 +0100 +0020 +1030 +0100 +1000 +0020 +0130 +0001 +0100 +, +0010 +0100 +0100 +0010 +0000 +0010 +1000 +0000 +, +0001 +0000 +0010 +0000 +0100 +0000 +1000 +0001 +0100 +0000 +0020 +0030 +2000 +3000 +2000 +3000 +, +0010 +0100 +0100 +0001 +0000 +0001 +1000 +0000 +, +0100 +0000 +0010 +0000 +0001 +0000 +1000 +0010 +0100 +0000 +0002 +0003 +0020 +0030 +0020 +0030 +, +0001 +1000 +1000 +0100 +0000 +0100 +1000 +0000 +, +0010 +0000 +0100 +0000 +0001 +0000 +0010 +0100 +1000 +0000 +0020 +0030 +0200 +0300 +0200 +0300 +, +0001 +0100 +0100 +0010 +0000 +0010 +1000 +0000 +, +0101 +0000 +0101 +0000 +0101 +0000 +0101 +0000 +00M1 +1000 +010M +0010 +0M01 +1000 +01M0 +1000 +, +010M +0000 +1000 +0000 +01M0 +0000 +0002 +0000 +M000 +0000 +0000 +0000 +00M3 +0000 +0100 +1000 +00M1 +0000 +0000 +0010 +M000 +0000 +0100 +0000 +002M +0000 +0000 +0000 +M000 +0000 +0000 +0000 +, +0M30 +0000 +0000 +0000 +01M0 +0000 +1000 +0000 +010M +0010 +0001 +0010 +M001 +0100 +0010 +2000 +000M +0000 +0000 +3000 +0100 +0000 +0010 +0000 +0M00 +0000 +1003 +0000 +0001 +0000 +1000 +0000 +, +0M00 +0031 +M000 +0310 +1000 +0000 +0001 +0000 +0010 +0000 +0200 +0000 +1000 +0000 +0000 +0000 +, +0310 +0000 +0010 +0001 +0200 +0000 +0300 +0020 +0000 +0030 +1000 +0000 +0002 +0000 +0000 +0000 +, +1000 +0000 +0000 +0000 +0100 +0000 +0003 +0000 +0001 +0000 +0010 +0000 +0100 +0010 +0001 +1000 +, +0100 +1000 +0001 +0010 +0200 +0000 +0300 +0000 +1000 +0000 +0001 +0000 +0020 +0000 +0130 +0000 +, +1000 +0003 +0100 +0030 +0100 +0000 +0001 +0000 +0010 +0000 +0200 +0000 +1000 +0000 +0000 +0000 +, +0310 +0000 +0010 +0001 +0200 +0000 +0300 +0002 +0000 +0003 +0100 +0000 +0002 +0000 +0000 +0000 +, +1000 +0000 +0000 +0000 +0100 +0000 +0003 +0000 +0001 +0000 +0010 +0000 +0100 +0010 +0001 +1000 +, +0010 +0000 +1000 +0000 +0001 +0000 +0100 +0000 +0001 +0000 +0010 +0000 +0100 +0000 +1000 +0000 +0010 +0000 +0000 +0000 +0100 +0000 +0000 +0000 +0001 +0000 +0010 +0000 +0000 +0003 +0100 +0000 +, +0000 +0030 +1000 +0000 +0000 +0300 +1000 +0000 +0010 +0000 +0000 +0000 +1000 +0000 +0000 +0000 +0100 +0000 +0000 +0000 +0020 +0000 +0000 +0000 +0001 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0130 +0000 +0100 +1000 +0020 +0000 +0030 +0200 +0000 +0300 +0001 +0000 +2000 +0000 +0000 +0000 +, +0001 +3000 +0020 +0000 +1000 +0030 +0200 +0300 +, +0002 +0003 +2000 +0000 +0010 +3010 +0200 +0001 +, +0001 +0301 +2000 +0000 +0001 +0000 +0010 +3000 +, +0002 +0003 +0020 +0000 +0001 +0000 +0100 +0030 +, +0100 +1000 +0002 +0003 +2000 +0000 +0010 +0000 +, +0001 +0000 +3000 +0000 +0010 +0100 +0010 +0100 +0010 +0100 +0010 +0100 +0001 +1000 +0001 +1000 +, +0000 +0003 +0100 +0000 +02M2 +0000 +M000 +0000 +00M0 +0000 +M000 +0000 +00M0 +0000 +M000 +0000 +, +00M0 +M000 +00M0 +M000 +00M0 +M300 +00M0 +0M00 +, +00M0 +0M03 +0000 +0000 +0000 +0000 +0000 +0000 +; + +//---------------dance-single - Kommisar---------------- +#NOTEDATA:; +#STEPSTYPE:dance-single; +#DESCRIPTION:Kommisar; +#CHARTSTYLE:; +#DIFFICULTY:Hard; +#METER:9; +#RADARVALUES:0.825,0.969,0.000,0.542,0.395,675.000,0.000,70.000,0.000,0.000,2.000,0.000,0.000,0.825,0.969,0.000,0.542,0.395,675.000,0.000,70.000,0.000,0.000,2.000,0.000,0.000; +#CREDIT:Kommisar; +#OFFSET:-0.125000; +#BPMS:0.000000=181.699997 +,304.000000=90.850998 +,311.000000=181.701996 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +; +#ATTACKS: +; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0001 +0000 +1000 +0100 +1000 +0000 +0001 +0000 +0010 +0000 +0100 +0000 +1000 +0000 +0001 +0000 +, +0100 +0000 +0010 +1000 +0010 +0000 +1000 +0000 +0100 +0000 +0010 +0000 +0001 +0000 +1000 +0000 +, +0001 +0000 +0100 +0010 +0100 +0000 +0001 +0000 +1000 +0000 +0010 +0000 +1000 +0000 +0100 +0000 +, +0010 +0000 +0001 +0100 +0001 +0000 +1000 +0000 +0100 +0000 +0100 +0000 +0020 +0030 +0002 +0003 +, +1000 +0000 +0010 +0100 +0010 +0000 +1000 +0000 +0001 +0000 +0010 +0000 +0100 +0000 +1000 +0000 +, +0001 +0000 +1000 +0010 +1000 +0000 +0001 +0000 +0100 +0000 +0010 +0000 +1000 +0000 +0100 +0000 +, +0010 +0000 +0001 +0100 +0001 +0000 +1000 +0000 +0010 +0000 +1000 +0000 +0100 +0000 +0010 +0000 +, +0001 +0000 +0001 +0000 +0100 +0000 +0100 +0000 +0010 +0000 +0010 +0000 +2000 +3000 +0002 +0003 +, +1000 +0010 +0010 +0100 +0000 +0001 +0010 +0000 +, +0100 +0000 +1000 +0000 +1000 +0000 +0001 +0010 +0001 +0000 +1000 +0000 +0100 +0000 +0100 +0000 +, +0010 +0001 +0001 +0100 +0000 +0010 +1000 +0000 +, +0100 +0000 +0010 +0000 +0100 +0000 +1000 +0001 +1000 +0000 +0010 +0000 +0200 +0300 +0002 +0003 +, +1000 +0001 +0001 +0010 +0000 +0001 +1000 +0000 +, +0010 +0000 +1000 +0000 +1000 +0000 +0001 +0100 +0001 +0000 +1000 +0000 +0010 +0000 +0010 +0000 +, +0100 +0001 +1000 +0100 +0000 +0010 +0001 +0000 +, +1000 +0000 +0010 +0000 +0100 +0000 +0001 +0000 +1000 +0100 +1000 +0000 +0001 +0100 +0001 +0000 +, +1000 +0010 +0010 +0100 +0000 +0001 +0010 +0000 +, +0100 +0000 +1000 +0000 +1000 +0000 +0001 +0010 +0001 +0000 +1000 +0000 +0100 +0000 +0100 +0000 +, +0010 +0001 +0001 +0100 +0000 +0010 +1000 +0000 +, +0100 +0000 +0010 +0000 +0100 +0000 +1000 +0001 +1000 +0000 +0010 +0000 +0200 +0300 +0002 +0003 +, +1000 +0001 +0001 +0010 +0000 +0001 +1000 +0000 +, +0010 +0000 +1000 +0000 +1000 +0000 +0001 +0100 +0001 +0000 +1000 +0000 +0010 +0000 +0010 +0000 +, +1000 +0100 +0010 +0001 +0000 +1000 +0010 +0000 +, +0100 +0001 +0100 +0000 +0001 +0100 +0001 +0000 +1000 +0001 +1000 +0000 +0002 +0003 +2000 +3000 +, +0010 +0000 +0100 +0000 +0001 +0000 +2000 +0000 +0000 +0000 +0000 +3000 +0000 +0000 +0010 +0100 +, +0002 +0000 +0003 +2000 +0000 +3000 +0100 +0000 +0020 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0030 +0001 +0000 +0100 +0000 +0001 +1000 +0001 +0000 +1000 +0100 +1000 +0020 +, +0000 +0000 +0030 +0000 +0100 +0000 +0001 +0000 +2000 +0000 +0000 +0000 +3020 +0030 +0200 +0300 +, +0001 +0000 +1000 +0000 +0100 +0000 +0020 +0000 +0000 +0000 +0000 +0000 +0030 +0000 +0001 +0010 +, +0002 +0000 +0003 +0200 +0000 +0300 +0020 +0000 +2030 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +3000 +0000 +0001 +0000 +0100 +0000 +0010 +1000 +0010 +0000 +1000 +0100 +1000 +0000 +, +0010 +0100 +0010 +0000 +0100 +0010 +0100 +0000 +0001 +1000 +0001 +0000 +2000 +3000 +0020 +0030 +, +1000 +0100 +0100 +0010 +0000 +0001 +0100 +0010 +, +1000 +0001 +0001 +0100 +0000 +0001 +1000 +0100 +, +1000 +0010 +0010 +1000 +0000 +0001 +0010 +0100 +, +1000 +0001 +1000 +0000 +0001 +0010 +0001 +0000 +1000 +0100 +1000 +0000 +0001 +0010 +0100 +0000 +, +1000 +0100 +0100 +0010 +0000 +0001 +1000 +0100 +, +1000 +0001 +0010 +0100 +0000 +1000 +0010 +1000 +, +0001 +0100 +0100 +0010 +0000 +1000 +0001 +0010 +, +0100 +1000 +0100 +0000 +1000 +0100 +1000 +0000 +0001 +0000 +1000 +0001 +1000 +0001 +1000 +0000 +, +0010 +0000 +0100 +0000 +0001 +0000 +2000 +0000 +0000 +0000 +0000 +3000 +0000 +0000 +0010 +0100 +, +0002 +0000 +0003 +2000 +0000 +3000 +0100 +0000 +0020 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0030 +0001 +0000 +0100 +0000 +0001 +1000 +0001 +0000 +1000 +0100 +1000 +0020 +, +0000 +0000 +0030 +0000 +0100 +0000 +0001 +0000 +2000 +0000 +0000 +0000 +3020 +0030 +0200 +0300 +, +0001 +0000 +1000 +0000 +0100 +0000 +0020 +0000 +0000 +0000 +0000 +0000 +0030 +0000 +0001 +0010 +, +0002 +0000 +0003 +0200 +0000 +0300 +0020 +0000 +2030 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +3000 +0000 +0001 +0000 +0100 +0000 +0010 +1000 +0010 +0000 +1000 +0100 +1000 +0000 +, +0010 +0100 +0010 +0000 +0100 +0010 +0100 +0000 +0001 +1000 +0001 +0000 +2000 +3000 +0020 +0030 +, +1000 +0000 +0001 +0000 +0010 +0000 +0100 +0100 +, +1000 +0000 +0010 +0000 +1000 +0000 +0001 +0001 +, +0100 +0000 +0010 +0000 +1000 +0000 +0100 +0100 +, +0010 +0000 +0001 +0000 +0100 +0000 +0010 +0010 +, +1000 +0000 +0010 +0000 +0100 +0000 +0010 +0010 +, +1000 +0000 +0100 +0000 +0010 +0000 +0001 +0001 +, +1000 +0000 +0010 +0000 +1000 +0000 +0100 +0100 +, +0010 +0000 +0001 +0000 +0100 +0000 +0010 +0010 +, +1000 +0000 +0001 +0010 +0001 +0000 +1000 +0000 +0100 +0000 +0010 +0001 +0010 +0000 +0001 +0000 +, +1000 +0000 +0010 +0100 +0010 +0000 +1000 +0000 +0001 +0000 +1000 +0100 +0010 +0000 +0001 +0000 +, +1000 +0000 +0001 +0100 +0001 +0000 +1000 +0000 +0100 +0000 +0010 +0001 +0010 +0000 +0001 +0000 +, +1000 +0000 +0001 +0010 +0100 +0000 +1000 +0000 +0001 +0000 +0100 +0010 +0100 +0000 +0001 +0000 +, +1000 +0000 +0010 +0100 +0010 +0000 +1000 +0000 +0001 +0000 +1000 +0100 +1000 +0000 +0001 +0000 +, +0010 +0000 +0100 +1000 +0100 +0000 +1000 +0000 +0001 +0000 +1000 +0010 +1000 +0000 +0001 +0000 +, +1000 +0000 +0100 +0010 +0001 +0000 +1000 +0000 +0010 +0000 +0100 +0001 +0100 +0000 +0001 +0000 +, +1000 +0000 +0010 +0100 +0010 +0000 +1000 +0000 +0001 +0000 +0100 +0001 +0100 +0000 +0001 +0000 +, +1000 +0010 +0010 +0100 +0000 +0001 +0010 +0000 +, +0100 +0000 +1000 +0000 +1000 +0000 +0001 +0010 +0001 +0000 +1000 +0000 +0100 +0000 +0100 +0000 +, +0010 +0001 +0001 +0100 +0000 +0010 +1000 +0000 +, +0100 +0000 +0010 +0000 +0100 +0000 +1000 +0001 +1000 +0000 +0010 +0000 +0100 +0000 +0001 +0000 +, +1000 +0001 +0001 +0010 +0000 +0001 +1000 +0000 +, +0010 +0000 +1000 +0000 +1000 +0000 +0001 +0100 +0001 +0000 +1000 +0000 +0010 +0000 +0010 +0000 +, +0100 +0001 +1000 +0100 +0000 +0010 +0001 +0000 +, +1000 +0000 +1000 +0000 +1000 +0000 +1000 +0000 +0001 +0100 +0001 +0000 +1000 +0001 +1000 +0000 +, +0001 +0000 +0010 +0000 +0100 +0000 +2000 +0000 +0000 +0000 +0000 +0000 +3000 +0000 +0001 +0100 +0002 +0000 +0003 +0010 +0000 +0000 +0100 +0000 +2000 +0000 +0000 +0000 +0000 +0000 +0000 +3000 +, +0000 +0000 +0000 +0000 +0001 +0000 +0100 +0000 +0001 +1000 +0001 +0000 +1000 +0010 +1000 +0200 +0000 +0000 +0300 +0000 +0010 +0000 +0001 +0000 +4000 +0000 +0000 +0000 +0000 +0000 +0000 +3000 +, +0040 +0000 +0000 +0000 +0000 +0000 +0000 +0030 +0100 +0000 +0000 +0000 +0010 +0000 +0000 +0000 +1000 +0000 +0000 +0000 +0002 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0003 +0000 +, +0000 +0000 +0100 +0010 +2000 +0000 +3000 +0002 +0000 +0003 +0010 +0000 +0200 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0300 +1000 +0000 +0010 +0000 +1000 +0001 +1000 +0000 +, +0001 +0010 +0001 +0200 +0000 +0000 +0300 +0000 +0010 +0000 +1000 +0000 +0002 +0000 +0000 +0000 +, +0203 +0300 +0020 +0030 +1000 +0000 +0001 +0000 +0010 +0000 +0200 +0000 +0000 +0000 +0000 +0000 +, +0300 +0000 +1000 +0100 +2000 +0000 +3000 +0020 +0000 +0030 +0200 +0000 +0302 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +0000 +0000 +0003 +0000 +1000 +0000 +0010 +0000 +0100 +0001 +0100 +0000 +, +0001 +0010 +0001 +0000 +1000 +0000 +0100 +0000 +1000 +0000 +0001 +0000 +0100 +0000 +0001 +1000 +, +0001 +1000 +0020 +0000 +1030 +0000 +0100 +0000 +0010 +0000 +0002 +0000 +0000 +0000 +0000 +0000 +, +0000 +0003 +0100 +0010 +0200 +0000 +0300 +0002 +0000 +0003 +1000 +0000 +0020 +0000 +0000 +0000 +, +0000 +0000 +0000 +0030 +2000 +0000 +0000 +0000 +0000 +0000 +0000 +3000 +0200 +0000 +0300 +0000 +, +0020 +0000 +0000 +0030 +0002 +0000 +0000 +0000 +0000 +0000 +0000 +0003 +2000 +0000 +0000 +0000 +, +0000 +0000 +0000 +3000 +0010 +0000 +0100 +0000 +0001 +0000 +1000 +0000 +0100 +0000 +0010 +0000 +, +0001 +0000 +0010 +0100 +1000 +0000 +0001 +0000 +1000 +0000 +0010 +0000 +1000 +0000 +0001 +0000 +, +0100 +0000 +0001 +0010 +0100 +0000 +1000 +0000 +0010 +0000 +1000 +0000 +0100 +0000 +0010 +0000 +, +0001 +0000 +1000 +0000 +0010 +0100 +0010 +0000 +0100 +0010 +0100 +0000 +0001 +1000 +0001 +0000 +, +2000 +3000 +0002 +0003 +0200 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0300 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +; + +//---------------dance-single - Kommisar---------------- +#NOTEDATA:; +#STEPSTYPE:dance-single; +#DESCRIPTION:Kommisar; +#CHARTSTYLE:; +#DIFFICULTY:Beginner; +#METER:1; +#RADARVALUES:0.234,0.219,0.008,0.000,0.000,210.000,1.000,0.000,0.000,0.000,0.000,0.000,0.000,0.234,0.219,0.008,0.000,0.000,210.000,1.000,0.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Kommisar; +#OFFSET:-0.125000; +#BPMS:0.000000=181.699997 +,304.000000=90.850998 +,311.000000=181.701996 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +; +#ATTACKS: +; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +0100 +0000 +, +0001 +0000 +0010 +0000 +, +0001 +0000 +1000 +0000 +, +0100 +0000 +1000 +0000 +, +0010 +0000 +0100 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0010 +0100 +0100 +, +0001 +0000 +1000 +0000 +, +0100 +0000 +0010 +0000 +, +0001 +0000 +0100 +0000 +, +0001 +0000 +1000 +0000 +, +0100 +0000 +1000 +0000 +, +0010 +0000 +0100 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +0100 +0100 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +1000 +0000 +, +0100 +0000 +0010 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +1000 +0000 +, +0001 +0000 +1000 +0000 +, +0100 +0000 +0010 +0000 +, +0001 +0001 +1000 +1000 +, +0001 +0000 +0100 +0000 +, +0001 +0000 +1000 +0000 +, +0100 +0000 +1000 +0000 +, +0010 +0000 +0100 +0000 +, +0010 +0000 +0100 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +1000 +0000 +, +0001 +0001 +1000 +1000 +, +0010 +0000 +0100 +0000 +, +0001 +0000 +1000 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +0100 +0000 +, +0010 +0000 +1000 +0000 +, +0001 +0000 +0100 +0000 +, +0001 +0000 +0010 +0000 +, +0100 +0100 +1000 +1000 +, +0001 +0000 +0100 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +1000 +0000 +, +0100 +0000 +0010 +0000 +, +0001 +0000 +1000 +0000 +, +0001 +0000 +0100 +0000 +, +0001 +0000 +0010 +0000 +, +0100 +0100 +1000 +1000 +, +0001 +0000 +0010 +0000 +, +0001 +0000 +1000 +0000 +, +0000 +0010 +1000 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +1000 +0000 +, +0001 +0000 +0100 +0000 +, +0001 +0000 +0010 +0000 +, +0100 +0000 +1000 +0000 +, +0001 +0001 +0001 +0000 +, +1000 +1000 +1000 +0000 +, +0010 +0010 +0010 +0000 +, +0100 +0100 +0100 +0000 +, +0001 +0001 +0001 +0000 +, +1000 +1000 +1000 +0000 +, +0010 +0010 +0010 +0000 +, +0100 +0100 +0100 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +0100 +0000 +, +0001 +0000 +1000 +0000 +, +0010 +0000 +1000 +0000 +, +0100 +0000 +1000 +0000 +, +0010 +0000 +1000 +0000 +, +0001 +0000 +0100 +0000 +, +0001 +0001 +1000 +1000 +, +0001 +0000 +1000 +0000 +, +0100 +0000 +0010 +0001 +, +0001 +1000 +0000 +0010 +, +0000 +1000 +0000 +0001 +, +0000 +0010 +0000 +0001 +, +0000 +1000 +1000 +0100 +, +0100 +1000 +0000 +0001 +, +0000 +1000 +0000 +0001 +, +0000 +0100 +0000 +0001 +, +0000 +1000 +1000 +0001 +, +0001 +1000 +0000 +0010 +, +0000 +0100 +0000 +0001 +, +0000 +0100 +0000 +0010 +, +0000 +1000 +0000 +0001 +, +0000 +1000 +0000 +0001 +, +0000 +0100 +0000 +0001 +, +0000 +1000 +0000 +0010 +, +0000 +1000 +1000 +0001 +, +0001 +1001 +0000 +0000 +; + +//---------------dance-single - Kommisar---------------- +#NOTEDATA:; +#STEPSTYPE:dance-single; +#DESCRIPTION:Kommisar; +#CHARTSTYLE:; +#DIFFICULTY:Medium; +#METER:6; +#RADARVALUES:0.648,0.634,0.000,0.426,0.031,530.000,0.000,55.000,0.000,0.000,6.000,0.000,0.000,0.648,0.634,0.000,0.426,0.031,530.000,0.000,55.000,0.000,0.000,6.000,0.000,0.000; +#CREDIT:Kommisar; +#OFFSET:-0.125000; +#BPMS:0.000000=181.699997 +,304.000000=90.850998 +,311.000000=181.701996 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +; +#ATTACKS: +; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0001 +0000 +1000 +0000 +0010 +0100 +0010 +0000 +, +1000 +0000 +0001 +0000 +0010 +0100 +1000 +0000 +, +0010 +0000 +1000 +0000 +0001 +1000 +0001 +0000 +, +1000 +0000 +0001 +0000 +1000 +0001 +1000 +0001 +, +0100 +0000 +0010 +0000 +1000 +0001 +1000 +0000 +, +0001 +0000 +0100 +0000 +0001 +1000 +0100 +0000 +, +1000 +0000 +0001 +0000 +1000 +0010 +1000 +0000 +, +0001 +0000 +1000 +0000 +0001 +0000 +1000 +0000 +0001 +0000 +1000 +0000 +0002 +0003 +2000 +3000 +, +0001 +0010 +0100 +1000 +0000 +0001 +1000 +0000 +, +0010 +0100 +0010 +1000 +0001 +0100 +0001 +1000 +, +0100 +0010 +0001 +1000 +0000 +0001 +0010 +0000 +, +0001 +1000 +0100 +1000 +0001 +0100 +0010 +0100 +, +0001 +1000 +0100 +0010 +0000 +0001 +1000 +0000 +, +0010 +1000 +0010 +1000 +0100 +0010 +0001 +1000 +, +0010 +0100 +0001 +0100 +0000 +0001 +1000 +0000 +, +0100 +0010 +0001 +1000 +0010 +1000 +0001 +1000 +, +0001 +0010 +0100 +1000 +0000 +0001 +1000 +0000 +, +0010 +0100 +0010 +1000 +0001 +0100 +0001 +1000 +, +0100 +0010 +0001 +1000 +0000 +0001 +0010 +0000 +, +0001 +1000 +0100 +1000 +0001 +0100 +0010 +0100 +, +0001 +1000 +0100 +0010 +0000 +0001 +1000 +0000 +, +0010 +1000 +0010 +1000 +0100 +0010 +0001 +1000 +, +0010 +0100 +0001 +0100 +0000 +0001 +1000 +0000 +, +0001 +0000 +0010 +0000 +0001 +0000 +0010 +0000 +0001 +0000 +0010 +0000 +0002 +0003 +2000 +3000 +, +0001 +0010 +0100 +2000 +0000 +0000 +3000 +0001 +, +0200 +0000 +0300 +0002 +0000 +0003 +1000 +0000 +0200 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0300 +0010 +0001 +1000 +0100 +1000 +0001 +, +0100 +0000 +0001 +0000 +0100 +0000 +0001 +0000 +1000 +0000 +0100 +0000 +2000 +3000 +0002 +0003 +, +1000 +0100 +0010 +0002 +0000 +0000 +0000 +0103 +, +0020 +0000 +0030 +2000 +0000 +3000 +0001 +0000 +0200 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0300 +0001 +0000 +1000 +0000 +0010 +0000 +1000 +0000 +0100 +0000 +0010 +0000 +, +0001 +0000 +1000 +0000 +0001 +0000 +1000 +0000 +0010 +0000 +1000 +0000 +0002 +0003 +0200 +0300 +, +0001 +0010 +0100 +1000 +0000 +0010 +1000 +0001 +, +1000 +0100 +0010 +0001 +0000 +0100 +0010 +0100 +, +0001 +0010 +0001 +1000 +0000 +1000 +0100 +0010 +, +0004 +0003 +4000 +3000 +0400 +0300 +0040 +0030 +, +0001 +0100 +0001 +1000 +0000 +0010 +1000 +0010 +, +1000 +0100 +0010 +0001 +0000 +0100 +0010 +0100 +, +0001 +1000 +0010 +1000 +0000 +0001 +0010 +0100 +, +4000 +3000 +0004 +0003 +1000 +1000 +0001 +1000 +, +0001 +0010 +0100 +2000 +0000 +0000 +3000 +0001 +, +0200 +0000 +0300 +0002 +0000 +0003 +1000 +0000 +0200 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0300 +0010 +0001 +1000 +0100 +1000 +0001 +, +0100 +0000 +0001 +0000 +0100 +0000 +0001 +0000 +1000 +0000 +0100 +0000 +2000 +3000 +0002 +0003 +, +1000 +0100 +0010 +0002 +0000 +0000 +0000 +0103 +, +0020 +0000 +0030 +2000 +0000 +3000 +0001 +0000 +0200 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0300 +0001 +0000 +1000 +0000 +0010 +0000 +1000 +0000 +0100 +0000 +0010 +0000 +, +0001 +0000 +1000 +0000 +0001 +0000 +1000 +0000 +0010 +0000 +1000 +0000 +0002 +0003 +0200 +0300 +, +0001 +1000 +0010 +0100 +, +0001 +0010 +0001 +1000 +, +0010 +1000 +0100 +1000 +, +0001 +0010 +0100 +1000 +, +0001 +0010 +0001 +0100 +, +0001 +1000 +0010 +1000 +, +0100 +1000 +0010 +0100 +, +0001 +0010 +0100 +1000 +, +0001 +0100 +0001 +0000 +1000 +0100 +1000 +0000 +, +0010 +0100 +0010 +0000 +1000 +0001 +1000 +0000 +, +0001 +0010 +0100 +0000 +1000 +0100 +0010 +0000 +, +0001 +0100 +0001 +0000 +1000 +0100 +1000 +0000 +, +0001 +0010 +0100 +1000 +0010 +1000 +0100 +1000 +, +0001 +0010 +0100 +1000 +0001 +0100 +0001 +1000 +, +0100 +0010 +0001 +1000 +0100 +1000 +0010 +1000 +, +0100 +0010 +0001 +0100 +0001 +1000 +0010 +1000 +, +0001 +0010 +0100 +1000 +0000 +0001 +0100 +0000 +, +0001 +1000 +0100 +0010 +0001 +0100 +0010 +0100 +, +0001 +1000 +0100 +1000 +0000 +0010 +1000 +0000 +, +0100 +0010 +0001 +0100 +0010 +1000 +0001 +1000 +, +0001 +0010 +0100 +1000 +0000 +0001 +1000 +0000 +, +0100 +0010 +0100 +1000 +0001 +0100 +0001 +1000 +, +0100 +0010 +0100 +1000 +0000 +0001 +0100 +0000 +, +0001 +1000 +0001 +1000 +0001 +0100 +0001 +0100 +, +0001 +0000 +0000 +1000 +0000 +0000 +0000 +0000 +0010 +0000 +0000 +0000 +0100 +0000 +0000 +0000 +, +0001 +0000 +1000 +0000 +0100 +0000 +0020 +0030 +, +0002 +0000 +0000 +0003 +1000 +0000 +0100 +0000 +0010 +0000 +0002 +0000 +0000 +0000 +0000 +0000 +, +0003 +0000 +0100 +0000 +0002 +0000 +0003 +2000 +0000 +3000 +0010 +0000 +0200 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0300 +0001 +0000 +1000 +0000 +0010 +0000 +1000 +0000 +, +0100 +0010 +0001 +0100 +0001 +1000 +0010 +1000 +, +0002 +0003 +0200 +0300 +0001 +0000 +0010 +0000 +0100 +0000 +2000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +3001 +0000 +0200 +0000 +0300 +0002 +0000 +0003 +1000 +0000 +0020 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0030 +0100 +0000 +0010 +0000 +1000 +0000 +0100 +0000 +, +0010 +0001 +1000 +0100 +1000 +0100 +1000 +0001 +, +0010 +0100 +1000 +0010 +1000 +0002 +0000 +0000 +, +0003 +0000 +0100 +0000 +0010 +0000 +0000 +1000 +0000 +0000 +0001 +0000 +0200 +0000 +0000 +0000 +, +0000 +0300 +0020 +0000 +0000 +0030 +2000 +3000 +, +0200 +0300 +0020 +0000 +0030 +0000 +0002 +0000 +, +0000 +0003 +0020 +0000 +0000 +0000 +0030 +0000 +, +0200 +0300 +2000 +0000 +0000 +0000 +0000 +3000 +, +0010 +0100 +0002 +0000 +1003 +2000 +0000 +0000 +, +3000 +0000 +0010 +0100 +0010 +0100 +0001 +1000 +, +0002 +0003 +2000 +3000 +0020 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0030 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +; + +//---------------dance-single - Kommisar---------------- +#NOTEDATA:; +#STEPSTYPE:dance-single; +#DESCRIPTION:Kommisar; +#CHARTSTYLE:; +#DIFFICULTY:Easy; +#METER:4; +#RADARVALUES:0.492,0.484,0.000,0.248,0.000,412.000,0.000,32.000,0.000,0.000,0.000,0.000,0.000,0.492,0.484,0.000,0.248,0.000,412.000,0.000,32.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Kommisar; +#OFFSET:-0.125000; +#BPMS:0.000000=181.699997 +,304.000000=90.850998 +,311.000000=181.701996 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +; +#ATTACKS: +; +#NOTES: +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0001 +1000 +0010 +1000 +, +0001 +0100 +0001 +1000 +, +0100 +1000 +0100 +0010 +, +0001 +0000 +0000 +0000 +1000 +0000 +0000 +0000 +0001 +0000 +0000 +0000 +0200 +0300 +0002 +0003 +, +1000 +0010 +1000 +0001 +, +0100 +0010 +0100 +0001 +, +1000 +0100 +0010 +0001 +, +1000 +0000 +1000 +0000 +0001 +1000 +0001 +1000 +, +0001 +0100 +0001 +1000 +, +0010 +1000 +0100 +0010 +, +0001 +1000 +0100 +1000 +, +0010 +0000 +0000 +0000 +0100 +0000 +0000 +0000 +0001 +0000 +0000 +0000 +2000 +3000 +0002 +0003 +, +1000 +0010 +1000 +0001 +, +1000 +0010 +0100 +0001 +, +0010 +0100 +1000 +0010 +, +1000 +0000 +0000 +0000 +0100 +0000 +0000 +0000 +0010 +0000 +0000 +0000 +0002 +0003 +2000 +3000 +, +0001 +0100 +0010 +1000 +, +0100 +0010 +0001 +1000 +, +0010 +0100 +0010 +1000 +, +0100 +0000 +0000 +0000 +1000 +0000 +0000 +0000 +0010 +0000 +0000 +0000 +2000 +3000 +0002 +0003 +, +1000 +0010 +0100 +0001 +, +1000 +0100 +1000 +0001 +, +0100 +0001 +1000 +0100 +, +1000 +0001 +1000 +0000 +0001 +0100 +0001 +0000 +, +1000 +0000 +0100 +0020 +0000 +0000 +0030 +0001 +, +0100 +0000 +0001 +1000 +0001 +0000 +0100 +0000 +, +0010 +1000 +0100 +0010 +, +0001 +0000 +1000 +0000 +0010 +0000 +2000 +3002 +, +0103 +0000 +0010 +2000 +0000 +0000 +3000 +0001 +, +0100 +0000 +0001 +1000 +0001 +0000 +1000 +0000 +, +0100 +0010 +0001 +1000 +, +0100 +0000 +1000 +0000 +0100 +0000 +0000 +0000 +1000 +0000 +0001 +0000 +2000 +3000 +0002 +0003 +, +0100 +0000 +0001 +1000 +0000 +0010 +1000 +0000 +, +0001 +0000 +0100 +0001 +0000 +1000 +0001 +0000 +, +1000 +0000 +0100 +0010 +0000 +0100 +1000 +0000 +, +0001 +1000 +0010 +1000 +, +0001 +0000 +1000 +0010 +0000 +1000 +0001 +0000 +, +0100 +0000 +0010 +1000 +0000 +0010 +0100 +0000 +, +0001 +0000 +1000 +0010 +0000 +1000 +0001 +0000 +, +1000 +0000 +0100 +0000 +0010 +0000 +0001 +1000 +, +0001 +0000 +1000 +0200 +0000 +0000 +0300 +0010 +, +0001 +0000 +1000 +0100 +1000 +0000 +0001 +0000 +, +0100 +0010 +1000 +0100 +, +0010 +0000 +0001 +0000 +1000 +0000 +0002 +2003 +, +3010 +0000 +0100 +0002 +0000 +0000 +0003 +1000 +, +0010 +0000 +0100 +0001 +0100 +0000 +0001 +0000 +, +1000 +0100 +0010 +0001 +, +1000 +0000 +0001 +0000 +1000 +0000 +0000 +0000 +0010 +0000 +0100 +0000 +0020 +0030 +0200 +0300 +, +0001 +1000 +0001 +1000 +, +0010 +1000 +0010 +1000 +, +0001 +0100 +0001 +0100 +, +0001 +0010 +0001 +0010 +, +0001 +1000 +0100 +1000 +, +0010 +1000 +0100 +1000 +, +0001 +1000 +0100 +0010 +, +0001 +1000 +0100 +1000 +, +0001 +0100 +0001 +0000 +1000 +0000 +0010 +0000 +, +1000 +0100 +1000 +0000 +0001 +0000 +0100 +0000 +, +0010 +1000 +0010 +0000 +1000 +0000 +0100 +0000 +, +0010 +0001 +0010 +0000 +0100 +0000 +1000 +0000 +, +0001 +1000 +0001 +0000 +1000 +0000 +0010 +0000 +, +0100 +0001 +0100 +0000 +0001 +0000 +1000 +0000 +, +0100 +0010 +0001 +0000 +1000 +0000 +0100 +0000 +, +0010 +0001 +0010 +0000 +0100 +0000 +1000 +0000 +, +0001 +1000 +0010 +0100 +, +0001 +0000 +1000 +0000 +0010 +0000 +1000 +0001 +, +1000 +0010 +0100 +0001 +, +1000 +0000 +0100 +0000 +0010 +0000 +0001 +1000 +, +0001 +1000 +0100 +1000 +, +0010 +0000 +0100 +0000 +0001 +0000 +1000 +0010 +, +1000 +0001 +0010 +0100 +, +1000 +0000 +0001 +0000 +1000 +0000 +0000 +0000 +0001 +0000 +1000 +0000 +0002 +0003 +2000 +3000 +, +0001 +0000 +0100 +0000 +, +0001 +0000 +1000 +0000 +0001 +0000 +2000 +3000 +, +0002 +0003 +1000 +0000 +0001 +0200 +0000 +0000 +, +0300 +0010 +1000 +0000 +0100 +0010 +0001 +0000 +, +1000 +0010 +0100 +0001 +, +0010 +0100 +1000 +0001 +, +2000 +3200 +0310 +0000 +0001 +2000 +0000 +0000 +, +3000 +0010 +0100 +0000 +0001 +1000 +0001 +0000 +, +1000 +0000 +0010 +0000 +0100 +0001 +0100 +0000 +, +0001 +0000 +1000 +0000 +0100 +0000 +0010 +0001 +, +1000 +0000 +0010 +0000 +1000 +0002 +0000 +0000 +, +0003 +1000 +0001 +0000 +1000 +0100 +1000 +0000 +, +0010 +1000 +0001 +0010 +, +0100 +0000 +1000 +0000 +0010 +0000 +1000 +0001 +, +1000 +0001 +1000 +0000 +0010 +0000 +1000 +0000 +, +0100 +1000 +0001 +0010 +, +0100 +1000 +0010 +1000 +, +0001 +0000 +1000 +0100 +1000 +0000 +0001 +0100 +, +0002 +0003 +2000 +3000 +0002 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +, +0000 +0000 +0000 +0000 +, +0000 +0003 +0000 +0000 +0000 +0000 +0000 +0000 +; + +//---------------pump-single - Vin.il / Aegis---------------- +#NOTEDATA:; +#STEPSTYPE:pump-single; +#DESCRIPTION:Vin.il / Aegis; +#CHARTSTYLE:Pad; +#DIFFICULTY:Medium; +#METER:10; +#RADARVALUES:1.000,1.000,0.581,1.000,0.201,694.000,75.000,173.000,0.000,0.000,0.000,0.000,0.000,1.000,1.000,0.581,1.000,0.201,694.000,75.000,173.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Vin.il; +#OFFSET:-0.125000; +#BPMS:0.000000=181.699997 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=4 +,384.000000=13 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +,384.000000=1.500000=0.500000=0 +; +#SCROLLS:0.000000=1.000000 +,304.000000=0.500000 +,318.000000=1.000000 +,386.000000=0.000010 +; +#FAKES:; +#LABELS:0.000000=Song Start +; +#ATTACKS: +; +#NOTES: +// measure 0 +00000 +00000 +00000 +00000 +, // measure 1 +00000 +00000 +00000 +00000 +, // measure 2 +00000 +00000 +00000 +00000 +, // measure 3 +00000 +00000 +00000 +00000 +, // measure 4 +00100 +00000 +01001 +00000 +00010 +10000 +00001 +01000 +, // measure 5 +00100 +00000 +10100 +00000 +00100 +01000 +00010 +00100 +, // measure 6 +00001 +00000 +01001 +00000 +00001 +01000 +00100 +10000 +, // measure 7 +00100 +00000 +00100 +01000 +00010 +00100 +00001 +00000 +, // measure 8 +00100 +00000 +00000 +00000 +01010 +00000 +00000 +00000 +01000 +00020 +00000 +00030 +00100 +00000 +00010 +00000 +, // measure 9 +10000 +00000 +00000 +00000 +10010 +00000 +00000 +00000 +10000 +00200 +00000 +00300 +01000 +00000 +00001 +00000 +, // measure 10 +00100 +00000 +00000 +00000 +00101 +00000 +00000 +00000 +00100 +00002 +00000 +00003 +10000 +00000 +00100 +00000 +, // measure 11 +01000 +00000 +00001 +00000 +01000 +00000 +00001 +00000 +10000 +00010 +10000 +00010 +00200 +00000 +00300 +00000 +, // measure 12 +00001 +00100 +00001 +10000 +00000 +00010 +01000 +00001 +, // measure 13 +10000 +00100 +01000 +00010 +00100 +00001 +10000 +00100 +, // measure 14 +00000 +01000 +00010 +00001 +00000 +00010 +00100 +00010 +, // measure 15 +10000 +00010 +01000 +00100 +10000 +00001 +01000 +10000 +, // measure 16 +00000 +00100 +00001 +01000 +00000 +00100 +00010 +00001 +, // measure 17 +00100 +10000 +00010 +00001 +00100 +00010 +01000 +00100 +, // measure 18 +00000 +10000 +00001 +00100 +00000 +00010 +01000 +00100 +, // measure 19 +01000 +00001 +10000 +00100 +01000 +02000 +03001 +00002 +, // measure 20 +10003 +00010 +01000 +00100 +10000 +00001 +01000 +00001 +, // measure 21 +10000 +00010 +01000 +00100 +10000 +00010 +01000 +01000 +, // measure 22 +00001 +01000 +00010 +10000 +00100 +01000 +00010 +00001 +, // measure 23 +00100 +10000 +00010 +00100 +00001 +10000 +00001 +00001 +, // measure 24 +01000 +10000 +00100 +00001 +01000 +00100 +01000 +00010 +, // measure 25 +10000 +01000 +00100 +00010 +00100 +00001 +10000 +10000 +, // measure 26 +00100 +10000 +00010 +01000 +00100 +10000 +00010 +00100 +, // measure 27 +00001 +00002 +00003 +00000 +10000 +20000 +30000 +00000 +00001 +00002 +00003 +00000 +10000 +20000 +30000 +00000 +00010 +00020 +00030 +00000 +01000 +02000 +03000 +00000 +00010 +00020 +00030 +00000 +01000 +02000 +03000 +00000 +, // measure 28 +00100 +10000 +00100 +02000 +10000 +00000 +03100 +00000 +, // measure 29 +10000 +01000 +00100 +00020 +00100 +00000 +01030 +00000 +, // measure 30 +00010 +10000 +00001 +00100 +00010 +10000 +00001 +00100 +, // measure 31 +00010 +01000 +00100 +10100 +10000 +00001 +10001 +10000 +, // measure 32 +00001 +01000 +10000 +02000 +00010 +00000 +03100 +00000 +, // measure 33 +10000 +00010 +00100 +00020 +00001 +00000 +00130 +00000 +, // measure 34 +00001 +10000 +00100 +01000 +00001 +10000 +00100 +01000 +, // measure 35 +00010 +00020 +00030 +00000 +01000 +02000 +03000 +00000 +00010 +00020 +00030 +00000 +01000 +02000 +03000 +00000 +00001 +00002 +00003 +00000 +10000 +20000 +30000 +00000 +00001 +00002 +00003 +00000 +10000 +20000 +30000 +00000 +, // measure 36 +00010 +00100 +00010 +00002 +00003 +00010 +10000 +00010 +, // measure 37 +00100 +00010 +01000 +00001 +10000 +00010 +01000 +00100 +, // measure 38 +10000 +00010 +01000 +20000 +30000 +01000 +00001 +01000 +, // measure 39 +02100 +03100 +10200 +10300 +21000 +31000 +02100 +03100 +, // measure 40 +00010 +00100 +00001 +00020 +00030 +00001 +00100 +00010 +, // measure 41 +01000 +00100 +10000 +01000 +00100 +00010 +00100 +00001 +, // measure 42 +00100 +00010 +01000 +00200 +00300 +10000 +00010 +00100 +, // measure 43 +00201 +00301 +00012 +00013 +00120 +00130 +01200 +01300 +, // measure 44 +00010 +00100 +00001 +02000 +00010 +00000 +03100 +00000 +, // measure 45 +01000 +00010 +00100 +00002 +10000 +00000 +00103 +00000 +, // measure 46 +00010 +01000 +00100 +10000 +00010 +01000 +00100 +10000 +, // measure 47 +00010 +01000 +00100 +10010 +00100 +00001 +01001 +00100 +, // measure 48 +10000 +00010 +00100 +02000 +10000 +00000 +03100 +00000 +, // measure 49 +00010 +01000 +00001 +00200 +00010 +00000 +00301 +00000 +, // measure 50 +10000 +00100 +01000 +00010 +10000 +00100 +01000 +00010 +, // measure 51 +10000 +20000 +30000 +00000 +00001 +00002 +00003 +00000 +10000 +20000 +30000 +00000 +00001 +00002 +00003 +00000 +01000 +02000 +03000 +00000 +00010 +00020 +00030 +00000 +01000 +02000 +03000 +00000 +00010 +00020 +00030 +00000 +, // measure 52 +02020 +03030 +00220 +00330 +02020 +03030 +02002 +03003 +, // measure 53 +02020 +03030 +20020 +30030 +02020 +03030 +02200 +03300 +, // measure 54 +02002 +03003 +00202 +00303 +02002 +03003 +02200 +03300 +, // measure 55 +20020 +30030 +02002 +03003 +10010 +01001 +10010 +00000 +, // measure 56 +20002 +30003 +02002 +03003 +20002 +30003 +20200 +30300 +, // measure 57 +20002 +30003 +00202 +00303 +20002 +30003 +20020 +30030 +, // measure 58 +20200 +30300 +20020 +30030 +00220 +00330 +20020 +30030 +, // measure 59 +00020 +20030 +30200 +02300 +03002 +00203 +00320 +10030 +, // measure 60 +20100 +30100 +01200 +01300 +02010 +03010 +00120 +00130 +, // measure 61 +00201 +00301 +01002 +01003 +02100 +03100 +10200 +10300 +, // measure 62 +20010 +30010 +10020 +10030 +20010 +30010 +10020 +10030 +, // measure 63 +00200 +02300 +03020 +00230 +00302 +20003 +30020 +00130 +, // measure 64 +00201 +00301 +10002 +10003 +20010 +30010 +01020 +01030 +, // measure 65 +02001 +03001 +10002 +10003 +20100 +30100 +01200 +01300 +, // measure 66 +02001 +03001 +01002 +01003 +02001 +03001 +01002 +01003 +, // measure 67 +00200 +20300 +30020 +00230 +00302 +20003 +30200 +01300 +, // measure 68 +00010 +00001 +00010 +00100 +00000 +00001 +00010 +00100 +, // measure 69 +01000 +10000 +00100 +00001 +00100 +10000 +00100 +00001 +, // measure 70 +00000 +01000 +10000 +01000 +00000 +00100 +10000 +00001 +, // measure 71 +01000 +10000 +00100 +00001 +10000 +00010 +00100 +00001 +, // measure 72 +00000 +00100 +00010 +01000 +00000 +00010 +00100 +00001 +, // measure 73 +00100 +00010 +01000 +10000 +01000 +00010 +10000 +00100 +, // measure 74 +00000 +10000 +01000 +00100 +00000 +00010 +01000 +00100 +, // measure 75 +01000 +00000 +00001 +00000 +10000 +00000 +00010 +00000 +10000 +00010 +10000 +00010 +10000 +00010 +10000 +00010 +, // measure 76 +00100 +00000 +00000 +00000 +00000 +00000 +00001 +00000 +00000 +00000 +00000 +00000 +00100 +00000 +00000 +00000 +00000 +00000 +00020 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00030 +00000 +00000 +00000 +00000 +10000 +00000 +00000 +00000 +, // measure 77 +00100 +00000 +00000 +00100 +00000 +00000 +01000 +00000 +00020 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +, // measure 78 +00000 +00000 +00030 +00000 +00100 +00000 +00010 +00000 +02000 +03000 +00002 +00003 +20000 +30000 +00100 +02000 +, // measure 79 +00000 +00000 +00000 +00000 +03000 +00000 +00000 +00000 +00010 +00000 +00000 +00000 +00100 +00000 +00000 +00000 +00001 +00002 +00003 +00000 +10000 +20000 +30000 +00000 +00001 +00002 +00003 +00000 +10000 +20000 +30000 +00000 +, // measure 80 +00100 +01000 +10000 +01000 +00100 +01000 +10000 +01000 +, // measure 81 +00100 +10000 +00001 +10000 +00100 +10000 +00001 +10000 +, // measure 82 +00100 +00001 +00010 +10000 +00010 +00001 +00100 +10000 +, // measure 83 +00010 +00100 +01001 +00100 +10000 +01001 +10010 +00100 +, // measure 84 +00001 +00010 +00100 +00010 +00001 +00010 +00100 +00010 +, // measure 85 +00001 +10000 +00010 +10000 +00001 +10000 +00010 +10000 +, // measure 86 +00001 +01000 +10000 +01000 +00001 +01000 +10000 +00100 +, // measure 87 +00001 +00000 +00000 +00000 +10000 +00000 +00000 +00000 +01000 +00000 +00000 +00000 +00100 +00000 +00000 +00000 +00010 +00020 +00030 +00000 +01000 +02000 +03000 +00000 +00010 +00020 +00030 +00000 +01000 +02000 +03000 +00000 +, // measure 88 +00001 +00100 +00010 +02000 +00100 +00000 +03010 +00100 +, // measure 89 +00001 +10000 +00010 +01000 +00200 +00000 +10300 +00000 +, // measure 90 +00010 +10000 +00010 +01000 +00001 +00100 +00010 +01000 +, // measure 91 +00100 +10000 +00100 +10000 +00100 +00001 +00100 +00001 +, // measure 92 +00010 +00100 +01000 +10000 +00010 +00100 +00001 +00100 +, // measure 93 +00010 +01000 +00100 +01000 +10000 +00100 +00001 +00100 +, // measure 94 +00010 +01000 +00100 +10000 +00001 +00100 +00010 +01000 +, // measure 95 +00010 +00020 +00030 +00000 +01000 +02000 +03000 +00000 +00010 +00020 +00030 +00000 +01000 +02000 +03000 +00000 +00001 +00002 +00003 +00000 +10000 +20000 +30000 +00000 +00001 +00002 +00003 +00000 +10000 +20000 +30000 +00000 +, // measure 96 +20002 +00000 +00000 +00000 +, // measure 97 +00000 +00000 +00000 +00000 +00000 +30003 +00000 +00000 +; + +//---------------pump-single - Vin.il---------------- +#NOTEDATA:; +#STEPSTYPE:pump-single; +#DESCRIPTION:Vin.il; +#CHARTSTYLE:Pad; +#DIFFICULTY:Easy; +#METER:7; +#RADARVALUES:0.572,0.594,0.380,0.101,0.012,455.000,49.000,13.000,0.000,0.000,0.000,0.000,0.000,0.572,0.594,0.380,0.101,0.012,455.000,49.000,13.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Vin.il; +#OFFSET:-0.125000; +#BPMS:0.000000=181.699997 +,304.000000=90.850998 +,311.000000=181.701996 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=2 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +,380.000000=0.062500=0.062500=0 +,380.062500=1.000000=0.062500=0 +,380.500000=0.062500=0.062500=0 +,380.562500=1.000000=0.062500=0 +,381.000000=0.062500=0.062500=0 +,381.062500=1.000000=0.062500=0 +,381.250000=0.062500=0.062500=0 +,381.312500=1.000000=0.062500=0 +,381.750000=0.062500=0.062500=0 +,381.812500=1.000000=0.062500=0 +,382.500000=0.062500=0.062500=0 +,382.562500=1.000000=0.062500=0 +,383.000000=0.062500=0.062500=0 +,383.062500=1.000000=0.062500=0 +; +#SCROLLS:0.000000=1.000000 +; +#FAKES:; +#LABELS:0.000000=Song Start +; +#ATTACKS: +; +#NOTES: +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +, +10000 +00000 +10100 +00000 +00000 +10000 +00001 +00000 +, +00001 +00000 +00101 +00000 +00000 +00001 +01000 +00000 +, +01000 +00000 +01100 +00000 +00000 +01000 +00010 +00000 +, +00010 +00000 +00000 +00100 +00001 +01000 +00100 +00000 +, +01000 +00000 +01100 +00000 +00000 +01000 +00010 +00000 +, +00010 +00000 +00110 +00000 +00000 +00010 +10000 +00000 +, +10000 +00000 +10100 +00000 +00000 +10000 +00001 +00000 +, +00001 +00100 +00001 +00100 +00010 +10000 +00200 +00300 +, +01000 +00000 +01001 +00000 +00001 +00000 +00100 +00001 +, +10000 +00000 +00000 +00100 +01000 +00000 +00010 +00100 +, +00001 +00000 +01001 +00000 +01000 +00000 +00100 +01000 +, +00010 +00000 +00000 +00100 +00001 +00000 +10000 +00100 +, +10000 +00000 +10010 +00000 +00010 +00000 +00100 +00001 +, +00100 +00010 +00000 +01000 +00100 +00000 +10000 +00001 +, +01000 +01001 +00001 +00100 +, +00010 +00100 +00010 +00000 +10000 +00100 +10000 +00000 +, +00001 +00000 +00101 +00000 +00001 +00100 +00010 +00000 +, +01000 +00100 +00000 +00100 +10000 +00000 +00010 +00100 +, +00010 +00000 +00110 +00000 +00010 +01000 +00100 +00000 +, +10000 +00001 +00000 +00001 +00100 +00000 +00010 +01000 +, +00010 +00000 +01010 +00000 +01000 +00100 +01000 +00000 +, +00001 +10000 +00000 +10000 +00010 +00000 +00010 +01000 +, +00001 +00000 +00101 +00000 +00001 +01000 +00100 +00000 +, +10000 +00010 +10000 +00010 +01000 +00001 +00200 +00300 +, +00001 +00000 +00001 +20000 +00000 +30000 +00000 +00100 +, +10000 +00000 +00010 +00100 +00020 +00000 +00000 +00000 +, +00030 +00000 +00100 +00000 +00001 +00100 +00001 +02000 +, +03000 +00000 +00100 +00000 +01000 +00000 +00010 +00100 +, +00010 +00000 +00010 +02000 +00000 +03000 +00000 +00100 +, +01000 +00000 +00001 +00100 +00002 +00000 +00000 +00000 +, +00003 +00000 +00100 +00000 +00010 +00100 +00010 +10000 +, +00100 +00000 +01000 +00000 +00100 +10000 +00002 +00003 +, +00100 +00000 +00001 +00000 +00100 +00000 +00010 +01000 +, +00100 +00000 +10000 +00000 +00100 +00000 +01000 +00010 +, +00100 +00001 +00000 +10000 +00000 +00100 +00000 +00100 +, +01000 +00010 +00100 +00000 +00001 +00000 +01000 +00100 +, +01000 +00000 +01000 +00000 +00100 +00000 +10000 +00001 +, +00100 +00000 +00010 +00000 +00100 +00000 +00001 +10000 +, +00100 +01000 +00000 +00010 +00000 +00100 +00000 +00100 +, +00001 +10000 +00100 +10000 +00100 +00000 +01000 +00010 +, +00100 +00000 +00101 +00000 +00001 +10000 +00100 +00000 +, +10000 +00000 +10100 +00000 +10000 +00010 +00100 +00000 +, +00010 +00000 +01010 +00000 +01000 +00100 +01000 +00001 +, +00000 +00000 +00100 +00000 +00001 +00000 +10000 +00100 +, +01000 +00000 +01100 +00000 +00100 +01000 +00010 +00000 +, +00100 +00000 +00101 +00000 +00001 +01000 +00100 +00000 +, +01000 +01010 +00010 +00100 +, +00010 +00100 +00001 +00000 +01000 +00100 +20000 +30000 +, +00010 +00110 +00010 +01010 +, +01000 +01100 +01000 +01010 +, +00001 +00101 +00001 +10001 +, +10000 +10100 +10000 +10001 +, +01000 +00000 +00010 +00100 +00001 +00000 +01000 +00000 +, +00001 +00000 +10000 +00100 +01000 +00000 +00001 +00000 +, +10000 +00000 +00001 +00100 +00010 +00000 +01000 +00000 +, +00010 +00000 +01000 +00100 +10000 +00000 +00001 +00000 +, +01000 +00000 +01010 +00000 +00010 +00100 +00001 +00000 +, +10000 +00000 +10001 +00000 +00001 +00100 +00010 +00000 +, +01000 +00000 +01100 +00000 +00100 +10000 +00010 +00000 +, +10000 +00000 +10100 +00000 +00100 +01000 +00001 +00000 +, +00100 +00001 +00100 +00000 +00001 +00000 +01000 +00000 +, +00100 +10000 +00100 +00000 +10000 +00000 +00010 +00000 +, +00100 +00010 +00100 +00000 +00010 +00000 +10000 +00000 +, +00100 +01000 +00100 +00000 +01000 +00000 +00001 +00000 +, +00100 +00000 +00101 +00000 +00001 +01000 +00100 +00000 +, +00100 +10000 +00000 +00010 +00100 +00000 +00001 +00000 +, +00100 +00000 +00110 +00000 +00010 +10000 +00100 +00000 +, +00100 +01000 +00000 +00001 +00100 +00000 +00010 +00000 +, +00100 +00000 +00110 +00000 +00010 +10000 +00100 +00000 +, +00100 +01000 +00000 +00001 +00100 +00000 +00010 +00000 +, +00100 +00000 +00101 +00000 +00001 +01000 +00100 +00000 +, +00100 +10000 +00000 +00010 +00100 +00000 +00001 +00000 +, +00100 +00000 +00001 +20000 +00000 +00000 +30000 +00000 +10000 +00000 +00000 +00001 +00200 +00000 +00000 +00000 +, +00300 +00000 +00100 +00000 +00010 +01000 +00100 +00000 +10000 +00000 +00001 +00000 +00100 +00000 +00001 +00000 +, +10000 +00100 +10001 +00000 +00001 +00000 +00100 +00001 +, +01000 +00000 +00100 +00000 +10100 +00000 +10000 +00010 +, +00100 +00000 +00001 +00100 +00001 +00000 +10000 +00000 +, +10100 +00000 +00010 +00100 +00010 +00000 +01000 +00000 +, +01100 +00000 +00010 +00000 +01000 +00000 +00100 +01000 +, +00001 +00000 +00100 +00000 +00110 +00000 +00010 +10000 +, +00100 +00000 +01000 +00100 +01000 +00000 +00010 +00000 +, +00110 +00000 +10000 +00100 +10000 +00000 +00001 +00000 +, +00101 +00000 +00001 +01000 +00001 +01000 +00000 +00000 +, +00000 +01000 +00100 +00000 +00100 +10000 +00010 +00000 +, +00110 +00100 +00101 +00001 +, +10001 +00000 +10000 +00000 +00100 +10000 +00100 +00000 +, +01000 +00000 +00001 +00100 +00001 +00000 +01000 +00000 +, +00010 +00000 +10000 +00000 +10100 +00000 +00100 +10000 +, +00001 +00100 +00010 +00000 +01010 +00000 +01000 +00000 +, +00100 +00000 +10000 +00100 +10000 +00100 +01000 +00001 +, +00100 +00010 +02020 +00000 +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +00000 +00000 +00000 +03030 +; + +//---------------pump-single - Vin.il - Another CZ---------------- +#NOTEDATA:; +#STEPSTYPE:pump-single; +#DESCRIPTION:Vin.il - Another CZ; +#CHARTSTYLE:Pad - ACZ; +#DIFFICULTY:Challenge; +#METER:21; +#RADARVALUES:1.000,1.000,0.620,0.488,1.000,1006.000,80.000,63.000,0.000,0.000,0.000,0.000,0.000,1.000,1.000,0.620,0.488,1.000,1006.000,80.000,63.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Vin.il; +#OFFSET:-0.125000; +#BPMS:0.000000=181.699997 +,44.000000=363.399994 +,47.000000=726.799988 +,48.000000=181.699997 +,300.000000=363.399994 +,304.000000=181.699997 +; +#STOPS:; +#DELAYS:44.500000=0.082554 +,45.000000=0.082554 +,45.500000=0.082554 +,46.000000=0.082554 +,46.250000=0.041277 +,46.500000=0.041277 +,46.750000=0.041277 +,47.000000=0.041277 +,48.000000=0.247661 +,300.500000=0.082558 +,301.000000=0.082558 +,301.500000=0.082558 +,302.000000=0.082558 +,302.250000=0.041275 +,302.500000=0.041275 +,302.750000=0.041275 +,303.000000=0.041275 +,303.250000=0.041275 +,303.500000=0.041275 +,303.750000=0.041275 +,304.000000=0.041275 +; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=4 +,384.000000=8 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +,174.750000=0.500000=0.500000=0 +,175.000000=1.000000=0.500000=0 +,175.250000=0.500000=0.250000=0 +,175.375000=1.000000=0.250000=0 +,175.500000=0.500000=0.250000=0 +,175.625000=1.000000=0.250000=0 +,175.750000=0.500000=0.250000=0 +,175.875000=1.000000=0.250000=0 +,304.000000=2.000000=14.000000=0 +,384.000000=1000.000000=6.500000=0 +; +#SCROLLS:0.000000=1.000000 +,174.500000=0.000000 +,176.000000=1.000000 +,304.000000=0.250000 +,318.000000=0.500000 +,384.000000=0.001000 +; +#FAKES:; +#LABELS:0.000000=Song Start +; +#ATTACKS:; +#NOTES: +// measure 0 +00000 +00000 +00000 +00000 +, // measure 1 +00000 +00000 +00000 +00000 +, // measure 2 +00000 +00000 +00000 +00000 +, // measure 3 +00000 +00000 +00000 +00000 +, // measure 4 +10000 +00000 +00001 +00100 +00001 +00000 +01000 +00100 +01000 +00010 +00000 +00000 +01010 +00000 +01010 +00000 +, // measure 5 +10000 +00000 +00001 +00100 +00001 +00000 +01000 +00100 +01000 +00010 +00000 +00000 +01010 +00000 +01010 +00000 +, // measure 6 +00010 +00000 +01000 +00100 +01000 +00000 +00001 +00100 +00001 +10000 +00000 +00000 +10001 +00000 +10001 +00000 +, // measure 7 +00010 +00000 +01000 +00100 +01000 +00000 +00001 +00000 +00101 +00000 +00101 +00000 +20002 +00000 +30003 +00000 +, // measure 8 +00001 +00000 +01000 +00100 +01000 +00000 +00010 +00100 +00010 +10000 +00000 +00100 +10000 +00001 +00100 +00000 +, // measure 9 +00001 +00000 +01000 +00100 +01000 +00000 +00010 +00100 +00010 +10000 +00000 +00100 +10000 +00001 +00100 +00000 +, // measure 10 +00010 +00000 +10000 +00100 +10000 +00000 +00001 +00100 +00001 +01000 +00000 +00100 +01000 +00010 +00100 +00000 +, // measure 11 +00010 +00000 +00100 +00000 +00010 +00000 +10000 +00000 +00010 +01000 +00100 +10000 +00002 +00000 +00003 +00000 +, // measure 12 +00001 +00000 +00010 +00100 +01000 +00000 +00001 +00000 +01000 +00100 +00010 +00100 +01000 +00000 +00001 +00000 +, // measure 13 +10000 +00000 +00100 +00000 +00000 +00000 +10000 +00100 +00010 +00000 +00001 +00000 +00010 +00000 +00010 +00000 +, // measure 14 +00001 +00000 +10000 +00000 +10000 +00000 +01000 +00100 +00010 +00000 +10000 +00000 +00010 +00100 +01000 +00100 +, // measure 15 +00010 +00000 +10000 +00000 +00000 +00000 +00001 +00100 +01000 +00000 +10000 +00000 +01000 +00100 +00010 +00100 +, // measure 16 +00001 +00000 +00010 +00100 +00010 +00000 +00001 +00000 +10000 +01000 +00100 +01000 +10000 +00100 +01000 +00010 +, // measure 17 +00100 +00000 +00001 +00000 +00000 +00000 +00010 +00001 +00100 +00000 +01000 +00000 +10000 +00000 +00100 +00000 +, // measure 18 +10000 +00000 +01000 +00100 +01000 +00000 +10000 +00000 +00001 +00010 +00100 +00010 +00001 +00100 +00010 +01000 +, // measure 19 +00100 +10000 +00010 +00000 +00110 +01001 +00110 +10001 +, // measure 20 +00100 +00000 +10000 +00100 +10000 +00000 +00010 +00100 +00010 +00100 +00001 +00010 +00100 +00000 +01000 +00000 +, // measure 21 +00010 +00000 +00100 +00000 +01000 +00000 +10000 +01000 +00100 +00000 +00010 +00000 +01000 +00000 +00001 +00000 +, // measure 22 +00100 +00000 +00010 +00100 +00010 +00000 +10000 +00100 +10000 +00100 +01000 +10000 +00100 +00000 +00001 +00000 +, // measure 23 +10000 +00000 +00100 +00000 +00000 +00000 +01000 +00100 +00010 +00100 +01000 +00010 +00100 +00000 +00001 +00000 +, // measure 24 +10000 +00000 +00010 +00100 +00001 +00000 +01000 +00100 +10000 +00010 +01000 +00001 +00100 +00000 +00010 +00000 +, // measure 25 +01000 +00000 +00100 +00000 +00000 +00000 +10000 +00100 +00001 +00000 +00010 +00000 +00100 +00000 +00100 +00000 +, // measure 26 +00010 +10000 +10100 +00001 +00100 +00010 +01000 +00100 +, // measure 27 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +01000 +00010 +01000 +00010 +10000 +00000 +00001 +00000 +, // measure 28 +10001 +00000 +00001 +00000 +00101 +00000 +00100 +00000 +00010 +00000 +01000 +00000 +01100 +00000 +00100 +10000 +, // measure 29 +00001 +00000 +01000 +00000 +01001 +00000 +00001 +00000 +10000 +00000 +00010 +00000 +10010 +00000 +00010 +10000 +, // measure 30 +00010 +00100 +00010 +00000 +00110 +00000 +00010 +00000 +01000 +00100 +10000 +00001 +01000 +00010 +00100 +00001 +, // measure 31 +20000 +00000 +30001 +10001 +00101 +00001 +10100 +10000 +, // measure 32 +01010 +00000 +01000 +00000 +01100 +00000 +00100 +00000 +10000 +00000 +00001 +00000 +00101 +00000 +00100 +00010 +, // measure 33 +01000 +00000 +00001 +00000 +01001 +00000 +01000 +00000 +00010 +00000 +10000 +00000 +10010 +00000 +10000 +00010 +, // measure 34 +10000 +00100 +10000 +00000 +10100 +00000 +10000 +00000 +00001 +00100 +00010 +01000 +00001 +10000 +00100 +01000 +, // measure 35 +00010 +00100 +00010 +00100 +00010 +00100 +00010 +00100 +00010 +10000 +00100 +10000 +00010 +00100 +00010 +01000 +, // measure 36 +00002 +00003 +00200 +00000 +00000 +00300 +00020 +00000 +00000 +00030 +02000 +03000 +00020 +00030 +00002 +00003 +, // measure 37 +00200 +00300 +20000 +00000 +00100 +00000 +00000 +30000 +00002 +00000 +00000 +00000 +00100 +00000 +00000 +00003 +, // measure 38 +20000 +30000 +00200 +00000 +00000 +00300 +00020 +00000 +00000 +00030 +00200 +00000 +00000 +00300 +00010 +00000 +, // measure 39 +00001 +00100 +00010 +00001 +00100 +10000 +00100 +01000 +10000 +00100 +00001 +10000 +00010 +01000 +00100 +10000 +, // measure 40 +00020 +00030 +00200 +00000 +00000 +00300 +00002 +00000 +00000 +00003 +20000 +30000 +00002 +00003 +00020 +00030 +, // measure 41 +00200 +00300 +02000 +00000 +00100 +00000 +00000 +03000 +00020 +00000 +00000 +00000 +00100 +00000 +00000 +00030 +, // measure 42 +02000 +03000 +00200 +00000 +00000 +00300 +20000 +00000 +00000 +30000 +00002 +00000 +00000 +00003 +00100 +00000 +, // measure 43 +00010 +00100 +00001 +00010 +00100 +01000 +00100 +10000 +00010 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +, // measure 44 +01010 +00000 +00010 +00000 +00110 +00000 +01000 +00000 +00100 +00000 +10000 +00000 +10001 +00000 +00001 +10000 +, // measure 45 +00100 +00000 +01000 +00010 +00100 +00001 +10000 +00000 +10010 +00000 +10000 +00000 +00101 +00000 +00001 +01000 +, // measure 46 +00001 +00100 +00001 +00000 +10100 +00000 +00001 +00000 +00010 +00100 +01000 +00010 +00100 +01000 +10000 +00001 +, // measure 47 +00100 +00010 +01000 +00100 +10000 +00010 +00100 +01000 +00100 +00010 +01000 +00100 +00010 +00001 +00100 +00010 +, // measure 48 +10000 +00000 +10000 +00000 +10100 +00000 +00001 +00000 +00100 +00000 +00010 +00000 +01010 +00000 +01000 +00010 +, // measure 49 +00100 +00000 +00001 +00100 +00010 +01000 +00100 +00000 +10010 +00000 +00010 +00000 +01100 +00000 +01000 +00001 +, // measure 50 +01000 +00100 +01000 +00000 +00110 +00000 +01000 +00000 +10000 +00100 +00001 +10000 +00100 +00001 +00010 +01000 +, // measure 51 +00100 +10000 +00001 +00100 +00010 +10000 +00100 +00001 +00100 +10000 +00001 +00100 +10000 +01000 +00100 +10000 +, // measure 52 +00001 +00000 +00100 +00000 +01001 +00000 +10000 +00000 +00001 +00000 +00100 +00000 +01001 +00000 +10000 +00010 +, // measure 53 +01000 +00000 +00100 +00000 +01001 +00000 +00010 +00000 +01000 +00000 +00100 +00000 +01001 +00000 +00001 +01000 +, // measure 54 +00010 +00000 +00100 +00000 +10010 +00000 +01000 +00000 +00010 +00000 +00100 +00000 +10010 +00000 +01000 +00001 +, // measure 55 +10000 +00000 +00100 +00000 +10010 +00000 +00001 +00000 +10000 +00000 +00100 +00000 +10010 +00000 +00010 +10000 +, // measure 56 +00001 +00000 +00100 +00000 +01001 +00000 +10000 +00000 +00001 +00000 +00100 +00000 +01001 +00000 +10000 +00010 +, // measure 57 +01000 +00000 +00100 +00000 +01001 +00000 +00010 +00000 +01000 +00000 +00100 +00000 +01001 +00000 +00001 +01000 +, // measure 58 +00010 +00000 +00100 +00000 +10010 +00000 +01000 +00000 +00010 +00000 +00100 +00000 +10010 +00000 +01000 +00001 +, // measure 59 +10000 +00000 +00100 +00000 +10010 +00000 +00001 +00000 +10000 +00000 +00100 +00000 +10010 +00000 +00010 +10000 +, // measure 60 +00001 +00000 +00100 +00001 +00100 +00010 +01000 +00100 +01000 +00010 +00100 +00001 +00100 +00010 +01000 +00100 +, // measure 61 +01000 +00010 +10000 +00100 +10000 +00010 +00100 +00001 +01000 +00100 +10000 +00100 +10000 +00010 +00100 +00001 +, // measure 62 +01000 +00100 +00010 +00001 +01000 +00100 +00010 +00001 +10000 +01000 +00100 +00010 +10000 +01000 +00100 +00010 +, // measure 63 +00200 +00300 +00002 +00003 +02000 +03000 +00002 +00003 +00200 +00300 +00002 +00003 +02000 +03000 +00020 +00030 +, // measure 64 +10000 +00000 +00100 +01000 +00100 +10000 +00001 +00100 +00001 +10000 +00100 +01000 +00100 +10000 +00001 +00100 +, // measure 65 +00001 +10000 +00010 +00100 +00010 +10000 +00100 +01000 +00001 +00100 +00010 +00100 +00010 +10000 +00100 +01000 +, // measure 66 +00001 +00100 +10000 +01000 +00001 +00100 +10000 +01000 +00010 +00001 +00100 +10000 +00010 +00001 +00100 +10000 +, // measure 67 +00200 +00300 +02000 +03000 +00002 +00003 +02000 +03000 +00200 +00300 +02000 +03000 +00002 +00003 +20000 +30000 +, // measure 68 +00010 +00100 +00100 +00010 +00110 +01000 +00100 +10000 +, // measure 69 +00001 +00000 +00100 +00000 +00100 +00000 +00010 +00100 +01000 +00000 +01000 +00100 +00010 +00000 +01000 +00000 +, // measure 70 +01000 +00000 +00100 +01000 +00100 +00000 +01000 +00000 +01100 +00000 +00100 +10000 +00100 +00000 +01000 +00000 +, // measure 71 +00010 +00000 +00100 +00000 +00110 +00000 +01000 +00100 +10000 +00000 +00001 +10000 +00100 +01000 +00100 +10000 +, // measure 72 +00001 +00010 +00110 +00100 +01000 +00100 +10100 +10000 +, // measure 73 +00001 +00000 +00100 +00000 +00101 +00000 +00100 +00010 +00100 +00010 +01000 +00100 +10000 +00100 +01000 +00001 +, // measure 74 +10000 +01000 +01100 +00100 +00010 +00100 +00101 +00001 +, // measure 75 +10001 +00000 +10001 +00000 +10001 +00000 +10001 +00000 +00001 +10000 +00001 +10000 +00010 +01000 +00010 +01000 +, // measure 76 +00200 +00300 +20000 +30000 +00200 +00300 +00020 +00000 +00000 +00000 +00000 +00000 +00000 +00030 +00100 +01000 +, // measure 77 +00002 +00000 +00003 +00200 +00000 +00300 +00020 +00030 +02000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +, // measure 78 +00000 +00000 +00000 +03000 +00200 +00300 +02000 +03000 +00010 +01000 +00100 +10000 +01000 +10000 +00100 +02000 +, // measure 79 +00000 +00000 +00000 +03000 +00020 +00030 +00200 +00300 +00001 +10000 +00100 +00001 +00010 +00100 +01000 +10000 +, // measure 80 +00001 +00100 +00001 +00100 +00001 +01000 +00010 +00100 +00010 +00000 +10000 +00000 +10100 +00000 +00010 +10000 +, // measure 81 +00100 +00000 +01000 +00010 +00100 +00010 +00001 +00100 +10000 +00000 +00001 +00000 +00101 +00000 +01000 +00000 +, // measure 82 +00010 +00000 +00200 +00300 +01000 +00000 +00200 +00300 +00010 +01000 +00100 +10000 +00010 +00100 +01000 +10000 +, // measure 83 +00001 +00100 +00001 +00100 +00001 +00000 +10001 +00000 +00101 +00000 +00110 +00000 +01100 +00000 +10100 +00000 +, // measure 84 +10001 +00000 +00001 +00100 +00001 +10000 +00100 +01000 +00010 +00000 +00100 +00010 +00100 +00000 +00001 +00100 +, // measure 85 +00001 +00000 +10000 +00100 +10000 +00000 +00100 +00000 +01000 +00000 +00010 +00100 +00010 +00100 +00001 +10000 +, // measure 86 +00100 +01000 +00010 +00000 +00100 +00010 +01000 +00000 +00100 +01000 +00010 +00100 +00001 +00010 +00100 +01000 +, // measure 87 +00010 +00100 +00001 +10000 +00100 +01000 +00010 +00100 +00001 +10000 +00010 +01000 +00001 +10000 +00100 +01000 +, // measure 88 +00010 +00100 +00010 +00100 +00001 +00010 +00100 +01000 +00010 +00100 +00010 +01000 +00100 +01000 +00100 +00010 +, // measure 89 +00100 +01000 +00010 +00100 +00001 +10000 +00100 +01000 +00010 +00100 +00001 +00010 +00100 +01000 +00010 +00100 +, // measure 90 +01000 +00100 +00010 +01000 +00100 +10000 +00001 +00100 +10000 +01000 +00010 +00100 +00001 +10000 +00100 +00001 +, // measure 91 +00100 +10000 +00001 +00010 +00100 +01000 +10000 +01000 +00100 +00000 +10100 +00000 +10001 +00000 +00101 +00000 +, // measure 92 +10000 +00001 +00100 +00010 +00001 +00100 +10000 +00001 +00100 +10000 +01000 +00100 +10000 +00010 +00100 +00001 +, // measure 93 +00100 +00010 +01000 +00100 +10000 +00100 +01000 +00100 +10000 +00010 +00100 +00001 +00100 +00010 +00001 +00010 +, // measure 94 +00100 +01000 +00001 +00100 +10000 +00010 +01000 +00100 +01000 +00010 +00100 +00001 +10000 +00100 +01000 +00010 +, // measure 95 +10000 +00000 +00001 +00000 +10000 +00000 +00001 +00000 +01000 +00000 +00010 +00000 +01000 +00000 +00010 +00000 +00100 +00000 +00001 +00000 +00100 +00000 +00001 +00000 +10000 +00010 +00000 +00000 +00000 +00000 +00000 +00000 +, // measure 96 +02020 +00000 +00000 +00000 +, // measure 97 +00000 +00000 +00000 +00000 +00000 +03030 +00000 +00000 +; + +//---------------pump-single - Vin.il---------------- +#NOTEDATA:; +#STEPSTYPE:pump-single; +#DESCRIPTION:Vin.il; +#CHARTSTYLE:Pad; +#DIFFICULTY:Hard; +#METER:16; +#RADARVALUES:1.000,1.000,0.473,0.395,0.612,829.000,61.000,51.000,0.000,0.000,0.000,0.000,0.000,1.000,1.000,0.473,0.395,0.612,829.000,61.000,51.000,0.000,0.000,0.000,0.000,0.000; +#CREDIT:Vin.il; +#OFFSET:-0.125000; +#BPMS:0.000000=181.699997 +; +#STOPS:; +#DELAYS:; +#WARPS:; +#TIMESIGNATURES:0.000000=4=4 +; +#TICKCOUNTS:0.000000=4 +,384.000000=8 +; +#COMBOS:0.000000=1 +; +#SPEEDS:0.000000=1.000000=0.000000=0 +,46.979168=0.000000=0.000000=0 +,47.000000=1.000000=1.000000=0 +; +#SCROLLS:0.000000=1.000000 +,304.000000=0.500000 +,318.000000=1.000000 +,384.000000=0.062500 +; +#FAKES:; +#LABELS:0.000000=Song Start +; +#ATTACKS: +; +#NOTES: +// measure 0 +00000 +00000 +00000 +00000 +, // measure 1 +00000 +00000 +00000 +00000 +, // measure 2 +00000 +00000 +00000 +00000 +, // measure 3 +00000 +00000 +00000 +00000 +, // measure 4 +10000 +00100 +10100 +00000 +00001 +00100 +00010 +01000 +, // measure 5 +00001 +00100 +00101 +00000 +10000 +00100 +01000 +00010 +, // measure 6 +01000 +00100 +01100 +00000 +00010 +00100 +00001 +10000 +, // measure 7 +00010 +00100 +00000 +00100 +00010 +01000 +00200 +00300 +, // measure 8 +10000 +00001 +00101 +00000 +00001 +00100 +00010 +00100 +, // measure 9 +00001 +10000 +10100 +00000 +10000 +00100 +01000 +00100 +, // measure 10 +01000 +00010 +00110 +00000 +00010 +00100 +00001 +00100 +, // measure 11 +00110 +00000 +00010 +00000 +01010 +00000 +01000 +00000 +00100 +10000 +00100 +10000 +00002 +00000 +00003 +00000 +, // measure 12 +00001 +00100 +00001 +10000 +00000 +00100 +10000 +00010 +, // measure 13 +00100 +00000 +00001 +00000 +00000 +00000 +00001 +00100 +00001 +00000 +01000 +00000 +00010 +00000 +00100 +00000 +, // measure 14 +00010 +00100 +00010 +10000 +00000 +00100 +01000 +00001 +, // measure 15 +00100 +00010 +00000 +00010 +10000 +00100 +10000 +00000 +, // measure 16 +00001 +00100 +00001 +10000 +00100 +01000 +00010 +00100 +, // measure 17 +00001 +00000 +10000 +00000 +00000 +00000 +00100 +01000 +00100 +00000 +01000 +00000 +00001 +00000 +00100 +00000 +, // measure 18 +00010 +00100 +00010 +01000 +00100 +10000 +00001 +00100 +, // measure 19 +00010 +00000 +01000 +00000 +00100 +00000 +00010 +00000 +00001 +00100 +00001 +00000 +10000 +00100 +10000 +00000 +, // measure 20 +00010 +00000 +00100 +00010 +00100 +00000 +00001 +00000 +00100 +00000 +00001 +00000 +10000 +00000 +00100 +00000 +, // measure 21 +01000 +00000 +00010 +00000 +00000 +00000 +00100 +00000 +00001 +00000 +10000 +00000 +00100 +01000 +00100 +01000 +, // measure 22 +00001 +00000 +00100 +00001 +00100 +00000 +00010 +00000 +00100 +00000 +00010 +00000 +01000 +00000 +00100 +00000 +, // measure 23 +10000 +00000 +00001 +00000 +00000 +00000 +00100 +00000 +00010 +00000 +01000 +00000 +00100 +10000 +00100 +10000 +, // measure 24 +00001 +00000 +00100 +00001 +00100 +00000 +00010 +00000 +01000 +00000 +00100 +10000 +00100 +00000 +10000 +00000 +, // measure 25 +00001 +00000 +00100 +00000 +00000 +00000 +00010 +00100 +00010 +00000 +01000 +00000 +00100 +00000 +00100 +00000 +, // measure 26 +10000 +00000 +00100 +10000 +00100 +00000 +01000 +00000 +00010 +00000 +00100 +00001 +00100 +00000 +00010 +00000 +, // measure 27 +01000 +00100 +01000 +00000 +00010 +00100 +00010 +00000 +10000 +00001 +10000 +00001 +10000 +00000 +00000 +00000 +, // measure 28 +00100 +00000 +10000 +00000 +00100 +00000 +01000 +00000 +00001 +00000 +00100 +00000 +00010 +00000 +01000 +00100 +, // measure 29 +01000 +00000 +00000 +00100 +10000 +00000 +00001 +00000 +00100 +00000 +00001 +00000 +01000 +00010 +01000 +00010 +, // measure 30 +01000 +00000 +00100 +00000 +10000 +00100 +10000 +00000 +00010 +00100 +00001 +10000 +00010 +00000 +01000 +00000 +, // measure 31 +00100 +10000 +00010 +01000 +00001 +00001 +10000 +10000 +, // measure 32 +10001 +00000 +00001 +00100 +00010 +00000 +01000 +00000 +00100 +00000 +10000 +00000 +00001 +00000 +00100 +00010 +, // measure 33 +01000 +00000 +00000 +00100 +01000 +00000 +00010 +00000 +00100 +00000 +00001 +00000 +10000 +00010 +10000 +00010 +, // measure 34 +10000 +00000 +00000 +00000 +00100 +00000 +01000 +00000 +00001 +00100 +00001 +00100 +00001 +00000 +10000 +00000 +, // measure 35 +00100 +01000 +00010 +00000 +00100 +00010 +01000 +00000 +00100 +10000 +00100 +10000 +00001 +00100 +00001 +00100 +, // measure 36 +00010 +00100 +00010 +02000 +03000 +00100 +01000 +10000 +, // measure 37 +01000 +00100 +10000 +00001 +00100 +00001 +01001 +00000 +, // measure 38 +10010 +20000 +30000 +00002 +00003 +00200 +00300 +00100 +, // measure 39 +00010 +01000 +00010 +01000 +00100 +00000 +10000 +00000 +00001 +00000 +00100 +00000 +00010 +01000 +00010 +01000 +, // measure 40 +00001 +00100 +00001 +20000 +30000 +00100 +10000 +01000 +, // measure 41 +10000 +00100 +01000 +00010 +00100 +00010 +10010 +00000 +, // measure 42 +01001 +02000 +03000 +00020 +00030 +00200 +00300 +00100 +, // measure 43 +00001 +10000 +00001 +10000 +00010 +01000 +00010 +01000 +00100 +00000 +00000 +10000 +00000 +00100 +00000 +01000 +, // measure 44 +00001 +00000 +00100 +00000 +00001 +00000 +01001 +00000 +01000 +00000 +00010 +00000 +01010 +00000 +00010 +01000 +, // measure 45 +00100 +00000 +00000 +10000 +00100 +00000 +00100 +00000 +01001 +00000 +00001 +00000 +00100 +00010 +00100 +00010 +, // measure 46 +01000 +00000 +00000 +00000 +00100 +00000 +10000 +00000 +01000 +00100 +01000 +00100 +00010 +00000 +00100 +00000 +, // measure 47 +00001 +00001 +01001 +01000 +01010 +00010 +00110 +00100 +, // measure 48 +10001 +00000 +00001 +00100 +00001 +00000 +10000 +00000 +10010 +00000 +10000 +00100 +10000 +00000 +00001 +00100 +, // measure 49 +00001 +00000 +00000 +00100 +00010 +00000 +01000 +00000 +01010 +00000 +01000 +00000 +00100 +10000 +00100 +10000 +, // measure 50 +00001 +00000 +00000 +00000 +00100 +00000 +00001 +00000 +01000 +00010 +00100 +00000 +00001 +00000 +10000 +00000 +, // measure 51 +00010 +00100 +00010 +00100 +00010 +00100 +00010 +00000 +01000 +00100 +01000 +00100 +01000 +00100 +01000 +00000 +, // measure 52 +01010 +00010 +00110 +00010 +10010 +00010 +01010 +00010 +, // measure 53 +01010 +01000 +01100 +01000 +01001 +01000 +01010 +01000 +, // measure 54 +10001 +10000 +10100 +10000 +10010 +10000 +10001 +10000 +, // measure 55 +10001 +00001 +00101 +00001 +01001 +00001 +10001 +00001 +, // measure 56 +01001 +00000 +00001 +01000 +00001 +00000 +10000 +00000 +00001 +00000 +10000 +00010 +10000 +00000 +00010 +00000 +, // measure 57 +01000 +00000 +00001 +00100 +00001 +00000 +01000 +00000 +00010 +00000 +10000 +00100 +10000 +00000 +00010 +00000 +, // measure 58 +00100 +00000 +00001 +01000 +00100 +00000 +10000 +00000 +00010 +00000 +10000 +00010 +00100 +00000 +00001 +00000 +, // measure 59 +02000 +03000 +00002 +00003 +00200 +00300 +00002 +00003 +02000 +03000 +00200 +00300 +20000 +30000 +00020 +00030 +, // measure 60 +10000 +00000 +00100 +01000 +00100 +01000 +00100 +01000 +00100 +00000 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 61 +10000 +00000 +00010 +00100 +00010 +00100 +00010 +00100 +00010 +00000 +01000 +00001 +01000 +00001 +01000 +00001 +, // measure 62 +01000 +00000 +00010 +10000 +00010 +10000 +00010 +10000 +00010 +00000 +01000 +00010 +01000 +00010 +01000 +00010 +, // measure 63 +02000 +03000 +00002 +00003 +00200 +00300 +00020 +00030 +20000 +30000 +00200 +00300 +02000 +03000 +00002 +00003 +, // measure 64 +01000 +00000 +00100 +10000 +00100 +10000 +00100 +10000 +00100 +00000 +01000 +00010 +01000 +00010 +01000 +00010 +, // measure 65 +01000 +00000 +00001 +00100 +00001 +00100 +00001 +00100 +00001 +00000 +10000 +00010 +10000 +00010 +10000 +00010 +, // measure 66 +10000 +00000 +00001 +01000 +00001 +01000 +00001 +01000 +00001 +00000 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 67 +20000 +30000 +00020 +00030 +00200 +00300 +00002 +00003 +02000 +03000 +00200 +00300 +20000 +30000 +00020 +00030 +, // measure 68 +01000 +00000 +00100 +00000 +01100 +00000 +00100 +01000 +00001 +00000 +00100 +00000 +00001 +00000 +10000 +00000 +, // measure 69 +00100 +00000 +01000 +00000 +01000 +00000 +00010 +00100 +00001 +00000 +01000 +00000 +00100 +00000 +00100 +00000 +, // measure 70 +10000 +00000 +00100 +00000 +10100 +00000 +00100 +10000 +00010 +00000 +00100 +00000 +00001 +00000 +01000 +00000 +, // measure 71 +00001 +00000 +00100 +00000 +00100 +00000 +00010 +01000 +00100 +00000 +10000 +00000 +00001 +00000 +00001 +00000 +, // measure 72 +00100 +00000 +00010 +00000 +00110 +00000 +00010 +00100 +00001 +00000 +01000 +00000 +00100 +00000 +10000 +00000 +, // measure 73 +00100 +00000 +01000 +00000 +01000 +00000 +00010 +00100 +00001 +00000 +01000 +00100 +10000 +00000 +10000 +00000 +, // measure 74 +00010 +00000 +00100 +00000 +00101 +00000 +00001 +01000 +00100 +00000 +10000 +00000 +00100 +00000 +01000 +00000 +, // measure 75 +00010 +00000 +00110 +00000 +00100 +00000 +00110 +00000 +00010 +01000 +00100 +01000 +00010 +00100 +00010 +01000 +, // measure 76 +00100 +00000 +10000 +00000 +00100 +00000 +02000 +00000 +00000 +00000 +00000 +00000 +00000 +03000 +00000 +00001 +, // measure 77 +00100 +00000 +00000 +00100 +00000 +00000 +00010 +00000 +02000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +, // measure 78 +00000 +00000 +03000 +00000 +00100 +00000 +01000 +00000 +00010 +00100 +00010 +00100 +00001 +01000 +00100 +20000 +, // measure 79 +00000 +00000 +30000 +00000 +00010 +00000 +00100 +00000 +00001 +00100 +00001 +00100 +00010 +10000 +00010 +10000 +, // measure 80 +00100 +00000 +01000 +00000 +01001 +00000 +00001 +00000 +00100 +00000 +00010 +00000 +10010 +00000 +10000 +00100 +, // measure 81 +10000 +00000 +00001 +00100 +00001 +00000 +01000 +00000 +00020 +00000 +00000 +00030 +00100 +00000 +00000 +00000 +, // measure 82 +00002 +00000 +00000 +00003 +00100 +00000 +00010 +00000 +01000 +00100 +10000 +00000 +00010 +00000 +00200 +00000 +, // measure 83 +00000 +00300 +00001 +00001 +10100 +10000 +00101 +00001 +, // measure 84 +00100 +00000 +00001 +00000 +01001 +00000 +01000 +00000 +00100 +00000 +10000 +00000 +10010 +00000 +00010 +00100 +, // measure 85 +00010 +00000 +01000 +00100 +01000 +00000 +00001 +00000 +20000 +00000 +00000 +30000 +00100 +00000 +00000 +00000 +, // measure 86 +02000 +00000 +00000 +03000 +00100 +00000 +10000 +00000 +00001 +00100 +00010 +00000 +10000 +00000 +00100 +00000 +, // measure 87 +02000 +00000 +03000 +00000 +00010 +00000 +00100 +00000 +00010 +00000 +00000 +01001 +00000 +01000 +00001 +01000 +, // measure 88 +00001 +00000 +00100 +00010 +00100 +00000 +00001 +00000 +10000 +00000 +00100 +01000 +00100 +00000 +01000 +00000 +, // measure 89 +00010 +00000 +00100 +00001 +00100 +00000 +00010 +00000 +01000 +00000 +00100 +10000 +00100 +00000 +01000 +00000 +, // measure 90 +00002 +00100 +00000 +00100 +20003 +00100 +30020 +00100 +, // measure 91 +02030 +00100 +00000 +00100 +03020 +00100 +20030 +00100 +, // measure 92 +30001 +00001 +00101 +00100 +00110 +00010 +01010 +01000 +, // measure 93 +01100 +00100 +10100 +10000 +10010 +00010 +01010 +01000 +, // measure 94 +01001 +00000 +00001 +01000 +00001 +00000 +10000 +00010 +10000 +00000 +00010 +01000 +00010 +00000 +10000 +00001 +, // measure 95 +10000 +00010 +10000 +00010 +10000 +00010 +10000 +00010 +01000 +00001 +01000 +00001 +00100 +00000 +00000 +00000 +, // measure 96 +20002 +00000 +00000 +00000 +, // measure 97 +00000 +00000 +00000 +00000 +00000 +30003 +00000 +00000 +; diff --git a/Songs/StepMania 5/Springtime/spring.png b/Songs/StepMania 5/Springtime/spring.png new file mode 100644 index 0000000000..e8461064cf Binary files /dev/null and b/Songs/StepMania 5/Springtime/spring.png differ diff --git a/Songs/StepMania 5/Springtime/springbn.png b/Songs/StepMania 5/Springtime/springbn.png new file mode 100644 index 0000000000..bcdf81d128 Binary files /dev/null and b/Songs/StepMania 5/Springtime/springbn.png differ diff --git a/Songs/instructions.txt b/Songs/instructions.txt new file mode 100644 index 0000000000..e9236b0028 --- /dev/null +++ b/Songs/instructions.txt @@ -0,0 +1,8 @@ +[How to Install Songs] + +Songs are laid out based on the group that they are in. + +Songs\ : root folder + StepMania 5\ : group folder + MechaTribe Assault\ : song/simfile folder + *.png, *.mp3/*.ogg, *.sm/*.ssc/etc files \ No newline at end of file diff --git a/Themes/_fallback/BGAnimations/ScreenCredits overlay.lua b/Themes/_fallback/BGAnimations/ScreenCredits overlay.lua index 94591c70b1..e1a275011b 100644 --- a/Themes/_fallback/BGAnimations/ScreenCredits overlay.lua +++ b/Themes/_fallback/BGAnimations/ScreenCredits overlay.lua @@ -25,7 +25,8 @@ local ssc = { } local sm_ssc = { - "Jason Felds (wolfman2000)", + "Jason Felds (wolfman2000)", -- Timing Segments, Split Timing, optimization + "Thai Pangsakulyanont (theDtTvB)", -- BMS, Split Timing, optimization "Alberto Ramos (Daisuke Master)", "Jack Walstrom (FSX)", } @@ -39,9 +40,10 @@ local stepmania = { local contrib = { "Aldo Fregoso (Aldo_MX)", -- delays - "Chris Eldridge (kurisu)", -- dance-threepanel "cerbo", "cesarmades", -- pump/cmd* noteskins + "Chris Eldridge (kurisu)", -- dance-threepanel + "Christophe Goulet-LeBlanc (Kommisar)", "corec", -- various fixes "galopin", -- piu PlayStation2 usb mat support "gholms", -- automake 1.11 support @@ -49,8 +51,8 @@ local contrib = { "Kaox", -- pump/default noteskin "NitroX72", -- pump/frame noteskin "sy567", -- beginner helper fix - "Thai Pangsakulyanont (theDtTvB)", "v1toko", -- x-mode from StepNXA + "waiei", -- custom scoring fixes + Hybrid scoring } local thanks = { @@ -70,10 +72,11 @@ local thanks = { local shoutout = { "The Lua team", -- lua project lead or some shit. super nerdy but oh hell. - "Mojang", -- minecraft forever -freem + "Mojang AB", -- minecraft forever -freem "NAKET Coder", "Ciera Boyd", -- you bet your ass I'm putting my girlfriend in the credits --Image(), -- we should have some logos probably to look super pro + "#KBO", "You showed us... your ultimate dance", -- "Can't stop crying... buckets of tears!" } diff --git a/Themes/_fallback/BGAnimations/ScreenGameplay background.lua b/Themes/_fallback/BGAnimations/ScreenGameplay background.lua new file mode 100644 index 0000000000..989e15f73d --- /dev/null +++ b/Themes/_fallback/BGAnimations/ScreenGameplay background.lua @@ -0,0 +1 @@ +return Def.ActorFrame { Name="YOU_WISH_YOU_WERE_PLAYING_BEATMANIA_RIGHT_NOW" }; \ No newline at end of file diff --git a/Themes/_fallback/BGAnimations/ScreenGameplay background.redir b/Themes/_fallback/BGAnimations/ScreenGameplay background.redir deleted file mode 100644 index 04b2ead777..0000000000 --- a/Themes/_fallback/BGAnimations/ScreenGameplay background.redir +++ /dev/null @@ -1 +0,0 @@ -_blank \ No newline at end of file diff --git a/Themes/_fallback/BGAnimations/ScreenNameEntryTraditional underlay/default.lua b/Themes/_fallback/BGAnimations/ScreenNameEntryTraditional underlay/default.lua new file mode 100644 index 0000000000..66e7d7daa7 --- /dev/null +++ b/Themes/_fallback/BGAnimations/ScreenNameEntryTraditional underlay/default.lua @@ -0,0 +1,289 @@ +function MakeScoreList(StagesAgo) + local c; + local Stats; + local PlayerStats = { } + local children = { + LoadActor( "difficulty cap 9x1" ) .. { + Name="DifficultyP1"; + InitCommand = cmd(x,-66;pause;halign,1); + OnCommand=cmd(zoomx,0;sleep,0.3;bounceend,0.3;zoomx,1); + OffCommand=cmd(bouncebegin,0.1;zoomx,0); + }; + LoadActor( "difficulty cap 9x1" ) .. { + Name="DifficultyP2"; + InitCommand = cmd(x,66;pause;halign,1;zoomx,0); + OnCommand=cmd(zoomx,0;sleep,0.3;bounceend,0.3;zoomx,-1); + OffCommand=cmd(bouncebegin,0.1;zoomx,0); + }; + LoadActor( "banner mask" ) .. { + Name="BannerMask"; + InitCommand=cmd(clearzbuffer,true;zwrite,true;blend,"BlendMode_NoEffect"); + OnCommand=cmd(zoom,0;bounceend,0.3;zoom,1); + OffCommand=cmd(bouncebegin,0.3;zoom,0); + }; + Def.Sprite { + Name = "Banner"; + InitCommand = cmd(setsize,300,100;zoom,0.5;ztest,true); + OnCommand=cmd(zoom,0;bounceend,0.3;zoom,0.5); + OffCommand=cmd(bouncebegin,0.3;zoom,0); + }; + LoadActor( "banner frame" ) .. { + Name="BannerFrame"; + OnCommand=cmd(zoom,0;bounceend,0.3;zoom,1); + OffCommand=cmd(bouncebegin,0.3;zoom,0); + }; + + LoadActor( "side score frame" ) .. { + Name="ScoreFrameP1"; + InitCommand=cmd(); + OnCommand=cmd(x,-266;addx,-250;diffusealpha,1;decelerate,0.3;addx,250); + OffCommand=cmd(linear,0.3;addx,-150;diffusealpha,0); + }; + LoadActor( "side score frame" ) .. { + Name="ScoreFrameP2"; + InitCommand=cmd(zoomx,-1); + OnCommand=cmd(x,266;addx,250;diffusealpha,1;decelerate,0.3;addx,-250); + OffCommand=cmd(linear,0.3;addx,150;diffusealpha,0); + }; + + LoadFont( "Common Normal" ) .. { +-- LoadFont( "_regra bold 30px" ) .. { + Name="PlayerScoreP1"; + InitCommand=cmd(x,-135;diffuse,color("#fdf991");shadowlength,0;zoom,0.6); + OnCommand=cmd(x,-135;addx,50;zoom,0;diffusealpha,0;sleep,0.1;accelerate,0.3;addx,-50;diffusealpha,1;zoom,0.6); + OffCommand=cmd(linear,0.3;diffusealpha,0); + }; + LoadFont( "Common Normal" ) .. { +-- LoadFont( "_regra bold 30px" ) .. { + Name="PlayerScoreP2"; + InitCommand=cmd(x,135;diffuse,color("#abfe8e");shadowlength,0;zoom,0.6); + OnCommand=cmd(x,135;addx,-50;zoom,0;diffusealpha,0;sleep,0.1;accelerate,0.3;addx,50;diffusealpha,1;zoom,0.6); + OffCommand=cmd(linear,0.3;diffusealpha,0); + }; + + LoadFont( "Common Normal" ) .. { +-- LoadFont( "_regra bold 30px" ) .. { + Name="MachineBestP1"; + InitCommand=cmd(diffuse,color("#ffffff");shadowlength,0;zoom,0.5); + OnCommand=cmd(x,-250;addx,-250;diffusealpha,1;decelerate,0.3;addx,250); + OffCommand=cmd(linear,0.3;addx,-150;diffusealpha,0); + }; + LoadFont( "Common Normal" ) .. { +-- LoadFont( "_regra bold 30px" ) .. { + Name="MachineBestP2"; + InitCommand=cmd(diffuse,color("#ffffff");shadowlength,0;zoom,0.5); + OnCommand=cmd(x,250;addx,250;diffusealpha,1;decelerate,0.3;addx,-250); + OffCommand=cmd(linear,0.3;addx,150;diffusealpha,0); + }; + + }; + + return Def.ActorFrame { + children = children; + InitCommand = function(self) + c = self:GetChildren(); + c.PlayerScore = {}; + c.PlayerScore[PLAYER_1] = c.PlayerScoreP1; + c.PlayerScore[PLAYER_2] = c.PlayerScoreP2; + c.MachineBest = {}; + c.MachineBest[PLAYER_1] = c.MachineBestP1; + c.MachineBest[PLAYER_2] = c.MachineBestP2; + c.ScoreFrame = {}; + c.ScoreFrame[PLAYER_1] = c.ScoreFrameP1; + c.ScoreFrame[PLAYER_2] = c.ScoreFrameP2; + c.Difficulty = {}; + c.Difficulty[PLAYER_1] = c.DifficultyP1; + c.Difficulty[PLAYER_2] = c.DifficultyP2; + end; + + BeginCommand = function(self) + Stats = STATSMAN:GetPlayedStageStats(StagesAgo); + if not Stats then + self:visible(false); + return; + end; + self:visible(true); + + PlayerStats[PLAYER_1] = Stats:GetPlayerStageStats(PLAYER_1); + PlayerStats[PLAYER_2] = Stats:GetPlayerStageStats(PLAYER_2); + + local Current; + local CurrentPart = {} + if GAMESTATE:IsCourseMode() then + Current = GAMESTATE:GetCurrentCourse(); + CurrentPart[PLAYER_1] = GAMESTATE:GetCurrentTrail( PLAYER_1 ); + CurrentPart[PLAYER_2] = GAMESTATE:GetCurrentTrail( PLAYER_2 ); + else + Current = Stats:GetPlayedSongs()[1]; + CurrentPart[PLAYER_1] = PlayerStats[PLAYER_1]:GetPlayedSteps()[1]; + CurrentPart[PLAYER_2] = PlayerStats[PLAYER_2]:GetPlayedSteps()[1]; + end + assert(Current); + + local sBannerPath = Current:GetBannerPath() or THEME:GetPathG("Common","fallback banner"); + c.Banner:LoadBanner( sBannerPath ); + + for pn in ivalues(PlayerNumber) do + local visible = GAMESTATE:IsHumanPlayer(pn) and CurrentPart[pn] ~= nil; -- was present for this song + c.MachineBest[pn]:visible( visible ); + c.PlayerScore[pn]:visible( visible ); + c.ScoreFrame[pn]:visible( visible ); + c.Difficulty[pn]:visible( visible ); + + local MachineProfile = PROFILEMAN:GetMachineProfile(); + if visible then + assert(CurrentPart[pn]); + +-- c.Difficulty[pn]:SetDifficultyAndStepsTypeFrame( CurrentPart[pn] ); + + local hsl = MachineProfile:GetHighScoreList( Current, CurrentPart[pn] ); + assert( hsl ); + + -- Find the first high score that isn't one that we're entering now. + local HighScores = hsl:GetHighScores(); + local hs; + for h in ivalues(HighScores) do + if not hs and not h:IsFillInMarker() then + hs = h; + end + end + + if hs then + local fMachineScore = hs:GetPercentDP() or 0; + local sName = hs:GetName() or ""; + local sText = sName .. " " .. FormatPercentScore( fMachineScore ); + c.MachineBest[pn]:settext( sText ); + else + c.ScoreFrame[pn]:visible( false ); + end + + local fPlayerScore = PlayerStats[pn]:GetPercentDancePoints(); + local sText = FormatPercentScore( fPlayerScore ); + c.PlayerScore[pn]:settext( sText ); + local colors = { + [PLAYER_1] = color("#fdf991"), + [PLAYER_2] = color("#abfe8e"), + }; + if Stats:PlayerHasHighScore(pn) then + colors = { + [PLAYER_1] = color("#feef01"), + [PLAYER_2] = color("#0ffc03"), + }; + end + c.PlayerScore[pn]:diffuse(colors[pn]); + end; + end; + end; + }; +end + +local children = { + LoadActor( "center frame" ) .. { + InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y+9); + OnCommand=cmd(fadetop,0.3; croptop,1; linear,0.5; croptop,-0.3); + OffCommand=cmd(linear,0.5; croptop,1); + }; + LoadActor( "line" ) .. { + InitCommand=cmd(x,SCREEN_CENTER_X;SetWidth,336;y,SCREEN_CENTER_Y+65;fadeleft,0.3; faderight,0.3); + OnCommand=cmd(cropleft,.5;cropright,.5; + sleep,0.2; + linear,0.3; + cropleft,-.2;cropright,-.2); + + OffCommand=cmd(linear,0.3;cropleft,.5;cropright,.5); + }; +}; + +for i = 1,5 do + children[#children+1] = + MakeScoreList(i) .. { + Name="Row" .. tostring(i); + InitCommand=cmd(x,SCREEN_CENTER_X); + }; +end + +--[[ children[#children+1] = + LoadActor( THEME:GetPathB("","_shared underlay") ) .. { OnCommand=cmd(); }; --]] + +children[#children+1] = LoadActor( "keyboard" ) .. { + InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y+80); + BeginCommand = cmd(visible,SCREENMAN:GetTopScreen():GetAnyEntering()); +}; + +for pn in ivalues(PlayerNumber) do + local FrameX = pn == PLAYER_1 and (SCREEN_CENTER_X-265) or (SCREEN_CENTER_X+267); + local P1 = pn == PLAYER_1 and 1 or -1; + children[#children+1] = LoadActor( "name frame" ) .. { + InitCommand=cmd(y,SCREEN_CENTER_Y+119; + zoomx,pn == PLAYER_1 and 1.0 or -1.0); + BeginCommand=cmd(visible,SCREENMAN:GetTopScreen():GetEnteringName(pn)); + OnCommand=cmd(finishtweening;x,FrameX;addx,-200*P1;zoom,0;bounceend,0.3;zoom,1;addx,200*P1); + OffCommand=cmd(stoptweening;bouncebegin,0.3;zoom,0;addx,-200*P1); + }; + + children[#children+1] = LoadFont( "Common Normal" ) .. { +-- children[#children+1] = LoadFont( "_regra bold 30px" ) .. { + Name="PlayerText"; + InitCommand=cmd(x,pn == PLAYER_1 and (SCREEN_CENTER_X-WideScale(310,330)) or (SCREEN_CENTER_X+WideScale(198,204)); + halign,0; + y,SCREEN_CENTER_Y+115;shadowlength,0;zoom,1); + BeginCommand=cmd(visible,SCREENMAN:GetTopScreen():GetEnteringName(pn)); + OnCommand=cmd(finishtweening;diffusealpha,0;sleep,0.1;linear,0.3;diffusealpha,1); + OffCommand=cmd(stoptweening;bouncebegin,0.3;zoom,0;addx,-200*P1); + EntryChangedMessageCommand=function(self,params) + if params.PlayerNumber ~= pn then + return; + end; + self:settext( params.Text ); + end; + }; +end; + +return Def.ActorFrame { + children = children; + + BeginCommand = function(self) + local StagesPlayed = STATSMAN:GetStagesPlayed(); + local c = self:GetChildren(); + + local fYCenter = SCREEN_CENTER_Y-60; + local fYMinSpacing = 44; + local fYMaxSpacing = 70; + local fYSpacing = scale(StagesPlayed, 4, 5, fYMaxSpacing, fYMinSpacing); + fYSpacing = clamp(fYSpacing, fYMinSpacing, fYMaxSpacing); + fYSpacing = fYSpacing + math.mod(fYSpacing, 2); -- even + fYSpacing = -fYSpacing; + + local fYStart = fYSpacing*(StagesPlayed-1)/2; + local fYEnd = -fYSpacing*(StagesPlayed-1)/2; + for i = 1,StagesPlayed do + local Name = "Row" .. tostring(i); + local row = c[Name]; + assert(row); + local fY = fYCenter + fYEnd + (i-1)*fYSpacing; + row:y( fY ); + end + + local Timer = SCREENMAN:GetTopScreen():GetChild("Timer"); + if not SCREENMAN:GetTopScreen():GetAnyEntering() then + Timer:setseconds(5); + Timer:silent(true); + else + Timer:setseconds(25); + Timer:silent(false); + end + end; + + OnCommand = function(self) + local StagesPlayed = STATSMAN:GetStagesPlayed(); + local c = self:GetChildren(); + for i = 1,StagesPlayed do + local Name = "Row" .. tostring(i); + local row = c[Name]; + assert(row); + + row:hibernate(0.3+(i/StagesPlayed)*0.3); + end + end; +}; + diff --git a/Themes/_fallback/BGAnimations/ScreenNameEntryTraditional underlay/keyboard.lua b/Themes/_fallback/BGAnimations/ScreenNameEntryTraditional underlay/keyboard.lua new file mode 100644 index 0000000000..08852dbaba --- /dev/null +++ b/Themes/_fallback/BGAnimations/ScreenNameEntryTraditional underlay/keyboard.lua @@ -0,0 +1,285 @@ +local function distance( x1, y1, x2, y2 ) + return math.pow( math.pow(x1-x2, 2) + math.pow(y1-y2, 2), 0.5 ); +end + +local children = { +}; + +local Letters = { + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", + "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "?", "!", + "BACK", "ENTER" +}; + +local LetterIndexes = { }; +for i, l in ipairs(Letters) do + LetterIndexes[l] = i; +end + +local MapNameToLetter = {}; +local MapLetterToName = {}; +local letter = LoadFont( "Common Normal" ) .. { +-- local letter = LoadFont( "_regra bold 30px" ) .. { + InitCommand=cmd(zoom,0.8;shadowlength,0); + PulseCommand = function(self) + self:finishtweening(); + local z = self:GetZoomX(); + (cmd(accelerate,0.15;zoom,1.2;decelerate,0.15;zoom,z))(self); + end; +}; + +for l in ivalues(Letters) do + local Name = "letter " .. l; + MapNameToLetter[Name] = l; + MapLetterToName[l] = Name; + children[#children+1] = letter .. { + Name = Name; + Text = l; + }; + if l == "BACK" or l == "ENTER" then + children[#children].File = THEME:GetPathF("", "Common Normal"); +-- children[#children].File = THEME:GetPathF("", "_venacti 26px normal"); + end; +end; +--[[ children[#children+1] = LoadActor( THEME:GetPathS(Var "LoadingScreen", "type key") ) .. { Name = "Type"; SupportPan = true; } +children[#children+1] = LoadActor( THEME:GetPathS(Var "LoadingScreen", "back") ) .. { Name = "Back"; SupportPan = true; } +children[#children+1] = LoadActor( THEME:GetPathS(Var "LoadingScreen", "enter") ) .. { Name = "Enter"; SupportPan = true; } +children[#children+1] = LoadActor( THEME:GetPathS(Var "LoadingScreen", "move cursor") ) .. { Name = "Move"; SupportPan = true; } --]] +children[#children+1] = LoadActor( THEME:GetPathS("Common", "value") ) .. { Name = "Type"; SupportPan = true; } +children[#children+1] = LoadActor( THEME:GetPathS("Common", "cancel") ) .. { Name = "Back"; SupportPan = true; } +children[#children+1] = LoadActor( THEME:GetPathS("Common", "start") ).. { Name = "Enter"; SupportPan = true; } +children[#children+1] = LoadActor( THEME:GetPathS("MusicWheel", "change") ) .. { Name = "Move"; SupportPan = true; } + +local CursorFiles = { + [PLAYER_1] = "Cursor P1", + [PLAYER_2] = "Cursor P2" +}; + +for pn in ivalues(PlayerNumber) do + children[#children+1] = LoadActor( THEME:GetPathG("_frame", "1D"), + { 4/10, 2/10, 4/10 }, + LoadActor(CursorFiles[pn]) + ) .. { + Name = CursorFiles[pn]; + BeginCommand = cmd(visible,SCREENMAN:GetTopScreen():GetEnteringName(pn)); + OnCommand = cmd( + zoom,0; + rotationz,-360*2; + sleep,0.55; + decelerate,0.5; + zoom,1; + rotationz,0; + ); + OffCommand = cmd(sleep,0.3;queuecommand,"TweenOff"); + PlayerFinishedMessageCommand = function(self,param) + if param.PlayerNumber ~= pn then return end + self:playcommand("TweenOff" ); + end; + TweenOffCommand = function(self,param) + (cmd( + accelerate,0.25; + zoomx,0; + ))(self); + end; + }; +end + +local c; +local Keys = {}; +local Selection = {}; +local PlayerX = {}; +local PlayerY = {}; +return Def.ActorFrame { + children = children; + BeginCommand = function(self) + c = self:GetChildren(); + c.Cursors = {}; + c.Cursors[PLAYER_1] = c["Cursor P1"]; + c.Cursors[PLAYER_2] = c["Cursor P2"]; + + for l in ivalues(Letters) do + local Name = MapLetterToName[l]; + assert(Name); + Keys[l] = { + Text = c[Name]; + Width = c[Name]:GetWidth(); + Height = c[Name]:GetHeight(); + }; + assert(c[Name], Name); + end; + + -- Position letters. + local RowWidths = {}; + local fX = 0; + local fXPadding = 4; + local fY = 0; + local iRow = 1; + for l in ivalues(Letters) do + if l == "O" or l == "0" or l == "BACK" + then + fX = 0; + fY = fY + 30; + iRow = iRow + 1; + end; + Keys[l].Row = iRow; + Keys[l].Text:x(fX + Keys[l].Width/2); + Keys[l].Text:y(fY + Keys[l].Height/2); + fX = fX + Keys[l].Width; + RowWidths[iRow] = fX; + fX = fX + fXPadding; + end; + for l in ivalues(Letters) do + local iRow = Keys[l].Row; + Keys[l].Text:addx(-RowWidths[iRow]/2); + end; + + Keys["BACK"].Text:x(-140); + Keys["ENTER"].Text:x(140); + + for pn in ivalues(PlayerNumber) do + local sName = SCREENMAN:GetTopScreen():GetSelection(pn); + local DefaultKey = "A" + if #sName > 0 then + DefaultKey = "ENTER" + end + + self:playcommand("SelectKey", { Key = DefaultKey, PlayerNumber = pn }); + c.Cursors[pn]:finishtweening(); + end + end; + + CodeMessageCommand = function(self, param) + local pn = param.PlayerNumber; + if not SCREENMAN:GetTopScreen():GetAnyStillEntering() and param.Name == "Enter" then + if SCREENMAN:GetTopScreen():Finish(pn) then + c.Enter:play(); + end + return; + end + if SCREENMAN:GetTopScreen():GetFinalized( pn ) then + return; + end + + if param.Name == "Left" or param.Name == "Right" then + local iDir = param.Name == "Left" and -1 or 1; + + local idx = LetterIndexes[Selection[pn]]; + idx = idx + iDir; + idx = math.mod(idx+#Letters-1, #Letters)+1; + self:playcommand("SelectKey", { Key = Letters[idx], PlayerNumber = pn }); + c.Move:playforplayer(pn); + return; + end + + if param.Name == "JumpToEnter" then + self:playcommand("SelectKey", { Key = "ENTER", PlayerNumber = pn }); + c.Move:playforplayer(pn); + return; + end + if param.Name == "Backspace" then + if SCREENMAN:GetTopScreen():Backspace(pn) then + c.Back:playforplayer(pn); + end + return; + end + + if param.Name == "NextRow" or param.Name == "PrevRow" then + local iDir = param.Name == "PrevRow" and -1 or 1; + local idx = LetterIndexes[Selection[pn]]; + local iRow = Keys[Selection[pn]].Row; + iRow = iRow + iDir; + iRow = math.mod(iRow+4-1, 4)+1; + + local NearestLetter + local NearestLetterDistance + for l in ivalues(Letters) do + if iRow == Keys[l].Row then + local Text = Keys[l].Text; + + local fDist = distance( PlayerX[pn], PlayerY[pn], + Text:GetX(), Text:GetY() ); + if not NearestLetterDistance or fDist < NearestLetterDistance then + NearestLetterDistance = fDist; + NearestLetter = l; + end + end + end + assert( NearestLetter ); + self:playcommand("SelectKey", { Key = NearestLetter, PlayerNumber = pn, NoStore = true }); + + c.Move:playforplayer(pn); + + return; + end + + if param.Name == "Enter" then + if Selection[pn] == "BACK" then + if SCREENMAN:GetTopScreen():Backspace(pn) then + Keys[Selection[pn]].Text:playcommand( "Pulse" ); + c.Back:playforplayer(pn); + end + elseif Selection[pn] == "ENTER" then + if SCREENMAN:GetTopScreen():Finish(pn) then + Keys[Selection[pn]].Text:playcommand( "Pulse" ); + c.Enter:playforplayer(pn); + end + else + local key = Selection[pn]; -- EnterKey may change this + if SCREENMAN:GetTopScreen():EnterKey(pn, key) then + Keys[key].Text:playcommand( "Pulse" ); + c.Type:playforplayer(pn); + end + end + end + end; + + SelectKeyMessageCommand = function(self, param) + local key = param.Key; + local pn = param.PlayerNumber; + if not Keys[key] then return end + + Selection[pn] = key; + c.Cursors[pn]:stoptweening(); + c.Cursors[pn]:playcommand( "SetSize", { Width=Keys[key].Width+6; tween=cmd(stoptweening;linear,0.10); } ); + c.Cursors[pn]:x( Keys[key].Text:GetX() ); + c.Cursors[pn]:y( Keys[key].Text:GetY() ); + if not param.NoStore then + PlayerX[pn] = Keys[key].Text:GetX(); + PlayerY[pn] = Keys[key].Text:GetY(); + end + + -- SCREENMAN:GetTopScreen():EnterKey(PLAYER_2,"x"); + end; + MenuTimerExpiredMessageCommand = function(self, param) + for pn in ivalues(PlayerNumber) do + SCREENMAN:GetTopScreen():Finish(pn); + end + c.Enter:play(); + end; + + OnCommand = function(self, param) + for key in ivalues(Letters) do + local fDist = distance( Keys[key].Text:GetX(), Keys[key].Text:GetY(), 0, 100 ); + + local f = cmd( + diffusealpha,0;zoom,0; + sleep,0.25 + (fDist / 400); + decelerate,0.5; + diffusealpha,1;zoom,0.8); + f(Keys[key].Text); + end + end; + + OffCommand = function(self, param) + for key in ivalues(Letters) do + local fDist = distance( Keys[key].Text:GetX(), Keys[key].Text:GetY(), 0, 100 ); + + local f = cmd( + sleep,0.0 + (fDist / 400); + decelerate,0.5; + diffusealpha,0;zoom,0); + f(Keys[key].Text); + end + end; +}; diff --git a/Themes/_fallback/BGAnimations/ScreenSystemLayer aux.lua b/Themes/_fallback/BGAnimations/ScreenSystemLayer aux.lua index 18bd636e50..cba3909a14 100644 --- a/Themes/_fallback/BGAnimations/ScreenSystemLayer aux.lua +++ b/Themes/_fallback/BGAnimations/ScreenSystemLayer aux.lua @@ -1,49 +1,2 @@ -local function CreditsText( pn ) - function update(self) - local str = ScreenSystemLayerHelpers.GetCreditsMessage(pn); - self:settext(str); - end - - function UpdateVisible(self) - local screen = SCREENMAN:GetTopScreen(); - local bShow = true; - if screen then - local sClass = screen:GetName(); - bShow = THEME:GetMetric( sClass, "ShowCreditDisplay" ); - end - - self:visible( bShow ); - end - - local text = LoadFont(Var "LoadingScreen","credits") .. { - InitCommand=function(self) - self:name("Credits" .. PlayerNumberToString(pn)) - ActorUtil.LoadAllCommandsAndSetXY(self,Var "LoadingScreen"); - end; - UpdateTextCommand=function(self) - local str = ScreenSystemLayerHelpers.GetCreditsMessage(pn); - self:settext(str); - end; - UpdateVisibleCommand=function(self) - local screen = SCREENMAN:GetTopScreen(); - local bShow = true; - if screen then - local sClass = screen:GetName(); - bShow = THEME:GetMetric( sClass, "ShowCreditDisplay" ); - end - - self:visible( bShow ); - end; ---[[ RefreshCreditTextMessageCommand=update; - CoinInsertedMessageCommand=update; - PlayerJoinedMessageCommand=update; - ScreenChangedMessageCommand=UpdateVisible; --]] - }; - return text; -end - -local t = Def.ActorFrame { - CreditsText( PLAYER_1 ); - CreditsText( PLAYER_2 ); -}; +local t = Def.ActorFrame {}; return t; \ No newline at end of file diff --git a/Themes/_fallback/BGAnimations/ScreenSystemLayer overlay/default.lua b/Themes/_fallback/BGAnimations/ScreenSystemLayer overlay/default.lua index 2dcdf564dd..a23015892f 100644 --- a/Themes/_fallback/BGAnimations/ScreenSystemLayer overlay/default.lua +++ b/Themes/_fallback/BGAnimations/ScreenSystemLayer overlay/default.lua @@ -1,4 +1,50 @@ +local function CreditsText( pn ) + function update(self) + local str = ScreenSystemLayerHelpers.GetCreditsMessage(pn); + self:settext(str); + end + + function UpdateVisible(self) + local screen = SCREENMAN:GetTopScreen(); + local bShow = true; + if screen then + local sClass = screen:GetName(); + bShow = THEME:GetMetric( sClass, "ShowCreditDisplay" ); + end + + self:visible( bShow ); + end + + local text = LoadFont(Var "LoadingScreen","credits") .. { + InitCommand=function(self) + self:name("Credits" .. PlayerNumberToString(pn)) + ActorUtil.LoadAllCommandsAndSetXY(self,Var "LoadingScreen"); + end; + UpdateTextCommand=function(self) + local str = ScreenSystemLayerHelpers.GetCreditsMessage(pn); + self:settext(str); + end; + UpdateVisibleCommand=function(self) + local screen = SCREENMAN:GetTopScreen(); + local bShow = true; + if screen then + local sClass = screen:GetName(); + bShow = THEME:GetMetric( sClass, "ShowCreditDisplay" ); + end + + self:visible( bShow ); + end; +--[[ RefreshCreditTextMessageCommand=update; + CoinInsertedMessageCommand=update; + PlayerJoinedMessageCommand=update; + ScreenChangedMessageCommand=UpdateVisible; --]] + }; + return text; +end; +-- local t = Def.ActorFrame { + CreditsText( PLAYER_1 ); + CreditsText( PLAYER_2 ); Def.ActorFrame { Def.Quad { InitCommand=cmd(zoomtowidth,SCREEN_WIDTH;zoomtoheight,30;horizalign,left;vertalign,top;y,SCREEN_TOP;diffuse,color("0,0,0,0")); diff --git a/Themes/_fallback/Fonts/ScreenReloadSongs LoadingText.redir b/Themes/_fallback/Fonts/InGameLoadingWindow LoadingText.redir similarity index 100% rename from Themes/_fallback/Fonts/ScreenReloadSongs LoadingText.redir rename to Themes/_fallback/Fonts/InGameLoadingWindow LoadingText.redir diff --git a/Themes/_fallback/Fonts/frutiger 24px [main-stroke] 16x16.png b/Themes/_fallback/Fonts/frutiger 24px [main-stroke] 16x16.png index 66f6fd79b3..cc9d1d62af 100644 Binary files a/Themes/_fallback/Fonts/frutiger 24px [main-stroke] 16x16.png and b/Themes/_fallback/Fonts/frutiger 24px [main-stroke] 16x16.png differ diff --git a/Themes/_fallback/Fonts/frutiger 24px [main] 16x16.png b/Themes/_fallback/Fonts/frutiger 24px [main] 16x16.png index 1963076070..bf737d6d3e 100644 Binary files a/Themes/_fallback/Fonts/frutiger 24px [main] 16x16.png and b/Themes/_fallback/Fonts/frutiger 24px [main] 16x16.png differ diff --git a/Themes/_fallback/Fonts/frutiger 24px [polish-stroke] 8x2.png b/Themes/_fallback/Fonts/frutiger 24px [polish-stroke] 8x2.png new file mode 100644 index 0000000000..fae305f37f Binary files /dev/null and b/Themes/_fallback/Fonts/frutiger 24px [polish-stroke] 8x2.png differ diff --git a/Themes/_fallback/Fonts/frutiger 24px [polish] 8x2.png b/Themes/_fallback/Fonts/frutiger 24px [polish] 8x2.png new file mode 100644 index 0000000000..0ed3c843c3 Binary files /dev/null and b/Themes/_fallback/Fonts/frutiger 24px [polish] 8x2.png differ diff --git a/Themes/_fallback/Fonts/frutiger 24px.ini b/Themes/_fallback/Fonts/frutiger 24px.ini index 702c8cd9cd..988bc39672 100644 --- a/Themes/_fallback/Fonts/frutiger 24px.ini +++ b/Themes/_fallback/Fonts/frutiger 24px.ini @@ -261,6 +261,7 @@ AdvanceExtraPixels=0 253=12 254=15 255=12 + [alt] 0=10 1=10 @@ -390,3 +391,28 @@ AdvanceExtraPixels=0 125=12 126=6 127=7 + +[polish] +Baseline=23 +Top=6 + +line 0=ĄĆĘŁŃŚŹŻ +line 1=ąćęłńśźż + +0=15 +1=10 +2=12 +3=12 +4=12 +5=12 +6=13 +7=13 + +8=11 +9=11 +10=11 +11=6 +12=11 +13=10 +14=10 +15=10 \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Common splash.png b/Themes/_fallback/Graphics/Common splash.png new file mode 100644 index 0000000000..2c365a3306 Binary files /dev/null and b/Themes/_fallback/Graphics/Common splash.png differ diff --git a/Themes/_fallback/Graphics/Progressbar Indeterminate.png b/Themes/_fallback/Graphics/Progressbar Indeterminate.png new file mode 100644 index 0000000000..c781e5d06e Binary files /dev/null and b/Themes/_fallback/Graphics/Progressbar Indeterminate.png differ diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index 1884302235..9f85bed459 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -372,7 +372,7 @@ MaxTextureResolution=Choose the maximum texture resolution. Setting this to any MenuTimer=When &oq;ON&cq;, menus have a time limit. Mines=Mines MoveRandomToEnd=Determines if courses with random songs should be placed at the end of the course select wheel. -MovieColorDepth=Choose the color depth of textures. 32 bit textures use more memory, but look nicer. +MovieColorDepth=Choose the color depth of movies. 32 bit textures use more memory, but look nicer. MusicWheelSwitchSpeed=Adjusts the speed of the music wheel. MusicWheelUsesSections=&oq;Always&cq; means sections in group + ABC; &oq;Never&cq; means no sections; &oq;Title Only&cq; shows sections in ABC order. Network Options=Connect to a server or change server options. @@ -656,6 +656,7 @@ Never=Never New=New NewEdit=-New Edit- No=No +NoAttacks=No Attacks NoHands=No Hands NoHolds=No Holds NoJumps=No Jumps @@ -707,7 +708,8 @@ Skip=Skip Skippy=Skippy Slow=Slow SN2=Supernova 2 -SongAttacks=Song Attacks +SongAttacks=Step Attacks +StepAttacks=Step Attacks Song BGAnimation=Song BGAnimation Song Bitmap=Song Bitmap Song Movie=Song Movie @@ -800,6 +802,7 @@ CelShadeModels=Cel-shaded Models Center Image=Center Image Chaos=Chaos Characters=Characters +Chart Name=Chart Name Chart Style=Chart Style Choose=Choose Clear Bookkeeping Data=Clear Bookkeeping Data @@ -807,13 +810,20 @@ Clear Machine Edits=Clear Machine Edits Clear Machine Stats=Clear Machine Scores Clear USB edits=Clear USB edits Clear area=Clear area +Clear clipboard=Clear clipboard CoinMode=Coin Mode CoinModeNoHome=Coin Mode CoinsPerCredit=Coins Per Credit Connection=Connection -Convert pause to beats=Convert pause to beats -Convert selection to pause=Convert selection to pause +Convert pause to beats=Convert stop to beats +Convert delay to beats=Convert delay to beats +Convert selection to attack=Convert selection to Attack +Convert selection to pause=Convert selection to stop +Convert selection to delay=Convert selection to delay +Convert selection to warp=Convert selection to Warp Segment +Convert selection to fake=Convert selection to Fake Segment Copy=Copy +Copy timing data=Copy timing data CourseSortOrder=Course Sort Create New=Create New Create New Course=Create New @@ -829,6 +839,8 @@ DelayedTextureDelete=Keep Textures In Memory Delete=Delete Delete beat and shift up=Delete beat and shift up Description=Description +Designate as Music Preview=Designate as Music Preview +Designate last second at current beat=Designate last second at current beat Difficulty=Difficulty Display BPM=Display BPM DisplayAspectRatio=Aspect Ratio @@ -867,6 +879,7 @@ Entry %d=Entry %d EventMode=Event Mode Exit=Exit Fail=Fail +Fakes=Fakes FastLoad=Fast\nLoad File1 Global BGAnimation=File1 Global BGAnimation File1 Global Movie=File1 Global Movie @@ -904,11 +917,13 @@ Insert=Insert Insert Credit=Insert Credit Insert beat and shift down=Insert beat and shift down Insert Entry=Insert Entry +Invert notes' player=Invert player notes (routine only) Jumps=Jumps Key Joy Mappings=Config Key/Joy Mappings Language=Language -Last beat hint=Last beat hint +Last second hint=Last second hint Layer=Layer +Lifts=Lifts LifeDifficulty=Life Difficulty LifeType=Life Type Low Meter=Low Meter @@ -921,6 +936,8 @@ MenuTimer=Menu Timer Meter=Meter Min BPM=Min Specified BPM Mines=Mines +Mirror Player 1 to 2=Mirror P1's notes to P2 (routine only) +Mirror Player 2 to 1=Mirror P2's notes to P1 (routine only) MoveRandomToEnd=Random At End More Options=More Options MovieColorDepth=Movie Color @@ -936,6 +953,7 @@ OsMountPlayer1=OS Mount Player1 OsMountPlayer2=OS Mount Player2 Paste at begin marker=Paste at begin marker Paste at current beat=Paste at current beat +Paste timing data=Paste timing data Persp=Persp Play current beat to end=Play current beat to end Play preview music=Play preview music @@ -971,7 +989,8 @@ Remove Change=Remove Change Rename=Rename Reset To Defaults=Reset Options To Default Values Revert from disk=Revert from disk -Revert to last save=Revert to last save +Revert to last save=Revert from cache +Rolls=Rolls Save=Save SaveScores=Save Scores SaveReplays=Save Replays @@ -1036,6 +1055,7 @@ Type=Type Turn=Turn Undo=Undo UseUnlockSystem=Unlock System +View steps data=View Steps Data VisualDelaySeconds=Visual Delay Voltage=Voltage Vsync=Wait For Vsync @@ -1216,6 +1236,7 @@ Write Profiles=Write Profiles off=off on=on or=or +Zoom In Camera=Zoom In Camera [ScreenEdit] %s notes=%s notes @@ -1228,7 +1249,7 @@ Enter a new Stop value.=Enter a new Stop value.\n\nType "0" to remove. Enter a new Delay value.=Enter a new Delay value.\n\nType "0" to remove. Enter a new Time Signature.=Enter a new time signature.\nUse the format "x/y".\nEnter the previous value to remove. Enter a new Tickcount value.=Enter a new Tickcount value.\n\nEnter the previous value to remove. -Enter a new Combo value.=Enter a new Combo value.\n\nEnter the previous value to remove. +Enter a new Combo value.=Enter a new Combo value.\nUse the format "x/y".\nEnter the previous value to remove. Enter a new Label value.=Enter a name for this section of the chart.\n\nEnter a previously used label to remove. Enter a new Warp value.=Enter the number of beats you will warp over.\n\nType "0" to remove this segment. Enter a new Speed percent value.=Enter the ratio for speed scrolling.\nEnter the previous value to remove.\n1 is the default scroll. @@ -1242,11 +1263,12 @@ Enter a new artist.=Enter a new artist. Enter a new genre.=Enter a new genre. Enter a new credit.=Enter a new credit. Enter a new description.=Enter a new description. +Enter a new chart name.=Enter the name/title of this chart. Enter a new chart style.=Enter a new chart style (e.g. "Pad", "Keyboard"). Enter a new meter.=Enter the difficulty rating for this chart. Enter the author who made this step pattern.=Enter the author who made this step pattern. Enter the offset for the song.=Enter the beat 0 offset for the song. -Enter a new last beat hint.=Enter a new last beat hint. +Enter a new last second hint.=Enter a new last second hint. Enter a new main title transliteration.=Enter a new main title transliteration. Enter a new main title.=Enter a new main title. Enter a new sub title transliteration.=Enter a new sub title transliteration. @@ -1257,7 +1279,7 @@ Enter a new min BPM.=Enter the minimum displayed BPM. Enter a new max BPM.=Enter the maximum displayed BPM. More than %d notes per measure is not allowed. This change has been reverted.=More than %d notes per measure is not allowed. This change has been reverted. No backgrounds available=No backgrounds available -EditHelpText=Up/Down:\n change beat\nLeft/Right:\n change snap\nNumber keys:\n add/remove\n tap note\nN and M keys:\n swap tap notes\nCreate hold note:\n Hold a number\n while moving\n Up or Down\nCreate roll note:\n Hold Shift,\n then create a\n hold note.\nSpace bar:\n Set area\n marker\nEnter:\n Area Menu\nEscape:\n Main Menu\nF4:\n Timing Menu\nF1:\n Show help\n +EditHelpText=Up/Down:\n change beat\nLeft/Right:\n change snap\nNumber keys:\n add/remove\n tap note\nN and M keys:\n swap tap notes\nCtrl + N/M:\n swap cycled segment\nCtrl + ,/.:\n cycle segments\nCreate hold note:\n Hold a number\n while moving\n Up or Down\nCreate roll note:\n Hold Shift,\n then create a\n hold note.\nSpace bar: Set area\n marker\nT key: Switch Timing\nEnter: Area Menu\nA Key: Alter Menu\nEscape: Main Menu\nF4: Timing Menu\nF1: Show help\n PlayRecordHelpText=Press START to end Save successful.=Save successful. Saved as SM and DWI.=Saved as SM and DWI. @@ -1269,6 +1291,7 @@ This change creates notes past the end of the music and is not allowed.=This cha This will destroy all unsaved changes.=This will destroy all unsaved changes. Undo=Undo You must be in Song Timing Mode to edit BG Changes.=You must be in Song Timing Mode to edit BG Changes. +You must have an area selected to enter the Alter Menu.=You must have an area selected to enter the Alter Menu. Current beat=Current beat Current second=Current second @@ -1276,10 +1299,13 @@ Snap to=Snap to Selection beat=Selection beat Difficulty=Difficulty Description=Description +Chart Name=Chart Name Chart Style=Chart Style +Step Author=Step Author Main title=Main title Subtitle=Subtitle Tap Note=Tap Note +Segment=Segment Tap Steps=Tap Steps Jumps=Jumps Hands=Hands @@ -1657,11 +1683,15 @@ Error adding file '%s'.=Error adding file '%s'. Loading courses...=Loading courses... Loading songs...=Loading songs... Reloading...=Reloading... +Unloading songs...=Unloading songs... +Unloading courses...=Unloading courses... The folder "%s" appears to be a song folder. All song folders must reside in a group folder. For example, "Songs/Originals/My Song".=The folder "%s" appears to be a song folder. All song folders must reside in a group folder. For example, "Songs/Originals/My Song" will contain the music file (MP3, OGG...), the steps file (.sm, .dwi, .ksf...) and other related files. [SongUtil] You must supply a name for your new edit.=You must supply a name for your new edit. +The name you chose conflicts with another chart. Please use a different name.=The name you chose conflicts with another chart. Please use a different name. The name you chose conflicts with another edit. Please use a different name.=The name you chose conflicts with another edit. Please use a different name. +The chart name cannot contain any of the following characters: %s=The chart name cannot contain any of the following characters: %s The edit name cannot contain any of the following characters: %s=The edit name can not contain any of the following characters: %s The step author's name cannot contain any of the following characters: %s=The step author's name cannot contain any of the following characters: %s @@ -1897,6 +1927,7 @@ P2=P2 [UnlockRewardType] Song=Song Steps=Steps +StepsType=StepsType Course=Course Modifier=Modifier diff --git a/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc b/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc index dde55e41ae..5721dff9bf 100644 --- a/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc +++ b/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc @@ -10,7 +10,7 @@ #BACKGROUND:; #LYRICSPATH:; #CDTITLE:; -#MUSIC:ScreenGameplaySyncMachine music.ogg; +#MUSIC:_sync music.ogg; #OFFSET:-0.012; #SAMPLESTART:0.000; #SAMPLELENGTH:12.000; @@ -26,6 +26,8 @@ #DIFFICULTY:Beginner; #METER:1; #RADARVALUES:0.302,0.205,0.000,0.000,0.000; +#BPMS:0.000=132.000; +#OFFSET:-0.012; #NOTES: // measure 1 0000 @@ -100,6 +102,8 @@ #DIFFICULTY:Beginner; #METER:1; #RADARVALUES:0.302,0.205,0.000,0.000,0.000; +#BPMS:0.000=132.000; +#OFFSET:-0.012; #NOTES: // measure 1 00000 diff --git a/Themes/_fallback/Other/ScreenHowToPlay steps.ssc b/Themes/_fallback/Other/ScreenHowToPlay steps.ssc index b64d877215..2f7ade5385 100644 --- a/Themes/_fallback/Other/ScreenHowToPlay steps.ssc +++ b/Themes/_fallback/Other/ScreenHowToPlay steps.ssc @@ -13,6 +13,8 @@ #DESCRIPTION:BASIC; #DIFFICULTY:easy; #METER:1; +#BPMS:0.000=100.000; +#STOPS:16=2,18=2,20=2,22=2; #RADARVALUES:0,0,0,0,0; #NOTES: 0000 @@ -72,6 +74,8 @@ #DESCRIPTION:NORMAL; #DIFFICULTY:easy; #METER:1; +#BPMS:0.000=100.000; +#STOPS:16=2,18=2,20=2,22=2; #RADARVALUES:0,0,0,0,0; #NOTES: 00000 diff --git a/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ogg b/Themes/_fallback/Other/_sync music.ogg similarity index 100% rename from Themes/_fallback/Other/ScreenGameplaySyncMachine music.ogg rename to Themes/_fallback/Other/_sync music.ogg diff --git a/Themes/_fallback/Scripts/01 alias.lua b/Themes/_fallback/Scripts/01 alias.lua index 126d9c69ef..05935425bf 100644 --- a/Themes/_fallback/Scripts/01 alias.lua +++ b/Themes/_fallback/Scripts/01 alias.lua @@ -20,4 +20,4 @@ local _screen = { h = SCREEN_HEIGHT, cx = SCREEN_CENTER_X, cy = SCREEN_CENTER_Y -} +} \ No newline at end of file diff --git a/Themes/_fallback/Scripts/01 compat.lua b/Themes/_fallback/Scripts/01 compat.lua index 36b5327aa2..4103cc9dbc 100644 --- a/Themes/_fallback/Scripts/01 compat.lua +++ b/Themes/_fallback/Scripts/01 compat.lua @@ -56,15 +56,6 @@ function ActorScroller:setfastcatchup(bFastCatchup) self:SetFastCatchup(bFastCatchup) end --- renaming various StepMania functions to sm-ssc ones: -if ScreenString then - ScreenString = Screen.String -end - -if ScreenMetric then - ScreenMetric = Screen.Metric -end - --[[ GameState ]] --Aliases for old GAMESTATE timing functions. --These have been converted to SongPosition, but most themes still use these old functions. diff --git a/Themes/_fallback/Scripts/02 Actor.lua b/Themes/_fallback/Scripts/02 Actor.lua index cfded1e6a4..5736536221 100644 --- a/Themes/_fallback/Scripts/02 Actor.lua +++ b/Themes/_fallback/Scripts/02 Actor.lua @@ -83,6 +83,44 @@ local DropBezier = function Actor:drop(t) self:tween( t, "TweenType_Bezier", DropBezier ); end + +-- compound tweens "combine multiple interpolators to allow generating more +-- complex tweens." length is how long to span the animation for, while +-- ... is either a string (e.g. "linear,0.25,accelerate,0.75") or a table +-- with the tween information. +function Actor:compound(length,...) + local tweens = ... + + if type(tweens) == "string" then + local parsed = split(";",tweens) + tweens = {} -- convert to table + for i,s in pairs(parsed) do + local res = split(",",s) + + tweens[i] = { + Type = res[1], + Percent = res[2], + Bezier = res[3] or nil + } + end + end + + for i,t in pairs(tweens) do + if t.Type == "linear" then self:linear(t.Percent*length) + elseif t.Type == "accelerate" then self:accelerate(t.Percent*length) + elseif t.Type == "decelerate" then self:decelerate(t.Percent*length) + elseif t.Type == "spring" then self:spring(t.Percent*length) + elseif t.Type == "bouncebegin" then self:bouncebegin(t.Percent*length) + elseif t.Type == "bounceend" then self:bounceend(t.Percent*length) + elseif t.Type == "smooth" then self:smooth(t.Percent*length) + elseif t.Type == "drop" then self:smooth(t.Percent*length) + --elseif t.Type == "ease" then self:ease(t.Percent*length) + elseif t.Type == "bezier" then + -- todo: handle using tween and 'TweenType_Bezier' + end + end +end + -- Hide if b is true, but don't unhide if b is false. function Actor:hide_if(b) if b then @@ -114,17 +152,32 @@ function Actor:FullScreen() end --[[ Typical background sizes: -320x240 - DDR 1st-Extreme, most NVLM_ZK songs -640x480 - most simfiles in distribution today are this big. -768x480 - 16:10 aspect ratio backgrounds -854x480 - pump it up pro +320x240 - [4:3] +640x480 - [4:3] (most simfiles in distribution today use this res.) +768x480 - [16:10] +854x480 - [16:9] ]] --- "Most backgrounds are 640x480. Some are 768x480. Stretch the 4:3 ones." function Actor:scale_or_crop_background() - if (self:GetWidth() * 3) / 4 == self:GetHeight() then + local gw = self:GetWidth() + local gh = self:GetHeight() + + local graphicAspect = gw/gh + local displayAspect = DISPLAY:GetDisplayWidth()/DISPLAY:GetDisplayHeight() + + if graphicAspect == displayAspect then + -- bga matches the current aspect, we can stretch it. self:stretchto( 0,0,SCREEN_WIDTH,SCREEN_HEIGHT ); else + -- temp self:scaletocover( 0,0,SCREEN_WIDTH,SCREEN_HEIGHT ); + --[[ + -- bga doesn't match the aspect. + if displayAspect > graphicAspect then + -- the graphic is smaller than the display aspect ratio + else + -- the graphic is bigger than the display aspect ratio; crop me + end + --]] end end diff --git a/Themes/_fallback/Scripts/02 Branches.lua b/Themes/_fallback/Scripts/02 Branches.lua index f4b1a09950..3f89ca77da 100644 --- a/Themes/_fallback/Scripts/02 Branches.lua +++ b/Themes/_fallback/Scripts/02 Branches.lua @@ -65,7 +65,11 @@ Branch = { if SONGMAN:GetNumSongs() == 0 and SONGMAN:GetNumAdditionalSongs() == 0 then return "ScreenHowToInstallSongs"; end; - return "ScreenSelectProfile"; + if PROFILEMAN:GetNumLocalProfiles() >= 2 then + return "ScreenSelectProfile"; + else + return "ScreenProfileLoad"; + end end, OptionsEdit = function() -- Similar to above, don't let anyone in here with 0 songs. @@ -75,7 +79,7 @@ Branch = { return "ScreenOptionsEdit"; end, AfterProfileLoad = function() - return "ScreenSelectProfile" + return Branch.AfterSelectProfile() end, AfterSelectProfile = function() if ( THEME:GetMetric("Common","AutoSetStyle") == true ) then @@ -189,4 +193,7 @@ Branch = { Network = function() return IsNetConnected() and "ScreenTitleMenu" or "ScreenTitleMenu" end, + AfterSaveSummary = function() + return GAMESTATE:AnyPlayerHasRankingFeats() and "ScreenNameEntryTraditional" or "ScreenGameOver" + end, } diff --git a/Themes/_fallback/Scripts/02 Colors.lua b/Themes/_fallback/Scripts/02 Colors.lua index 9cfe09c54c..b46d9c5fe5 100644 --- a/Themes/_fallback/Scripts/02 Colors.lua +++ b/Themes/_fallback/Scripts/02 Colors.lua @@ -1,5 +1,5 @@ -- SSC Color Module and Library -local nilColor = color("0,0,0,0") + -- Original Color Module. Color = { -- Color Library @@ -16,7 +16,7 @@ Color = { Purple = color("#92278f"), Outline = color("0,0,0,0.5"), Invisible = color("1,1,1,0"), - Stealth = nilColor, + Stealth = color("0,0,0,0"), -- Color Functions -- These functions alter colors in a certain way so that you can make -- new ones without having to copy a color or find a new one. @@ -30,8 +30,11 @@ Color = { return { c[1],c[2],c[3],fAlpha }; end } + +setmetatable(Color, { __call = function(self, c) return self[c] end }) + -- Remapped Color Module, since some themes are crazy -Colors = Color; +-- Colors = Color; GameColor = { PlayerColors = { @@ -95,10 +98,6 @@ GameColor.Difficulty["Nightmare"] = GameColor.Difficulty["Challenge"]; GameColor.Difficulty["HalfDouble"] = GameColor.Difficulty["Medium"]; --[[ Fallbacks ]] -function Color(c) - return Colors[c] -end - function BoostColor( cColor, fBoost ) local c = cColor return { c[1]*fBoost, c[2]*fBoost, c[3]*fBoost, c[4] } diff --git a/Themes/_fallback/Scripts/02 Other.lua b/Themes/_fallback/Scripts/02 Other.lua index f9f2532a6f..91f81f06e1 100644 --- a/Themes/_fallback/Scripts/02 Other.lua +++ b/Themes/_fallback/Scripts/02 Other.lua @@ -98,16 +98,17 @@ end -- Get a metric from the currently-loading screen. This is only valid while loading -- an actor, such as from File or InitCommand attributes; not from commands. -Screen = { - Metric = function ( sName ) - local sClass = Var "LoadingScreen" - return THEME:GetMetric( sClass, sName ) - end, - String = function ( sName ) - local sClass = Var "LoadingScreen"; - return THEME:GetString( sClass, sName ) - end -}; +Screen.Metric = function ( sName ) + local sClass = Var "LoadingScreen" + return THEME:GetMetric( sClass, sName ) +end +ScreenMetric = Screen.Metric + +Screen.String = function ( sName ) + local sClass = Var "LoadingScreen"; + return THEME:GetString( sClass, sName ) +end +ScreenString = Screen.String function TextBannerAfterSet(self,param) local Title=self:GetChild("Title"); diff --git a/Themes/_fallback/Scripts/02 StageMods.lua b/Themes/_fallback/Scripts/02 StageMods.lua index 294ccf6a76..0c552bde5d 100644 --- a/Themes/_fallback/Scripts/02 StageMods.lua +++ b/Themes/_fallback/Scripts/02 StageMods.lua @@ -13,23 +13,41 @@ function AreStageSongModsForced() return bExtraStage or bOni or bBattle or bRave end +function SetFail() + local sFail = ""; + + if GetGamePref("DefaultFail") then + sFail = string.format("Fail%s", GetGamePref("DefaultFail")); + else + sFail = "FailOff"; + end + + sFail = tostring(sFail); +-- SCREENMAN:SystemMessage( 'NEW FAIL IS: ' .. tostring(sFail) ); + + for pn in ivalues(GAMESTATE:GetHumanPlayers()) do +-- GAMESTATE:ApplyGameCommand( "stagemod,FailImmediateContinue", pn ); +-- GAMESTATE:GetPlayerState(pn):SetPlayerOptions( "ModsLevel_Song", 'mod,FailImmediateContinue' ); + MESSAGEMAN:Broadcast( "PlayerOptionsChanged", {PlayerNumber = pn} ); + end + +-- GAMESTATE:SetSongOptions( "ModsLevel_Preferred", 'mod,FailImmediateContinue' ); +-- GAMESTATE:SetSongOptions( "ModsLevel_Stage", 'mod,FailImmediateContinue' ); +-- GAMESTATE:SetSongOptions( "ModsLevel_Song",'mod,FailImmediateContinue' ); + GAMESTATE:ApplyGameCommand( "mod," .. sFail); +-- GAMESTATE:ApplyGameCommand( "stagemod,FailImmediateContinue"); + MESSAGEMAN:Broadcast( "SongOptionsChanged" ); +end + function ScreenSelectMusic:setupmusicstagemods() Trace( "setupmusicstagemods" ) local pm = GAMESTATE:GetPlayMode() - + if pm == "PlayMode_Battle" or pm == "PlayMode_Rave" then - -- FIX DAT BUG; - local sFail = ""; - if GetGamePref("DefaultFail") then - sFail = string.format("Fail%s", GetGamePref("DefaultFail") ); - else - sFail = "Failoff"; - end; - -- - local so = GAMESTATE:GetDefaultSongOptions() .. "," .. sFail; + local so = GAMESTATE:GetDefaultSongOptions(); GAMESTATE:SetSongOptions( "ModsLevel_Stage", so ); MESSAGEMAN:Broadcast( "SongOptionsChanged" ); - elseif GAMESTATE:IsAnExtraStage() then + elseif GAMESTATE:IsAnExtraStage() then if GAMESTATE:GetPreferredSongGroup() == "---Group All---" then local song = GAMESTATE:GetCurrentSong() GAMESTATE:SetPreferredSongGroup( song:GetGroupName() ) @@ -46,6 +64,7 @@ function ScreenSelectMusic:setupmusicstagemods() po = THEME:GetMetric("SongManager","ExtraStagePlayerModifiers"); so = THEME:GetMetric("SongManager","ExtraStageStageModifiers"); end + local difficulty = steps:GetDifficulty() local Reverse = PlayerNumber:Reverse() @@ -58,8 +77,6 @@ function ScreenSelectMusic:setupmusicstagemods() GAMESTATE:SetPreferredDifficulty( pn, difficulty ) MESSAGEMAN:Broadcast( "PlayerOptionsChanged", {PlayerNumber = pn} ) end - - GAMESTATE:SetSongOptions( "ModsLevel_Stage", so ) MESSAGEMAN:Broadcast( "SongOptionsChanged" ) diff --git a/Themes/_fallback/Scripts/03 CustomSpeedMods.lua b/Themes/_fallback/Scripts/03 CustomSpeedMods.lua index 48e23bd5ed..f84874a591 100644 --- a/Themes/_fallback/Scripts/03 CustomSpeedMods.lua +++ b/Themes/_fallback/Scripts/03 CustomSpeedMods.lua @@ -1,9 +1,12 @@ --[[ -Custom Speed Mods v2.0 (for sm-ssc) +Custom Speed Mods v2.1 (for StepMania 5) by AJ Kelly of KKI Labs ( http://kki.ajworld.net/ ) changelog: +v2.1 (StepMania 5 Preview 2) +* Added support for m-Mods. + v2.0 (for sm-ssc) Giant rewrite of the speed mod parser. This rewrite comes with the following changes/features: @@ -38,9 +41,6 @@ v1.2 v1.1 * Cleaned up code some, I think. -________________________________________________________________________________ -anticipated future changes: -* M-Mod support (when sm-ssc integrates it) ]] -- ProfileDir(slot): gets the profile dir for slot, @@ -68,7 +68,7 @@ local function ParseSpeedModFile(path) return mods else -- error; write a fallback mod file and return it - local fallbackString = "0.5x,1x,1.5x,2x,3x,4x,8x,C200,C400" + local fallbackString = "0.5x,1x,1.5x,2x,3x,4x,8x,C250,C450,m550" Trace("[CustomSpeedMods]: Could not read SpeedMods; writing fallback to "..path) file:Open(path, 2) file:Write(fallbackString) @@ -148,8 +148,8 @@ end local function SpeedModSort(tab) local xMods = {} + local mMods = {} local cMods = {} - --local mMods = {} -- convert to numbers so sorting works: for i=1,#tab do @@ -159,10 +159,10 @@ local function SpeedModSort(tab) if string.find(tab[i],"C%d") then typ = cMods val = string.gsub(tab[i], "C", "") - elseif string.find(tab[i],"M%d") then - Trace("[CustomSpeedMods] OpenITG's M-Mods are not supported yet in sm-ssc.") - --typ = mMods - --val = string.gsub(tab[i], "M", "") + -- support both cases because I want to hit people -freem + elseif string.find(tab[i],"m%d") or string.find(tab[i],"M%d") then + typ = mMods + val = string.gsub(tab[i], "m", "") else typ = xMods val = string.gsub(tab[i], "x", "") @@ -175,7 +175,7 @@ local function SpeedModSort(tab) -- sort cMods cMods = AnonSort(cMods) -- sort mMods - --mMods = AnonSort(mMods) + mMods = AnonSort(mMods) local fin = {} -- convert it back to a string since that's what it expects for i=1,#xMods do @@ -184,7 +184,9 @@ local function SpeedModSort(tab) for i=1,#cMods do table.insert(fin, "C"..cMods[i]) end - --for i=1,#mMods do table.insert(fin, "M"..mMods[i]); end; + for i=1,#mMods do + table.insert(fin, "m"..mMods[i]) + end return fin end @@ -295,7 +297,7 @@ function SpeedMods() end --[[ -Copyright 2008-2009 AJ Kelly/KKI Labs. +Copyright 2008-2011 AJ Kelly/KKI Labs. Use freely, so long this notice and the above documentation remains. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" diff --git a/Themes/_fallback/Scripts/03 Gameplay.lua b/Themes/_fallback/Scripts/03 Gameplay.lua index f26977c630..629453ff5a 100644 --- a/Themes/_fallback/Scripts/03 Gameplay.lua +++ b/Themes/_fallback/Scripts/03 Gameplay.lua @@ -11,7 +11,7 @@ function GetExtraColorThreshold() sGame = GAMESTATE:GetCurrentGame():GetName() local Modes = { dance = 10, - pump = 15, + pump = 21, beat = 12, kb7 = 10, para = 10, @@ -105,6 +105,10 @@ function ComboPerRow() end end +function EvalUsesCheckpointsWithJudgments() + return (GAMESTATE:GetCurrentGame():GetName() == "pump") and true or false +end + -- these need cleanup really. function HitCombo() sGame = GAMESTATE:GetCurrentGame():GetName() @@ -183,7 +187,11 @@ function HoldTiming() end function ShowHoldJudgments() - return not GAMESTATE:GetCurrentGame():GetName() == "pump" + if GAMESTATE:GetCurrentGame():GetName() == "pump" then + return false + else + return true + end end function HoldHeadStep() @@ -267,4 +275,4 @@ end function ComboUnderField() return GetUserPrefB("UserPrefComboUnderField") -end \ No newline at end of file +end diff --git a/Themes/_fallback/Scripts/03 HSV.lua b/Themes/_fallback/Scripts/03 HSV.lua index a4b56baa5d..c2fd988ea7 100644 --- a/Themes/_fallback/Scripts/03 HSV.lua +++ b/Themes/_fallback/Scripts/03 HSV.lua @@ -246,4 +246,16 @@ function Hue(color,newHue) end c.Hue = newHue return HSVToColor(c) +end; + +function Alpha(color,percent) + local c = ColorToHSV(color); + -- error checking + if percent < 0 then + percent = 0.0; + elseif percent > 1 then + percent = 1.0; + end; + c.Alpha = percent; + return HSVToColor(c); end; \ No newline at end of file diff --git a/Themes/_fallback/Scripts/03 ProductivityHelpers.lua b/Themes/_fallback/Scripts/03 ProductivityHelpers.lua index eb2d64bb9d..4297389fc6 100644 --- a/Themes/_fallback/Scripts/03 ProductivityHelpers.lua +++ b/Themes/_fallback/Scripts/03 ProductivityHelpers.lua @@ -148,7 +148,9 @@ end -- MaskSource([clearzbuffer]) -- Sets an actor up as the source for a mask. Clears zBuffer by default. function Actor:MaskSource(noclear) - self:clearzbuffer(noclear or true) + if noclear == true then + self:clearzbuffer(true) + end self:zwrite(true) self:blend('BlendMode_NoEffect') end @@ -224,10 +226,10 @@ end; --[[ ----------------------------------------------------------------------- ]] --[[ profile stuff ]] --- Profile(pn) +-- GetPlayerOrMachineProfile(pn) -- This returns a profile, preferably a player one. -- If there isn't one, we fall back on the machine profile. -function Profile(pn) +function GetPlayerOrMachineProfile(pn) if PROFILEMAN:IsPersistentProfile(pn) then -- player profile return PROFILEMAN:GetProfile(pn); diff --git a/Themes/_fallback/Scripts/03 ThemePrefs.lua b/Themes/_fallback/Scripts/03 ThemePrefs.lua index dfa9e3e695..90d7d73a19 100644 --- a/Themes/_fallback/Scripts/03 ThemePrefs.lua +++ b/Themes/_fallback/Scripts/03 ThemePrefs.lua @@ -150,7 +150,7 @@ function InitUserPrefs() end; function UserPrefScoringMode() - local baseChoices = { 'DDR 1stMIX', 'DDR 4thMIX', 'DDR Extreme', 'DDR SuperNOVA', 'DDR SuperNOVA 2', 'MIGS' }; --'[SSC] Radar Master' + local baseChoices = { 'DDR 1stMIX', 'DDR 4thMIX', 'DDR Extreme', 'DDR SuperNOVA', 'DDR SuperNOVA 2', 'MIGS', 'HYBRID' }; --'[SSC] Radar Master' local t = { Name = "UserPrefScoringMode"; LayoutType = "ShowAllInRow"; diff --git a/Themes/_fallback/Scripts/04 Scoring.lua b/Themes/_fallback/Scripts/04 Scoring.lua index 27a1d6155a..5d47fbd89a 100644 --- a/Themes/_fallback/Scripts/04 Scoring.lua +++ b/Themes/_fallback/Scripts/04 Scoring.lua @@ -67,7 +67,7 @@ r['DDR 4thMIX'] = function(params, pss) local capScore = 999999999; local bestPoints = scoreLookupTable['TapNoteScore_W1']; local bestCombo = bestPoints and comboBonusForThisStep or 0; - pss:SeCurMaxScore(clamp(pss:GeCurMaxScore()+bestPoints+bestCombo,0,capScore)); + pss:SetCurMaxScore(clamp(pss:GetCurMaxScore()+bestPoints+bestCombo,0,capScore)); local localPoints = scoreLookupTable[params.TapNoteScore]; local localCombo = localPoints and comboBonusForThisStep or 0; pss:SetScore(clamp(pss:GetScore()+localPoints+localCombo,0,capScore)); @@ -84,14 +84,19 @@ r['DDR Extreme'] = function(params, pss) setmetatable(judgmentBase, ZeroIfNotFound); local steps = GAMESTATE:GetCurrentSteps(params.Player); local radarValues = steps:GetRadarValues(params.Player); - local baseScore = (steps:IsAnEdit() and - 5 or steps:GetMeter()) * 1000000; + local meter = steps:GetMeter(); + if (steps:IsAnEdit()) then + meter = 5; + elseif (meter < 1) then + meter = 1; + elseif (meter > 10) then + meter = 10; + end; + local baseScore = meter * 1000000; if (GAMESTATE:GetCurrentSong():IsMarathon()) then baseScore = baseScore * 3; - else - if (GAMESTATE:GetCurrentSong():IsLong()) then - baseScore = baseScore * 2; - end; + elseif (GAMESTATE:GetCurrentSong():IsLong()) then + baseScore = baseScore * 2; end; local totalItems = GetTotalItems(radarValues); local singleStep = (1 + totalItems) * totalItems / 2; @@ -122,6 +127,47 @@ r['DDR Extreme'] = function(params, pss) Shared.CurrentStep[pn] = 0; -- Reset for the next song. end; end; + +----------------------------------------------------------- +--HYBRID Scoring +----------------------------------------------------------- +r['HYBRID'] = function(params, pss) + local multLookup = + { + ['TapNoteScore_W1'] = 10, + ['TapNoteScore_W2'] = 9, + ['TapNoteScore_W3'] = 5 + }; + setmetatable(multLookup, ZeroIfNotFound); + local radarValues = GetDirectRadar(params.Player); + local totalItems = GetTotalItems(radarValues); + -- 1+2+3+...+totalItems の値 + local sTotal = (totalItems+1)*totalItems/2; + -- [en] Score for one song + -- [ja] 1つあたりのスコア + local sOne = math.floor(100000000/sTotal); + -- [ja] 端数は最後の1ステップで加算するのでその値を取得 + local sLast = 100000000-(sOne*sTotal); + -- [ja] 現在何個目の譜面か + pss:SetCurMaxScore(pss:GetCurMaxScore()+1); + -- [en] current score + -- [ja] 今回のスコア + local vScore = sOne*(pss:GetCurMaxScore()); + if (params.HoldNoteScore == 'HoldNoteScore_Held') then + vScore = vScore; + else + if (params.HoldNoteScore == 'HoldNoteScore_LetGo') then + vScore = 0; + else + vScore = vScore*multLookup[params.TapNoteScore]/10; + end; + end; + if ((vScore > 0) and (pss:GetCurMaxScore() == totalItems)) then + vScore = vScore+sLast; + end; + pss:SetScore(pss:GetScore()+vScore); +end; + ----------------------------------------------------------- --DDR SuperNOVA(-esque) scoring ----------------------------------------------------------- @@ -148,24 +194,43 @@ end; r['DDR SuperNOVA 2'] = function(params, pss) local multLookup = { - ['TapNoteScore_W1'] = 1, - ['TapNoteScore_W2'] = 1, - ['TapNoteScore_W3'] = 0.5 + ['TapNoteScore_W1'] = 10, + ['TapNoteScore_W2'] = 10, + ['TapNoteScore_W3'] = 5 }; setmetatable(multLookup, ZeroIfNotFound); local radarValues = GetDirectRadar(params.Player); - local totalItems = GetTotalItems(radarValues); - local base = 100000 / totalItems; - local hold = base * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0); - local maxScore = (base * multLookup['TapNoteScore_W1']) + hold; - pss:SetCurMaxScore(pss:GetCurMaxScore() + (math.round(maxScore) * 10)); - local preW1 = base * multLookup[params.TapNoteScore]; - local buildScore = (preW1 - (IsW1Allowed(params.TapNoteScore) and 10 or 0)) + hold; - pss:SetScore(pss:GetScore() + (math.round(buildScore) * 10)); + local totalItems = GetTotalItems(radarValues); + + -- handle holds + local maxAdd = 0; + if params.HoldNoteScore == 'HoldNoteScore_Held' then + maxAdd = 10; + elseif params.HoldNoteScore == 'HoldNoteScore_LetGo' then + maxAdd = 0; + else + maxAdd = multLookup[params.TapNoteScore]; + if params.TapNoteScore == 'TapNoteScore_W2' or 'TapNoteScore_W3' then + -- [ja] 超最終手段 + pss:SetCurMaxScore( pss:GetCurMaxScore() + 1000000 ); + end; + end; + pss:SetCurMaxScore(pss:GetCurMaxScore() + maxAdd); + + --[[ + [ja] パフェ数取得 この方法で取得するとロングノートの場合2つカウントされる そのため使えない + pss:GetTapNoteScores('TapNoteScore_W2') + 仕方がないのでパフェ数を 1000000 単位で GetCurMaxScore に記録 + その後、情報を分解して取り出す + --]] + + local vScore = pss:GetCurMaxScore() % 1000000 + local vSub = math.floor( pss:GetCurMaxScore()/1000000 ) + pss:SetScore( math.floor(10000*vScore/totalItems) * 10 - (vSub*10) ); end; ----------------------------------------------------------- ---Radar Master (doesn't work in 1.2.1, disabled) ---don't try to "fix it up", either. you *cannot* make it work in 1.2.1. +--Radar Master (doesn't work in sm-ssc 1.2.1, disabled) +--todo: get this working with StepMania 5 ----------------------------------------------------------- r['[SSC] Radar Master'] = function(params, pss) local masterTable = { diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index fbe5f51939..7255b9a842 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -28,7 +28,7 @@ ScreenHeight=480 AutoSetStyle=GetUserPrefB("UserPrefAutoSetStyle") # Default modifiers and noteskin. -DefaultModifiers="default,1.5x" +DefaultModifiers="1x" DefaultNoteSkinName="default" # Difficulties to show. Useful for custom games where you want to hide these. @@ -124,6 +124,8 @@ ExtraColor=color("#ff0000") -- red [UnlockManager] # Unlock specific things. AutoLockChallengeSteps=false +AutoLockEditSteps=false +SongsNotAdditional=true UnlockNames="" # useful commands: @@ -200,6 +202,8 @@ BeatOffsetHeight=15 BeatPIHeight=2 MiniPercentBase=0.5 MiniPercentGate=1 +TinyPercentBase=0.5 +TinyPercentGate=1 DizzyHoldHeads=false QuantizeArrowYPosition=false @@ -411,72 +415,7 @@ SortLevel5Color=color("0,1,0,1") # Custom system that lets you rename certain classes of difficulties to # something else. Mostly for custom games and game emulation, PIU for example. -# The names of which -Names="PumpHard,PumpFreestyle,PumpNightmare,PumpHalfDouble,PumpRoutine" - -# Names="DanceCoupleBeginner,DanceCoupleEasy,DanceCoupleMedium,DanceCoupleHard,DanceCoupleExpert,PumpHard" -# That get remapped to -DanceCoupleBeginnerStepsType="StepsType_Dance_Couple" -DanceCoupleBeginnerDifficulty="Difficulty_Beginner" -DanceCoupleBeginnerCourseType=nil -DanceCoupleBeginnerString="Beginner" -#--# -DanceCoupleEasyStepsType="StepsType_Dance_Couple" -DanceCoupleEasyDifficulty="Difficulty_Easy" -DanceCoupleEasyCourseType=nil -DanceCoupleEasyString="Easy" -#--# -DanceCoupleMediumStepsType="StepsType_Dance_Couple" -DanceCoupleMediumDifficulty="Difficulty_Medium" -DanceCoupleMediumCourseType=nil -DanceCoupleMediumString="Medium" -#--# -DanceCoupleHardStepsType="StepsType_Dance_Couple" -DanceCoupleHardDifficulty="Difficulty_Hard" -DanceCoupleHardCourseType=nil -DanceCoupleHardString="Hard" -#--# -DanceCoupleExpertStepsType="StepsType_Dance_Couple" -DanceCoupleExpertDifficulty="Difficulty_Expert" -DanceCoupleExpertCourseType=nil -DanceCoupleExpertString="Expert" -#===# -PumpHardStepsType="StepsType_Pump_Single" -PumpHardDifficulty="Difficulty_Hard" -PumpHardCourseType=nil -PumpHardString="Crazy" -#--# -PumpFreestyleStepsType="StepsType_Pump_Double" -PumpFreestyleDifficulty="Difficulty_Medium" -PumpFreestyleCourseType=nil -PumpFreestyleString="Freestyle" -#--# -PumpNightmareStepsType="StepsType_Pump_Double" -PumpNightmareDifficulty="Difficulty_Hard" -PumpNightmareCourseType=nil -PumpNightmareString="Nightmare" -#--# -PumpHalfDoubleStepsType="StepsType_Pump_Halfdouble" -PumpHalfDoubleDifficulty="Difficulty_Medium" -PumpHalfDoubleCourseType=nil -PumpHalfDoubleString="HalfDouble" -#--# -PumpRoutineStepsType="StepsType_Pump_Routine" -PumpRoutineDifficulty="Difficulty_Medium" -PumpRoutineCourseType=nil -PumpRoutineString="Routine" -# -# Difficulty_Beginner-StepsType_Pump_Single=Easy -# Difficulty_Easy-StepsType_Pump_Single=Normal -# Difficulty_Medium-StepsType_Pump_Single=Hard -# Difficulty_Hard-StepsType_Pump_Single=Crazy -# Difficulty_Medium-StepsType_Pump_Halfdouble=Half-Double -# Difficulty_Medium-StepsType_Pump_Double=Freestyle -# Difficulty_Hard-StepsType_Pump_Double=Nightmare -# Difficulty_Edit-StepsType_Pump_Single=Edit -# Difficulty_Edit-StepsType_Pump_Halfdouble=Edit -# Difficulty_Edit-StepsType_Pump_Double=Edit -# Course=Progressive +Names= [DifficultyList] # A list that shows difficulties in a song. @@ -606,7 +545,19 @@ OverY=0 [LifeMeterBattery] # The bar that shows up in Oni mode. +# any score below this one will cause you to lose a life. +MinScoreToKeepLife='TapNoteScore_W3' +# how many lives you'll lose upon doing so. +SubtractLives=1 +# how many lives you'll lose hitting a mine +MinesSubtractLives=1 +# how many lives a successful hold will net you. +HeldAddLives=0 +# how many lives an unsuccessful hold will cost you. +LetGoSubtractLives=1 +# How many lives trigger the "Danger" state. +DangerThreshold=1 # How long it flashes when you lose a life. BatteryBlinkTime=1.2 # Where the batteries are @@ -614,11 +565,16 @@ BatteryP1X=-92 BatteryP1Y=2 BatteryP2X=92 BatteryP2Y=2 -# Where your live count is +# Where your life count is +NumLivesFormat="x%d" NumLivesP1X=-92 NumLivesP1Y=0 +NumLivesP1GainLifeCommand= +NumLivesP1LoseLifeCommand=zoom,1.5;linear,0.15;zoom,1 NumLivesP2X=92 NumLivesP2Y=0 +NumLivesP2GainLifeCommand= +NumLivesP2LoseLifeCommand=zoom,1.5;linear,0.15;zoom,1 [LifeMeterBattery Percent] # The percentage on the bar. I wouldn't even bother changing this, because I @@ -1012,8 +968,8 @@ StopOffsetX=50 DelayOffsetX=120 WarpOffsetX=90 TimeSignatureOffsetX=30 -TickcountOffsetX=70 -ComboOffsetX=50 +TickcountOffsetX=50 +ComboOffsetX=70 LabelOffsetX=130 SpeedOffsetX=30 ScrollOffsetX=100 @@ -1067,7 +1023,8 @@ CheckpointsUseTickcounts=(GAMESTATE:GetCurrentGame():GetName() == "pump") ; deprecated? CheckpointsUseTimeSignatures=false CheckpointsTapsSeparateJudgment=CheckpointsTapsSeparateJudgment() -CheckpointsFlashOnHold=false +; someone misunderstood me :x -Daisu +CheckpointsFlashOnHold=(GAMESTATE:GetCurrentGame():GetName() == "pump") ImmediateHoldLetGo=ImmediateHoldLetGo() RequireStepOnHoldHeads=HoldHeadStep() RequireStepOnMines=false @@ -1081,6 +1038,7 @@ ComboStoppedAt=50 AttackRunTimeRandom=6 AttackRunTimeMine=7 BattleRaveMirror=true +MModHighCap=600 [PlayerOptions] RandomSpeedChance=0.2 @@ -1527,7 +1485,7 @@ AllowRepeatingInput=false PreSwitchPageSeconds=0 PostSwitchPageSeconds=0 ScrollerSecondsPerItem=0 -ScrollerNumItemsToDraw=1024 +ScrollerNumItemsToDraw=16 ScrollerTransform=function(self,offset,itemIndex,numItems) end ScrollerSubdivisions=1 OverrideSleepAfterTweenOffSeconds=false @@ -1791,8 +1749,7 @@ CodeUp="+MenuUp" CodeUp2="+Up" CodeDown="+MenuDown" CodeDown2="+Down" -# Holding Start let us skip ( annoying ) -CodeStart="~Start,+Start" +CodeStart="+Start" CodeBack="Back" CodeCenter="Center" CodeDownLeft="DownLeft" @@ -1817,6 +1774,7 @@ ChoiceDouble="name,Double;style,double;text,Double;screen,"..Branch.AfterSelectP ChoiceSolo="name,Solo;style,solo;text,Solo;screen,"..Branch.AfterSelectPlayMode() ChoiceVersus="name,Versus;style,versus;text,Versus;screen,"..Branch.AfterSelectPlayMode() ChoiceCouple="name,Couple;style,couple;text,Couple;screen,"..Branch.AfterSelectPlayMode() +ChoiceRoutine="name,Routine;style,routine;text,Routine;screen,"..Branch.AfterSelectPlayMode() ChoiceHalfDouble="name,HalfDouble;style,halfdouble;text,HalfDouble;screen,"..Branch.AfterSelectPlayMode() Choice5Keys="name,5Keys;style,single5;text,5Keys;screen,"..Branch.AfterSelectPlayMode() Choice7Keys="name,7Keys;style,single7;text,7Keys;screen,"..Branch.AfterSelectPlayMode() @@ -2064,7 +2022,8 @@ ForceTimer=true TimerMetricsGroup="MenuTimerNoSound" TimerSeconds=5 # - +ScreenBeginCommand=%SetFail +# [ScreenOptions] Fallback="ScreenWithMenuElements" NavigationMode="normal" @@ -2134,6 +2093,7 @@ OptionRowExitMetricsGroup="OptionRowExit" Fallback="ScreenOptions" Class="ScreenOptionsMaster" NoteSkinSortOrder="" +StepsUseChartName=false # ExitItem is an exit row with the "Exit" text as a menu item; ExitTitle # uses the menu title. @@ -2177,22 +2137,23 @@ Accel,5="mod,boomerang;name,Boomerang" # Accel,5="mod,expand;name,Expand" # Accel,6="mod,boomerang;name,Boomerang" -Effect="14;selectmultiple" +Effect="15;selectmultiple" EffectDefault="mod,no drunk,no dizzy,,no twirl,no roll,no confusion,no mini,no tiny,no flip,no invert,no tornado,no tipsy,no bumpy,no beat,no xmode" Effect,1="mod,drunk;name,Drunk" Effect,2="mod,dizzy;name,Dizzy" Effect,3="mod,twirl;name,Twirl" Effect,4="mod,roll;name,Roll" Effect,5="mod,confusion;name,Confusion" -Effect,6="mod,tiny;name,Tiny" -Effect,7="mod,-100% mini;name,Big" -Effect,8="mod,flip;name,Flip" -Effect,9="mod,invert;name,Invert" -Effect,10="mod,tornado;name,Tornado" -Effect,11="mod,tipsy;name,Tipsy" -Effect,12="mod,bumpy;name,Bumpy" -Effect,13="mod,beat;name,Beat" -Effect,14="mod,45% xmode;name,XMode" +Effect,6="mod,mini;name,Mini" +Effect,7="mod,tiny;name,Tiny" +Effect,8="mod,-100% mini;name,Big" +Effect,9="mod,flip;name,Flip" +Effect,10="mod,invert;name,Invert" +Effect,11="mod,tornado;name,Tornado" +Effect,12="mod,tipsy;name,Tipsy" +Effect,13="mod,bumpy;name,Bumpy" +Effect,14="mod,beat;name,Beat" +Effect,15="mod,45% xmode;name,XMode" EffectsReceptor="selectmultiple" EffectsReceptorDefault="" @@ -2335,18 +2296,11 @@ Mines,2="name,On" Mines,3="mod,mines;name,Add" Mines,4="mod,attackmines;name,AttackMines" -# Mines="4" -# MinesDefault="mod,no nomines,no mines, no attackmines" -# Mines,1="mod,nomines;name,Off" -# Mines,2="name,On" -# Mines,3="mod,mines;name,Add" -# Mines,4="mod,attackmines;name,AttackMines" - Attacks="3" -AttacksDefault="mod,songattacks" -Attacks,3="mod,no randomattacks,no songattacks;name,Off" +AttacksDefault="mod,no randomattacks, no noattacks" +Attacks,1="name,On" Attacks,2="mod,randomattacks;name,RandomAttacks" -Attacks,1="name,SongAttacks" +Attacks,3="mod,noattacks;name,Off" PlayerAutoPlay="2" PlayerAutoPlayDefault="mod,no playerautoplay" @@ -2357,7 +2311,7 @@ Hide="3;selectmultiple" HideDefault="mod,no dark,no blind,no cover" Hide,1="mod,dark;name,Dark" Hide,2="mod,blind;name,Blind" -Hide,3="mod,60% cover;name,Cover" +Hide,3="mod,80% cover;name,Cover" # Hide="3" # HideDefault="mod,no dark,no blind" @@ -2373,12 +2327,6 @@ Persp,3="mod,space;name,Space" Persp,4="mod,hallway;name,Hallway" Persp,5="mod,distant;name,Distant" -ScoreDisplay="3" -ScoreDisplayDefault="mod,addscore" -ScoreDisplay,1="mod,addscore;name,Add" -ScoreDisplay,2="mod,subtractscore;name,Subtract" -ScoreDisplay,3="mod,averagescore;name,Average" - # Song options # LifeType="3;together" LifeType=(GAMESTATE:IsCourseMode() and 3 or 2)..";together" @@ -2507,6 +2455,7 @@ LineHighlightP2ChangeToExitCommand= CursorOnCommand=visible,false [ScreenOptionsService] +AllowOperatorMenuButton=false Class="ScreenOptionsMaster" Fallback="ScreenOptionsSimpleService" # @@ -2884,7 +2833,6 @@ Line11="list,Attacks" Line12="list,PlayerAutoPlay" Line13="list,Hide" Line14="list,Persp" -Line15="list,ScoreDisplay" Line16="list,Steps" Line17="list,Characters" @@ -3276,10 +3224,13 @@ PlayerType="PlayerShared" Class="ScreenEvaluation" Fallback="ScreenWithMenuElements" # +NextScreen=Branch.AfterEvaluation() +PrevScreen=Branch.AfterEvaluation() +# LightsMode="LightsMode_MenuStartOnly" # Summary=false -CheckpointsWithJudgments=false +CheckpointsWithJudgments=EvalUsesCheckpointsWithJudgments() # TimerSeconds=20 # @@ -3361,30 +3312,34 @@ DetailLineFormat="%3d/%3d" [ScreenEvaluationNormal] Fallback="ScreenEvaluation" # -NextScreen="ScreenProfileSave" +NextScreen=Branch.AfterEvaluation() +PrevScreen=Branch.AfterEvaluation() [ScreenEvaluationSummary] Fallback="ScreenEvaluation" # -NextScreen="ScreenSelectMusic" +NextScreen=Branch.AfterSummary() # Summary=true -# [ScreenNameEntry] # !!! # Class="ScreenNameEntry" Fallback="ScreenWithMenuElementsBlank" +# TimerX=SCREEN_CENTER_X+0 TimerY=SCREEN_CENTER_Y-210 +# CategoryY=SCREEN_CENTER_Y+190 CategoryZoom=0.7 +# CharsZoomSmall=1.0 CharsZoomLarge=1.5 CharsSpacingY=40 CharsChoices=" ABCDEFGHIJKLMNOPQRSTUVWXYZ" ScrollingCharsCommand=diffuse,0.6,0.8,0.8,1 SelectedCharsCommand=diffuse,0.8,1,1,1 +# ReceptorArrowsY=SCREEN_CENTER_Y-140 NumCharsToDrawBehind=2 NumCharsToDrawTotal=10 @@ -3394,7 +3349,9 @@ TimerSeconds=24 TimerStealth=false ShowStyleIcon=false MaxRankingNameLength=4 +# NextScreen="ScreenProfileSave" +# PlayerP1OnePlayerOneSideX=SCREEN_CENTER_X-160 PlayerP2OnePlayerOneSideX=SCREEN_CENTER_X+160 PlayerP1TwoPlayersTwoSidesX=SCREEN_CENTER_X-160 @@ -3402,6 +3359,31 @@ PlayerP2TwoPlayersTwoSidesX=SCREEN_CENTER_X+160 PlayerP1OnePlayerTwoSidesX=SCREEN_CENTER_X PlayerP2OnePlayerTwoSidesX=SCREEN_CENTER_X +[ScreenNameEntryTraditional] +Class="ScreenNameEntryTraditional" +Fallback="ScreenWithMenuElements" +# +TimerSeconds=30 +# +RepeatRate=15 +RepeatDelay=1/4 +# +NextScreen="ScreenProfileSaveSummary" +# +HelpText="Enter your name!" +# +CancelTransitionsOut=true +MaxRankingNameLength=4 +CodeNames="Backspace,Left,Right,NextRow1=NextRow,NextRow2=NextRow,PrevRow,JumpToEnter,Enter" +CodeLeft="+MenuLeft" +CodeRight="+MenuRight" +CodePrevRow="+MenuUp" +CodeNextRow1="+MenuDown" +CodeNextRow2="Select,~Select" +CodeBackspace="@Select-MenuLeft" +CodeJumpToEnter="@Select-Start" +CodeEnter="Start" + [ScreenProfileSave] Class="ScreenProfileSave" Fallback="ScreenWithMenuElementsBlank" @@ -3414,8 +3396,8 @@ TimerSeconds=-1 [ScreenProfileSaveSummary] Fallback="ScreenProfileSave" # -NextScreen="ScreenGameOver" -PrevScreen="ScreenGameOver" +NextScreen=Branch.AfterSaveSummary() +PrevScreen=Branch.AfterSaveSummary() [ScreenGameOver] Class="ScreenEnding" @@ -3638,19 +3620,22 @@ PlayRecordHelpOnCommand=halign,0;valign,0;shadowlength,1 LoopOnChartEnd=true -CurrentBeatFormat="%s:\n %.5f\n" -CurrentSecondFormat="%s:\n %.5f\n" -SnapToFormat="%s:\n %s\n" -SelectionBeatBeginFormat="%s:\n %.5f" +CurrentBeatFormat="%s:\n %.6f\n" +CurrentSecondFormat="%s:\n %.6f\n" +SnapToFormat="%s: %s\n" +SelectionBeatBeginFormat="%s:\n %.6f" SelectionBeatUnfinishedFormat=" ...\n" -SelectionBeatEndFormat="-%.5f\n" +SelectionBeatEndFormat="-%.6f\n" DifficultyFormat="%s:\n %s\n" -RoutinePlayerFormat="%s:\n %d\n" +RoutinePlayerFormat="%s: %d\n" DescriptionFormat="%s:\n %s\n" +StepAuthorFormat="%s:\n %s\n" +ChartNameFormat="%s:\n %s\n" ChartStyleFormat="%s:\n %s\n" MainTitleFormat="%s:\n %s\n" SubtitleFormat="%s:\n %s\n" TapNoteTypeFormat="%s: %s\n" +SegmentTypeFormat="%s: %s\n" NumStepsFormat="%s: %d\n" NumJumpsFormat="%s: %d\n" NumHoldsFormat="%s: %d\n" @@ -3659,10 +3644,18 @@ NumHandsFormat="%s: %d\n" NumRollsFormat="%s: %d\n" NumLiftsFormat="%s: %d\n" NumFakesFormat="%s: %d\n" +NumStepsFormatTwoPlayer="%s: %d/%d\n" +NumJumpsFormatTwoPlayer="%s: %d/%d\n" +NumHoldsFormatTwoPlayer="%s: %d/%d\n" +NumMinesFormatTwoPlayer="%s: %d/%d\n" +NumHandsFormatTwoPlayer="%s: %d/%d\n" +NumRollsFormatTwoPlayer="%s: %d/%d\n" +NumLiftsFormatTwoPlayer="%s: %d/%d\n" +NumFakesFormatTwoPlayer="%s: %d/%d\n" TimingModeFormat="%s:\n %s\n" -Beat0OffsetFormat="%s:\n %.5f secs\n" -PreviewStartFormat="%s:\n %.5f secs\n" -PreviewLengthFormat="%s:\n %.5f secs\n" +Beat0OffsetFormat="%s:\n %.6f secs\n" +PreviewStartFormat="%s:\n %.6f secs\n" +PreviewLengthFormat="%s:\n %.6f secs\n" [ScreenPracticeMenu] Fallback="ScreenEditMenu" @@ -3753,9 +3746,15 @@ TitleX=SCREEN_CENTER_X-80 [ScreenMiniMenuAreaMenu] Fallback="ScreenMiniMenu" +[ScreenMiniMenuAlterMenu] +Fallback="ScreenMiniMenu" + [ScreenMiniMenuStepsInformation] Fallback="ScreenMiniMenu" +[ScreenMiniMenuStepsData] +Fallback="ScreenMiniMenu" + [ScreenMiniMenuSongInformation] Fallback="ScreenMiniMenu" @@ -3949,6 +3948,7 @@ PrevScreen="ScreenNetRoom" NextScreen="ScreenStageInformation" NoSongsScreen=Branch.TitleMenu() RoomSelectScreen="ScreenNetRoom" +PlayerOptionsScreen="ScreenPlayerOptions" Codes="CodeDetectorOnline" ShowStyleIcon=false diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/basemeter.png b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/basemeter.png deleted file mode 100644 index 469e617168..0000000000 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/basemeter.png and /dev/null differ diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/center (doubleres).png b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/center (doubleres).png deleted file mode 100644 index f792417219..0000000000 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/center (doubleres).png and /dev/null differ diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/corner (doubleres).png b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/corner (doubleres).png deleted file mode 100644 index f509dde7a7..0000000000 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/corner (doubleres).png and /dev/null differ diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/danger.png b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/danger.png deleted file mode 100644 index 3adbe6ff21..0000000000 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/danger.png and /dev/null differ diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/decoration_corner (doubleres).png b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/decoration_corner (doubleres).png deleted file mode 100644 index 865e4ce12b..0000000000 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/decoration_corner (doubleres).png and /dev/null differ diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/default.lua b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/default.lua deleted file mode 100644 index 362e5013a2..0000000000 --- a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/default.lua +++ /dev/null @@ -1,512 +0,0 @@ -local t = Def.ActorFrame{} - -local newBPS; -local oldBPS; - - --- DECORATIONS //////////////////////// - --- Left Hex Corner Decoration -t[#t+1] = LoadActor("decoration_corner") .. { - InitCommand=cmd(visible,GAMESTATE:IsHumanPlayer(PLAYER_1)); - OnCommand=cmd(horizalign,left;x,SCREEN_LEFT;vertalign,top;y,SCREEN_TOP;zoomy,0.4;zoomx,0.6;diffusealpha,0.3;blend,Blend.Add); -}; - --- Right Hex Corner Decoration -t[#t+1] = LoadActor("decoration_corner") .. { - InitCommand=cmd(visible,GAMESTATE:IsHumanPlayer(PLAYER_2)); - OnCommand=cmd(horizalign,left;x,SCREEN_RIGHT;vertalign,top;y,SCREEN_TOP;zoomy,0.4;;zoomx,-0.6;diffusealpha,0.3;blend,Blend.Add); -}; - - --- WAVY LINE (thanks AJ) //////////////////////// - - ---P1 -t[#t+1] = LoadActor("hot_lores") .. { - OnCommand=cmd(diffusealpha,0;visible,GAMESTATE:IsHumanPlayer(PLAYER_1);horizalign,left;x,SCREEN_LEFT+18;vertalign,top;y,SCREEN_TOP+16;zoomtowidth,SCREEN_WIDTH/2-26;texcoordvelocity,0.1,0;queuecommand,"Begin"); - BeginCommand=function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(false); - else - local move = GAMESTATE:GetSongBPS()/2 - if GAMESTATE:GetSongFreeze() then - move = 0; - end - self:texcoordvelocity(move,0); - self:sleep(0.001); - self:queuecommand("Begin"); - end; - end; - LifeChangedMessageCommand=function(self,params) - if params.Player == PLAYER_1 then - local lifeP1=params.LifeMeter:GetLife(); - if lifeP1>=THEME:GetMetric("LifeMeterBar", "HotValue") then - self:diffusealpha(0.5); - else - self:diffusealpha(0); - end; - end; - end; -}; - ---P2 -t[#t+1] = LoadActor("hot_lores") .. { - OnCommand=cmd(diffusealpha,0;visible,GAMESTATE:IsHumanPlayer(PLAYER_2);horizalign,left;x,SCREEN_RIGHT-18;vertalign,top;y,SCREEN_TOP+16;zoomtowidth,(SCREEN_WIDTH/2-26)*-1;texcoordvelocity,0.1,0;queuecommand,"Begin"); - BeginCommand=function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(false); - else - local move = GAMESTATE:GetSongBPS()/2 - if GAMESTATE:GetSongFreeze() then - move = 0; - end - self:texcoordvelocity(move,0); - self:sleep(0.001); - self:queuecommand("Begin"); - end; - end; - LifeChangedMessageCommand=function(self,params) - if params.Player == PLAYER_2 then - local lifeP2=params.LifeMeter:GetLife(); - if lifeP2>=THEME:GetMetric("LifeMeterBar", "HotValue") then - self:diffusealpha(0.5); - else - self:diffusealpha(0); - end; - end; - end; -}; - ---Double ---customtexturerect,0,0,[PixelsToCoverWidth]/[ImageWidth],[PixelsToCoverHeight]/[ImageHeight] ---I said that I was gonna write it down. thx midi - -t[#t+1] = LoadActor("hot_lores") .. { - OnCommand=cmd(diffusealpha,0;horizalign,left;x,SCREEN_LEFT+18;vertalign,top;y,SCREEN_TOP+16;zoomtowidth,SCREEN_WIDTH-36;texcoordvelocity,0.1,0;customtexturerect,0,0,600/(SCREEN_WIDTH-36),1;queuecommand,"Begin"); - BeginCommand=function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - local move = GAMESTATE:GetSongBPS()/2 - if GAMESTATE:GetSongFreeze() then - move = 0; - end - self:texcoordvelocity(move,0); - self:sleep(0.001); - self:queuecommand("Begin"); - else - self:visible(false); - end; - end; - LifeChangedMessageCommand=function(self,params) - local life=params.LifeMeter:GetLife(); - if life>=THEME:GetMetric("LifeMeterBar", "HotValue") then - self:diffusealpha(0.5); - else - self:diffusealpha(0); - end; - end; -}; - - --- DANGER //////////////////////// - - ---DANGER P1 single -t[#t+1] = LoadActor("danger") .. { - InitCommand=cmd(visible,GAMESTATE:IsHumanPlayer(PLAYER_1);horizalign,left;x,SCREEN_LEFT+18;vertalign,top;y,SCREEN_TOP+16;zoomtowidth,SCREEN_WIDTH/2-26;zoomy,0.5); - OnCommand=cmd(effectclock,"bgm";diffusealpha,1;linear,0.2;diffusealpha,0.25;linear,0.2;diffusealpha,1;queuecommand,"On"); - LifeChangedMessageCommand=function(self,params) - if params.Player == PLAYER_1 then - local lifeP1 = params.LifeMeter:GetLife(); - if lifeP1 <= THEME:GetMetric("LifeMeterBar", "DangerThreshold") then - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(false); - else - self:visible(true); - end; - else - self:visible(false); - end; - end; -end; - -}; - ---DANGER P2 single -t[#t+1] = LoadActor("danger") .. { - InitCommand=cmd(visible,GAMESTATE:IsHumanPlayer(PLAYER_2);horizalign,right;x,SCREEN_RIGHT-18;vertalign,top;y,SCREEN_TOP+16;zoomtowidth,SCREEN_WIDTH/2-26;zoomy,0.5); - OnCommand=cmd(effectclock,"bgm";diffusealpha,1;linear,0.2;diffusealpha,0.25;linear,0.2;diffusealpha,1;queuecommand,"On"); - LifeChangedMessageCommand=function(self,params) - if params.Player == PLAYER_2 then - local lifeP2 = params.LifeMeter:GetLife(); - if lifeP2 <= THEME:GetMetric("LifeMeterBar", "DangerThreshold") then - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(false); - else - self:visible(true); - end; - else - self:visible(false); - end; - end; - end; -}; - ---DANGER double -t[#t+1] = LoadActor("danger") .. { - InitCommand=cmd(visible,false;horizalign,center;x,SCREEN_CENTER_X;vertalign,top;y,SCREEN_TOP+16;zoomtowidth,SCREEN_WIDTH-36;zoomy,0.5); - OnCommand=cmd(effectclock,"bgm";diffusealpha,1;linear,0.2;diffusealpha,0.25;linear,0.2;diffusealpha,1;queuecommand,"On"); - LifeChangedMessageCommand=function(self,params) - local life = params.LifeMeter:GetLife(); - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - if life <= THEME:GetMetric("LifeMeterBar", "DangerThreshold") then - self:visible(true); - else - self:visible(false); - end; - end; - end; -}; - - - --- METERS //////////////////////// - - - - - ----basemeter masked P1 -t[#t+1] = LoadActor("basemeter") .. { - InitCommand=cmd(visible,GAMESTATE:IsHumanPlayer(PLAYER_1);horizalign,left;x,SCREEN_LEFT+18;valign,0.5;y,SCREEN_TOP+41;zoomy,0.5;blend,Blend.Add); - OnCommand=cmd(bounce;effectmagnitude,-40,0,0;effectclock,"bgm";effecttiming,2,0,0,0;); - LifeChangedMessageCommand=function(self,params) - if params.Player == PLAYER_1 then - local style = GAMESTATE:GetCurrentStyle(); - local lifeP1 = params.LifeMeter:GetLife(); - if GAMESTATE:IsHumanPlayer(PLAYER_1)==true then - if lifeP1==0 then - self:visible(false); - else - - if lifeP1==1 then - self:effectmagnitude(0,0,0); - else - self:effectmagnitude(-40,0,0); - end; - - self:visible(true); - end - end - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:zoomtowidth((SCREEN_WIDTH-40)*lifeP1+5); - else - self:zoomtowidth((SCREEN_WIDTH/2-26)*lifeP1); - end; - - end; - end; - -}; - - - - - - - ----basemeter masked P2 -t[#t+1] = LoadActor("basemeter") .. { - InitCommand=cmd(visible,GAMESTATE:IsHumanPlayer(PLAYER_2);horizalign,right;x,SCREEN_RIGHT+18;valign,0.5;y,SCREEN_TOP+41;zoomy,0.5;blend,Blend.Add;queuecommand,"Set"); - OnCommand=cmd(bob;effectmagnitude,40,0,0;effectclock,"bgm";effecttiming,1,0,0,0;); - SetCommand=function(self,params) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:effectmagnitude(-40,0,0); - self:horizalign(left); - self:x(SCREEN_LEFT+18); - end; - end; - - LifeChangedMessageCommand=function(self,params) - if params.Player == PLAYER_2 then - local style = GAMESTATE:GetCurrentStyle(); - local lifeP2 = params.LifeMeter:GetLife(); - if GAMESTATE:IsHumanPlayer(PLAYER_2)==true then - if lifeP2==0 then - self:visible(false); - else - - if lifeP2==1 then - self:effectmagnitude(0,0,0); - else - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:effectmagnitude(-40,0,0); - else - self:effectmagnitude(40,0,0); - end - end; - - self:visible(true); - end - end - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:zoomtowidth((SCREEN_WIDTH-40)*lifeP2); - else - self:zoomtowidth(((SCREEN_WIDTH/2-26)*lifeP2)+40); - end; - - end; - end; - -}; - - - - --- FRAMES & TIPS //////////////////////// - - --- Left Corner -t[#t+1] = LoadActor("mask") .. { - OnCommand=cmd(horizalign,right;x,SCREEN_LEFT+130;vertalign,top;y,SCREEN_TOP+12;zoom,0.45;queuecommand,"Set"); - SetCommand = function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(true); - else - if GAMESTATE:IsHumanPlayer(PLAYER_1) == true then - self:visible(true); - else - self:visible(false); - end; - end; - end; -}; - --- Right Corner -t[#t+1] = LoadActor("mask") .. { - OnCommand=cmd(horizalign,right;x,SCREEN_RIGHT-130;vertalign,top;y,SCREEN_TOP+12;zoomx,-0.45;zoomy,0.45;queuecommand,"Set"); -SetCommand = function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(true); - else - if GAMESTATE:IsHumanPlayer(PLAYER_2) == true then - self:visible(true); - else - self:visible(false); - end; - end; - end; -}; - - --- Left Corner -t[#t+1] = LoadActor("corner") .. { - OnCommand=cmd(horizalign,left;x,SCREEN_LEFT+15;vertalign,top;y,SCREEN_TOP+16;zoom,0.75;queuecommand,"Set"); - SetCommand = function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(true); - else - if GAMESTATE:IsHumanPlayer(PLAYER_1) == true then - self:visible(true); - else - self:visible(false); - end; - end; - end; -}; - --- Right Corner -t[#t+1] = LoadActor("corner") .. { - OnCommand=cmd(horizalign,left;x,SCREEN_RIGHT-15;vertalign,top;y,SCREEN_TOP+16;zoomx,-0.75;zoomy,0.75;queuecommand,"Set"); -SetCommand = function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(true); - else - if GAMESTATE:IsHumanPlayer(PLAYER_2) == true then - self:visible(true); - else - self:visible(false); - end; - end; - end; -}; - --- Center Corner Left -t[#t+1] = LoadActor("center") .. { - OnCommand=cmd(horizalign,left;x,SCREEN_CENTER_X+5;vertalign,top;y,SCREEN_TOP+16;zoomx,-0.75;zoomy,0.75;queuecommand,"Set"); - SetCommand = function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(false); - else - if GAMESTATE:IsHumanPlayer(PLAYER_1) == true then - self:visible(true); - else - self:visible(false); - end; - end; - end; -}; - --- Center Corner Right -t[#t+1] = LoadActor("center") .. { - OnCommand=cmd(horizalign,left;x,SCREEN_CENTER_X-5;vertalign,top;y,SCREEN_TOP+16;zoom,0.75;queuecommand,"Set"); - SetCommand = function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(false); - else - if GAMESTATE:IsHumanPlayer(PLAYER_2) == true then - self:visible(true); - else - self:visible(false); - end; - end; - end; -}; - --- Center part 1 -t[#t+1] = LoadActor("frame") .. { - OnCommand=cmd(visible,GAMESTATE:IsHumanPlayer(PLAYER_1);horizalign,left;x,SCREEN_LEFT+52.5;vertalign,top;y,SCREEN_TOP+16;zoomtowidth,SCREEN_WIDTH/2-85;zoomy,0.75;queuecommand,"Set";); - SetCommand = function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:zoomtowidth(SCREEN_WIDTH-105); - self:visible(true) - else - if GAMESTATE:IsHumanPlayer(PLAYER_1) == false then - self:visible(false) - else - self:visible(true) - end - end; - end; -}; - --- Center part 2 -t[#t+1] = LoadActor("frame") .. { - OnCommand=cmd(horizalign,right;x,SCREEN_RIGHT-52.5;vertalign,top;y,SCREEN_TOP+16;zoomtowidth,SCREEN_WIDTH/2-85;zoomy,0.75;queuecommand,"Set";); - SetCommand = function(self) - local style = GAMESTATE:GetCurrentStyle(); - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:visible(false) - else - if GAMESTATE:IsHumanPlayer(PLAYER_2) == true then - self:visible(true) - else - self:visible(false) - end; - end; - end; -}; - - - ----tip P1 -t[#t+1] = LoadActor("tip") .. { - InitCommand=cmd(visible,GAMESTATE:IsHumanPlayer(PLAYER_1);valign,0.5;y,SCREEN_TOP+41;zoom,0.5;blend,Blend.Add;queuecommand,"Set"); - --OnCommand=cmd(bob;effectmagnitude,-40,0,0;effectclock,"bgm";effecttiming,1,0,0,0;); - LifeChangedMessageCommand=function(self,params) - if params.Player == PLAYER_1 then - local style = GAMESTATE:GetCurrentStyle(); - local lifeP1 = params.LifeMeter:GetLife(); - if GAMESTATE:IsHumanPlayer(PLAYER_1)==true then - if lifeP1==0 then - self:visible(false); - else - self:visible(true); - end - end - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:x((SCREEN_WIDTH-40)*lifeP1+20); - else - self:x((SCREEN_WIDTH/2-26)*lifeP1+20); - end; - - end; - end; - -}; - - - ----tip P2 -t[#t+1] = LoadActor("tip") .. { - InitCommand=cmd(visible,GAMESTATE:IsHumanPlayer(PLAYER_2);valign,0.5;y,SCREEN_TOP+41;zoom,0.5;blend,Blend.Add;); - --OnCommand=cmd(bob;effectmagnitude,40,0,0;effectclock,"bgm";effecttiming,1,0,0,0;); - LifeChangedMessageCommand=function(self,params) - if params.Player == PLAYER_2 then - local style = GAMESTATE:GetCurrentStyle(); - local lifeP2 = params.LifeMeter:GetLife(); - local fullstate; - if GAMESTATE:IsHumanPlayer(PLAYER_2)==true then - if lifeP2==0 then - self:visible(false); - else - self:visible(true); - end - end - if style:GetStyleType() == "StyleType_OnePlayerTwoSides" then - self:x((SCREEN_WIDTH-40)*lifeP2+20); - else - self:x(SCREEN_RIGHT-((SCREEN_WIDTH/2-26)*lifeP2)-20); - end; - - end; - end; - -}; - --- NAMES //////////////////////// - ---P1 NAME -t[#t+1] = LoadFont("Common Normal") .. { - InitCommand=cmd(horizalign,left;x,SCREEN_LEFT+30;y,SCREEN_TOP+15;zoom,0.4;shadowlength,1;uppercase,true); - BeginCommand=function(self) - local profile = PROFILEMAN:GetProfile(PLAYER_1); - local name = profile:GetDisplayName(); - - if GAMESTATE:IsHumanPlayer(PLAYER_1) == true then - if name=="" then - self:settext("Player 1"); - else - self:settext( name ); - end - end - - end; - - }; - ---P2 NAME -t[#t+1] = LoadFont("Common Normal") .. { - InitCommand=cmd(horizalign,right;x,SCREEN_RIGHT-30;y,SCREEN_TOP+15;zoom,0.4;shadowlength,1;uppercase,true); - BeginCommand=function(self) - local profile = PROFILEMAN:GetProfile(PLAYER_2); - local name = profile:GetDisplayName(); - - if GAMESTATE:IsHumanPlayer(PLAYER_2) == true then - if name=="" then - self:settext("Player 2"); - else - self:settext( name ); - end - end - end; - - }; - - - -return t \ No newline at end of file diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/hot_lores.png b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/hot_lores.png deleted file mode 100644 index 6b2698696e..0000000000 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/hot_lores.png and /dev/null differ diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/mask.png b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/mask.png deleted file mode 100644 index 94585b3638..0000000000 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/mask.png and /dev/null differ diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/meter.png b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/meter.png deleted file mode 100644 index 983338f40a..0000000000 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/meter.png and /dev/null differ diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/tip.png b/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/tip.png deleted file mode 100644 index 05b8c15fd5..0000000000 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/tip.png and /dev/null differ diff --git a/Themes/default-dev-midi/Graphics/Player judgment/default.lua b/Themes/default-dev-midi/Graphics/Player judgment/default.lua deleted file mode 100644 index 74dba2343c..0000000000 --- a/Themes/default-dev-midi/Graphics/Player judgment/default.lua +++ /dev/null @@ -1,250 +0,0 @@ -local c; -local player = Var "Player"; -local bShowProtiming = GetUserPrefB("UserPrefProtiming" .. ToEnumShortString(player) ); - -local function MakeAverage( t ) - local sum = 0; - for i=1,#t do - sum = sum + t[i]; - end - return sum / #t -end - --- New -local function PosCount( t ) - local Count = 0; - for i=1,#t do - if t[i] > 0 then Count = Count + 1 end - end - return Count -end - -local function NegCount( t ) - local Count = 0; - for i=1,#t do - if t[i] < 0 then Count = Count + 1 end - end - return Count -end - - -local function StdDev( t ) - local avg = MakeAverage( t ); - local sum = 0; - for i=1,#t do - sum = sum + math.pow(t[i] - avg, 2); - end - return math.sqrt(sum / (#t - 1)) -end - --- -local tTotalJudgments = {}; --- Global? ---[[ tPlayerData = {}; -for pn in ivalues(GAMESTATE:GetHumanPlayers()) - tPlayerData[pn].SignedJudgments = {}; - tPlayerData[pn].AverageDifference = 0; - tPlayerData[pn].AbsoluteDifference = 0; - tPlayerData[pn].StandardDeviation = 0; - tPlayerData[pn].StandardDeviation = 0; - tPlayerData[pn].Early = 0; - tPlayerData[pn].Late = 0; -end ]] --- -local JudgeCmds = { - TapNoteScore_W1 = THEME:GetMetric( "Judgment", "JudgmentW1Command" ); - TapNoteScore_W2 = THEME:GetMetric( "Judgment", "JudgmentW2Command" ); - TapNoteScore_W3 = THEME:GetMetric( "Judgment", "JudgmentW3Command" ); - TapNoteScore_W4 = THEME:GetMetric( "Judgment", "JudgmentW4Command" ); - TapNoteScore_W5 = THEME:GetMetric( "Judgment", "JudgmentW5Command" ); - TapNoteScore_Miss = THEME:GetMetric( "Judgment", "JudgmentMissCommand" ); -}; - -local ProtimingCmds = { - TapNoteScore_W1 = THEME:GetMetric( "Protiming", "ProtimingW1Command" ); - TapNoteScore_W2 = THEME:GetMetric( "Protiming", "ProtimingW2Command" ); - TapNoteScore_W3 = THEME:GetMetric( "Protiming", "ProtimingW3Command" ); - TapNoteScore_W4 = THEME:GetMetric( "Protiming", "ProtimingW4Command" ); - TapNoteScore_W5 = THEME:GetMetric( "Protiming", "ProtimingW5Command" ); - TapNoteScore_Miss = THEME:GetMetric( "Protiming", "ProtimingMissCommand" ); -}; - -local AverageCmds = { - Pulse = THEME:GetMetric( "Protiming", "AveragePulseCommand" ); -}; - -local TNSFrames = { - TapNoteScore_W1 = 0; - TapNoteScore_W2 = 1; - TapNoteScore_W3 = 2; - TapNoteScore_W4 = 3; - TapNoteScore_W5 = 4; - TapNoteScore_Miss = 5; -}; -local t = Def.ActorFrame {}; -t[#t+1] = Def.ActorFrame { - LoadActor(THEME:GetPathG("Judgment","Normal")) .. { - Name="Judgment"; - InitCommand=cmd(pause;visible,false); - OnCommand=THEME:GetMetric("Judgment","JudgmentOnCommand"); - ResetCommand=cmd(finishtweening;stopeffect;visible,false); - }; - LoadFont("Combo Numbers") .. { - Name="ProtimingDisplay"; - Text=""; - InitCommand=cmd(visible,false); - OnCommand=THEME:GetMetric("Protiming","ProtimingOnCommand"); - ResetCommand=cmd(finishtweening;stopeffect;visible,false); - }; - LoadFont("Common Normal") .. { - Name="ProtimingAverage"; - Text=""; - InitCommand=cmd(visible,false); - OnCommand=THEME:GetMetric("Protiming","AverageOnCommand"); - ResetCommand=cmd(finishtweening;stopeffect;visible,false); - }; - Def.Quad { - Name="ProtimingGraphBG"; - InitCommand=cmd(visible,false;y,32;zoomto,192,16); - ResetCommand=cmd(finishtweening;diffusealpha,0.8;visible,false); - OnCommand=cmd(diffuse,Color("Black");diffusetopedge,color("0.1,0.1,0.1,1");diffusealpha,0.8;shadowlength,2;); - }; - Def.Quad { - Name="ProtimingGraphWindowW3"; - InitCommand=cmd(visible,false;y,32;zoomto,192-4,16-4); - ResetCommand=cmd(finishtweening;diffusealpha,1;visible,false); - OnCommand=cmd(diffuse,GameColor.Judgment["JudgmentLine_W3"];); - }; - Def.Quad { - Name="ProtimingGraphWindowW2"; - InitCommand=cmd(visible,false;y,32;zoomto,scale(PREFSMAN:GetPreference("TimingWindowSecondsW2"),0,PREFSMAN:GetPreference("TimingWindowSecondsW3"),0,192-4),16-4); - ResetCommand=cmd(finishtweening;diffusealpha,1;visible,false); - OnCommand=cmd(diffuse,GameColor.Judgment["JudgmentLine_W2"];); - }; - Def.Quad { - Name="ProtimingGraphWindowW1"; - InitCommand=cmd(visible,false;y,32;zoomto,scale(PREFSMAN:GetPreference("TimingWindowSecondsW1"),0,PREFSMAN:GetPreference("TimingWindowSecondsW3"),0,192-4),16-4); - ResetCommand=cmd(finishtweening;diffusealpha,1;visible,false); - OnCommand=cmd(diffuse,GameColor.Judgment["JudgmentLine_W1"];); - }; - Def.Quad { - Name="ProtimingGraphUnderlay"; - InitCommand=cmd(visible,false;y,32;zoomto,192-4,16-4); - ResetCommand=cmd(finishtweening;diffusealpha,0.25;visible,false); - OnCommand=cmd(diffuse,Color("Black");diffusealpha,0.25); - }; - Def.Quad { - Name="ProtimingGraphFill"; - InitCommand=cmd(visible,false;y,32;zoomto,0,16-4;horizalign,left;); - ResetCommand=cmd(finishtweening;diffusealpha,1;visible,false); - OnCommand=cmd(diffuse,Color("Red");); - }; - Def.Quad { - Name="ProtimingGraphAverage"; - InitCommand=cmd(visible,false;y,32;zoomto,2,7;); - ResetCommand=cmd(finishtweening;diffusealpha,0.85;visible,false); - OnCommand=cmd(diffuse,Color("Orange");diffusealpha,0.85); - }; - Def.Quad { - Name="ProtimingGraphCenter"; - InitCommand=cmd(visible,false;y,32;zoomto,2,16-4;); - ResetCommand=cmd(finishtweening;diffusealpha,1;visible,false); - OnCommand=cmd(diffuse,Color("White");diffusealpha,1); - }; - InitCommand = function(self) - c = self:GetChildren(); - end; - - JudgmentMessageCommand=function(self, param) - if param.Player ~= player then return end; - if param.HoldNoteScore then return end; - - local iNumStates = c.Judgment:GetNumStates(); - local iFrame = TNSFrames[param.TapNoteScore]; - - if not iFrame then return end - if iNumStates == 12 then - iFrame = iFrame * 2; - if not param.Early then - iFrame = iFrame + 1; - end - end - - - local fTapNoteOffset = param.TapNoteOffset; - if param.HoldNoteScore then - fTapNoteOffset = 1; - else - fTapNoteOffset = param.TapNoteOffset; - end - - if param.TapNoteScore == 'TapNoteScore_Miss' then - fTapNoteOffset = 1; - bUseNegative = true; - else --- fTapNoteOffset = fTapNoteOffset; - bUseNegative = false; - end; - - if fTapNoteOffset ~= 1 then - -- we're safe, you can push the values - tTotalJudgments[#tTotalJudgments+1] = bUseNegative and fTapNoteOffset or math.abs( fTapNoteOffset ); - -- New --- tPlayerData[player].SignedJudgments[#(tPlayerData[player].SignedJudgments)+1] = fTapNoteOffset; --- table.getn(tPlayerData[player].SignedJudgments = bUseNegative and fTapNoteOffset or fTapNoteOffset; - end - - self:playcommand("Reset"); - - c.Judgment:visible( not bShowProtiming ); - c.Judgment:setstate( iFrame ); - JudgeCmds[param.TapNoteScore](c.Judgment); - - c.ProtimingDisplay:visible( bShowProtiming ); - c.ProtimingDisplay:settextf("%i",math.abs(fTapNoteOffset * 1000)); - ProtimingCmds[param.TapNoteScore](c.ProtimingDisplay); - - c.ProtimingAverage:visible( bShowProtiming ); - c.ProtimingAverage:settextf("%.2f%%",clamp(100 - MakeAverage( tTotalJudgments ) * 1000 ,0,100)); - AverageCmds['Pulse'](c.ProtimingAverage); - - c.ProtimingGraphBG:visible( bShowProtiming ); - c.ProtimingGraphUnderlay:visible( bShowProtiming ); - c.ProtimingGraphWindowW3:visible( bShowProtiming ); - c.ProtimingGraphWindowW2:visible( bShowProtiming ); - c.ProtimingGraphWindowW1:visible( bShowProtiming ); - c.ProtimingGraphFill:visible( bShowProtiming ); - c.ProtimingGraphFill:finishtweening(); - c.ProtimingGraphFill:decelerate(1/60); --- c.ProtimingGraphFill:zoomtowidth( clamp(fTapNoteOffset * 188,-188/2,188/2) ); - c.ProtimingGraphFill:zoomtowidth( clamp( - scale( - fTapNoteOffset, - 0,PREFSMAN:GetPreference("TimingWindowSecondsW3"), - 0,188/2), - -188/2,188/2) - ); - c.ProtimingGraphAverage:visible( bShowProtiming ); - c.ProtimingGraphAverage:zoomtowidth( clamp( - scale( - MakeAverage( tTotalJudgments ), - 0,PREFSMAN:GetPreference("TimingWindowSecondsW3"), - 0,188), - 0,188) - ); --- c.ProtimingGraphAverage:zoomtowidth( clamp(MakeAverage( tTotalJudgments ) * 1880,0,188) ); - c.ProtimingGraphCenter:visible( bShowProtiming ); - (cmd(sleep,2;linear,0.5;diffusealpha,0))(c.ProtimingGraphBG); - (cmd(sleep,2;linear,0.5;diffusealpha,0))(c.ProtimingGraphUnderlay); - (cmd(sleep,2;linear,0.5;diffusealpha,0))(c.ProtimingGraphWindowW3); - (cmd(sleep,2;linear,0.5;diffusealpha,0))(c.ProtimingGraphWindowW2); - (cmd(sleep,2;linear,0.5;diffusealpha,0))(c.ProtimingGraphWindowW1); - (cmd(sleep,2;linear,0.5;diffusealpha,0))(c.ProtimingGraphFill); - (cmd(sleep,2;linear,0.5;diffusealpha,0))(c.ProtimingGraphAverage); - (cmd(sleep,2;linear,0.5;diffusealpha,0))(c.ProtimingGraphCenter); - end; - -}; - - -return t; diff --git a/Themes/default-dev-midi/metrics.ini b/Themes/default-dev-midi/metrics.ini index e2eab4c818..2f0e2571a5 100644 --- a/Themes/default-dev-midi/metrics.ini +++ b/Themes/default-dev-midi/metrics.ini @@ -1,5 +1,8 @@ [Global] FallbackTheme=default +[ScreenTitleMenu] +ChoiceNames="1,4,5,6,PopScreen,7" +ChoicePopScreen="name,Boobs;text,Boobs"; [ScreenGameplay] -LifeP1OnCommand=visible,false -LifeP2OnCommand=visible,false \ No newline at end of file +# LifeP1OnCommand=visible,false +# LifeP2OnCommand=visible,false diff --git a/Themes/default/BGAnimations/ScreenCredits background/default.lua b/Themes/default/BGAnimations/ScreenCredits background/default.lua index 47e9237339..8cd4a8ea35 100644 --- a/Themes/default/BGAnimations/ScreenCredits background/default.lua +++ b/Themes/default/BGAnimations/ScreenCredits background/default.lua @@ -13,7 +13,7 @@ local t = Def.ActorFrame { LoadActor("_grid")..{ InitCommand=cmd(customtexturerect,0,0,(SCREEN_WIDTH+1)/4,SCREEN_HEIGHT/4;SetTextureFiltering,true); OnCommand=cmd(zoomto,SCREEN_WIDTH+1,SCREEN_HEIGHT;diffuse,Color("Black");diffuseshift;effecttiming,(1/8)*4,0,(7/8)*4,0;effectclock,'beatnooffset'; - effectcolor2,Color("Black");effectcolor1,Colors.Alpha(Color("Black"),0.45);fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480;diffusealpha,0.345); + effectcolor2,Color("Black");effectcolor1,Color.Alpha(Color("Black"),0.45);fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480;diffusealpha,0.345); }; }; diff --git a/Themes/default/BGAnimations/ScreenCredits overlay.lua b/Themes/default/BGAnimations/ScreenCredits overlay.lua index 6c06c5b06a..6d9b73f724 100644 --- a/Themes/default/BGAnimations/ScreenCredits overlay.lua +++ b/Themes/default/BGAnimations/ScreenCredits overlay.lua @@ -40,9 +40,10 @@ local stepmania = { local contrib = { "Aldo Fregoso (Aldo_MX)", -- delays - "Chris Eldridge (kurisu)", -- dance-threepanel "cerbo", "cesarmades", -- pump/cmd* noteskins + "Chris Eldridge (kurisu)", -- dance-threepanel + "Christophe Goulet-LeBlanc (Kommisar)", "corec", -- various fixes "galopin", -- piu PlayStation2 usb mat support "gholms", -- automake 1.11 support @@ -51,6 +52,7 @@ local contrib = { "NitroX72", -- pump/frame noteskin "sy567", -- beginner helper fix "v1toko", -- x-mode from StepNXA + "waiei", -- custom scoring fixes + Hybrid scoring } local thanks = { @@ -70,12 +72,13 @@ local thanks = { local shoutout = { "The Lua team", -- lua project lead or some shit. super nerdy but oh hell. - "Mojang", -- minecraft forever -freem + "Mojang AB", -- minecraft forever -freem "Wolfire Games", -- piles of inspiration "NAKET Coder", "Ciera Boyd", -- you bet your ass I'm putting my girlfriend in the credits --Image(), -- we should have some logos probably to look super pro -- "Can't stop crying... buckets of tears!" + "#KBO", "AJ Kelly, without which this game would have never been.", "You showed us... your ultimate dance", } diff --git a/Themes/default/BGAnimations/ScreenEvaluation background/default.lua b/Themes/default/BGAnimations/ScreenEvaluation background/default.lua index ac0c710158..5cd05e9772 100644 --- a/Themes/default/BGAnimations/ScreenEvaluation background/default.lua +++ b/Themes/default/BGAnimations/ScreenEvaluation background/default.lua @@ -5,7 +5,10 @@ t[#t+1] = Def.ActorFrame { Def.Sprite { OnCommand=function(self) if GAMESTATE:GetCurrentSong() then - self:LoadBackground( GAMESTATE:GetCurrentSong():GetBackgroundPath() ); + local song = GAMESTATE:GetCurrentSong(); + if song:HasBackground() then + self:LoadBackground(song:GetBackgroundPath()); + end; self:scaletoclipped( SCREEN_WIDTH+1,SCREEN_HEIGHT ); (cmd(fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480))(self); else diff --git a/Themes/default/BGAnimations/ScreenEvaluation overlay/default.lua b/Themes/default/BGAnimations/ScreenEvaluation overlay/default.lua index f60350e627..cd8f3eac73 100644 --- a/Themes/default/BGAnimations/ScreenEvaluation overlay/default.lua +++ b/Themes/default/BGAnimations/ScreenEvaluation overlay/default.lua @@ -55,14 +55,14 @@ local function CreateStats( pnPlayer ) return t end; --- xxx: this only currently works for player 1. -aj local t = Def.ActorFrame {}; +GAMESTATE:IsPlayerEnabled(PLAYER_1) t[#t+1] = Def.ActorFrame { - InitCommand=cmd(x,WideScale(math.floor(SCREEN_CENTER_X*0.3)-8,math.floor(SCREEN_CENTER_X*0.5)-8);y,SCREEN_CENTER_Y); + InitCommand=cmd(hide_if,not GAMESTATE:IsPlayerEnabled(PLAYER_1);x,WideScale(math.floor(SCREEN_CENTER_X*0.3)-8,math.floor(SCREEN_CENTER_X*0.5)-8);y,SCREEN_CENTER_Y-34); CreateStats( PLAYER_1 ); }; t[#t+1] = Def.ActorFrame { - InitCommand=cmd(x,WideScale(math.floor(SCREEN_CENTER_X*1.7)+8,math.floor(SCREEN_CENTER_X*1.5)+8);y,SCREEN_CENTER_Y); + InitCommand=cmd(hide_if,not GAMESTATE:IsPlayerEnabled(PLAYER_2);x,WideScale(math.floor(SCREEN_CENTER_X*1.7)+8,math.floor(SCREEN_CENTER_X*1.5)+8);y,SCREEN_CENTER_Y-34); CreateStats( PLAYER_2 ); }; return t \ No newline at end of file diff --git a/Themes/default/BGAnimations/ScreenGameplay background.lua b/Themes/default/BGAnimations/ScreenGameplay background.lua new file mode 100644 index 0000000000..989e15f73d --- /dev/null +++ b/Themes/default/BGAnimations/ScreenGameplay background.lua @@ -0,0 +1 @@ +return Def.ActorFrame { Name="YOU_WISH_YOU_WERE_PLAYING_BEATMANIA_RIGHT_NOW" }; \ No newline at end of file diff --git a/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua b/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua index f46c102f86..815b30b141 100644 --- a/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua +++ b/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua @@ -1,47 +1,55 @@ -local function CreateStops() +local function CreateSegments(Player) local t = Def.ActorFrame { }; local bars = Def.ActorFrame{ }; local bpmFrame = Def.ActorFrame{ Name="BPMFrame"; }; local stopFrame = Def.ActorFrame{ Name="StopFrame"; }; + local delayFrame = Def.ActorFrame{ Name="DelayFrame"; }; + local warpFrame = Def.ActorFrame{ Name="WarpFrame"; }; + local fakeFrame = Def.ActorFrame{ Name="FakeFrame"; }; + local scrollFrame = Def.ActorFrame{ Name="ScrollFrame"; }; + local speedFrame = Def.ActorFrame{ Name="SpeedFrame"; }; local fFrameWidth = 380; local fFrameHeight = 8; -- XXX: doesn't work in course mode -aj - if not GAMESTATE:IsCourseMode() then + if not GAMESTATE:IsSideJoined( Player ) then + return t + elseif not GAMESTATE:IsCourseMode() then -- Straight rip off NCRX local song = GAMESTATE:GetCurrentSong(); - local timingData = song:GetTimingData(); + local steps = GAMESTATE:GetCurrentSteps( Player ); + local timingData = steps:GetTimingData(); -- if we're using SSC, might as well use the StepsSeconds, which will -- almost always be more proper than a r21'd file. if song then local songLen = song:MusicLengthSeconds(); - local firstBeatSecs = timingData:GetElapsedTimeFromBeat(song:GetFirstBeat()); - local lastBeatSecs = timingData:GetElapsedTimeFromBeat(song:GetLastBeat()); - - local bpms = timingData:GetBPMs(); + local firstBeatSecs = song:GetFirstSecond(); + local lastBeatSecs = song:GetLastSecond(); + local bpms = timingData:GetBPMsAndTimes(); local stops = timingData:GetStops(); - for i=1,#stops do - local data = split("=",stops[i]); - local beat = data[1]; - local secs = data[2]; + local delays = timingData:GetDelays(); + local warps = timingData:GetWarps(); + local fakes = timingData:GetFakes(); + local scrolls = timingData:GetScrolls(); + local speeds = timingData:GetSpeeds(); + + local function CreateLine(beat, secs, firstShadow, firstDiffuse, secondShadow, firstEffect, secondEffect) local beatTime = timingData:GetElapsedTimeFromBeat(beat); if beatTime < 0 then beatTime = 0; end; - - stopFrame[#stopFrame+1] = Def.ActorFrame { + return Def.ActorFrame { Def.Quad { InitCommand=function(self) - --self:diffuse(HSVA(192,1,0.8,0.8)); self:shadowlength(0); - self:shadowcolor( color("#FFFFFF77") ); + self:shadowcolor(color(firstShadow)); -- set width - self:zoomto( math.max((secs/songLen)*fFrameWidth, 1), fFrameHeight ); + self:zoomto(math.max((secs/songLen)*fFrameWidth, 1), fFrameHeight); -- find location - self:x( ( scale(beatTime, firstBeatSecs,lastBeatSecs, -fFrameWidth/2,fFrameWidth/2) ) ); + self:x((scale(beatTime,firstBeatSecs,lastBeatSecs,-fFrameWidth/2,fFrameWidth/2))); end; OnCommand=function(self) - self:diffuse(Color("White")); + self:diffuse(color(firstDiffuse)); self:sleep(beatTime+1); self:linear(2); self:diffusealpha(0); @@ -51,42 +59,89 @@ local function CreateStops() InitCommand=function(self) --self:diffuse(HSVA(192,1,0.8,0.8)); self:shadowlength(0); - self:shadowcolor( color("#FFFFFF77") ); + self:shadowcolor(color(secondShadow)); -- set width - self:zoomto( math.max((secs/songLen)*fFrameWidth, 1), fFrameHeight ); + self:zoomto(math.max((secs/songLen)*fFrameWidth, 1),fFrameHeight); -- find location - self:x( ( scale(beatTime, firstBeatSecs,lastBeatSecs, -fFrameWidth/2,fFrameWidth/2) ) ); + self:x((scale(beatTime,firstBeatSecs,lastBeatSecs,-fFrameWidth/2,fFrameWidth/2))); end; OnCommand=function(self) self:diffusealpha(1); self:diffuseshift(); - self:effectcolor1(Color("Orange")); - self:effectcolor2(Color("Red")); + self:effectcolor1(color(firstEffect)); + self:effectcolor2(color(secondEffect)); self:effectclock('beat'); self:effectperiod(1/8); -- self:diffusealpha(0); self:sleep(beatTime+1); - -- self:linear(1); self:diffusealpha(1); self:linear(4); self:diffusealpha(0); end; }; - --OnCommand=cmd(diffuse,Color("White");sleep,math.min(0.00001+(secs-5),0.00001);linear,1;diffuse,Color("Orange");sleep,4;linear,2;diffusealpha,0); - --OnCommand=cmd(diffuse,Color("White");linear,1;diffuse,Color("Orange");); }; end; + + for i=1,#bpms do + local data = split("=",bpms[i]); + bpmFrame[#bpmFrame+1] = CreateLine(data[1], 0, + "#00808077", "#00808077", "#00808077", "#FF634777", "#FF000077"); + end; + + for i=1,#delays do + local data = split("=",delays[i]); + delayFrame[#delayFrame+1] = CreateLine(data[1], data[2], + "#FFFF0077", "#FFFF0077", "#FFFF0077", "#00FF0077", "#FF000077"); + end; + + for i=1,#stops do + local data = split("=",stops[i]); + stopFrame[#stopFrame+1] = CreateLine(data[1], data[2], + "#FFFFFF77", "#FFFFFF77", "#FFFFFF77", "#FFA50077", "#FF000077"); + end; + + for i=1,#scrolls do + local data = split("=",scrolls[i]); + scrollFrame[#scrollFrame+1] = CreateLine(data[1], 0, + "#4169E177", "#4169E177", "#4169E177", "#0000FF77", "#FF000077"); + end; + + for i=1,#speeds do + local data = split("=",speeds[i]); + -- TODO: Turn beats into seconds for this calculation? + speedFrame[#speedFrame+1] = CreateLine(data[1], 0, + "#ADFF2F77", "#ADFF2F77", "#ADFF2F77", "#7CFC0077", "#FF000077"); + end; + + for i=1,#warps do + local data = split("=",warps[i]); + warpFrame[#warpFrame+1] = CreateLine(data[1], 0, + "#CC00CC77", "#CC00CC77", "#CC00CC77", "#FF33CC77", "#FF000077"); + end; + + for i=1,#fakes do + local data = split("=",fakes[i]); + fakeFrame[#fakeFrame+1] = CreateLine(data[1], 0, + "#BC8F8F77", "#BC8F8F77", "#BC8F8F77", "#F4A46077", "#FF000077"); + end; end; + bars[#bars+1] = bpmFrame; + bars[#bars+1] = scrollFrame; + bars[#bars+1] = speedFrame; bars[#bars+1] = stopFrame; + bars[#bars+1] = delayFrame; + bars[#bars+1] = warpFrame; + bars[#bars+1] = fakeFrame; t[#t+1] = bars; end return t end local t = LoadFallbackB() +t[#t+1] = StandardDecorationFromFileOptional("ScoreFrame","ScoreFrame"); for pn in ivalues(PlayerNumber) do --- local MetricsName = "SongMeterDisplay" .. PlayerNumberToString(pn); ---[[ t[#t+1] = Def.ActorFrame { + local MetricsName = "SongMeterDisplay" .. PlayerNumberToString(pn); + t[#t+1] = Def.ActorFrame { InitCommand=function(self) self:player(pn); self:name(MetricsName); @@ -117,8 +172,10 @@ for pn in ivalues(PlayerNumber) do }; Tip=LoadActor( THEME:GetPathG( 'SongMeterDisplay', 'tip ' .. PlayerNumberToString(pn) ) ) .. { InitCommand=cmd(visible,false); }; }; - CreateStops(); - }; --]] + CreateSegments(pn) .. { +-- InitCommand=cmd(draworder,10); + }; + }; end; for pn in ivalues(PlayerNumber) do local MetricsName = "ToastyDisplay" .. PlayerNumberToString(pn); @@ -131,43 +188,11 @@ for pn in ivalues(PlayerNumber) do }; end; -t[#t+1] = StandardDecorationFromFileOptional("ScoreFrame","ScoreFrame"); + t[#t+1] = StandardDecorationFromFileOptional("BPMDisplay","BPMDisplay"); t[#t+1] = StandardDecorationFromFileOptional("StageDisplay","StageDisplay"); t[#t+1] = StandardDecorationFromFileOptional("SongTitle","SongTitle"); -t[#t+1] = Def.ActorFrame { - InitCommand=function(self) - self:name("SongMeterDisplay"); - ActorUtil.LoadAllCommandsAndSetXY(self,Var "LoadingScreen"); - end; - LoadActor( THEME:GetPathG( 'SongMeterDisplay', 'frame ' .. PlayerNumberToString(PLAYER_1) ) ) .. { - InitCommand=function(self) - self:name('Frame'); - ActorUtil.LoadAllCommandsAndSetXY(self,"SongMeterDisplay"); - end; - }; - Def.Quad { - InitCommand=cmd(zoomto,2,8); - OnCommand=cmd(x,scale(0.25,0,1,-380/2,380/2);diffuse,Color("Orange");diffusealpha,0.5); - }; - Def.Quad { - InitCommand=cmd(zoomto,2,8); - OnCommand=cmd(x,scale(0.5,0,1,-380/2,380/2);diffuse,Color("Orange");diffusealpha,0.5); - }; - Def.Quad { - InitCommand=cmd(zoomto,2,8); - OnCommand=cmd(x,scale(0.75,0,1,-380/2,380/2);diffuse,Color("Orange");diffusealpha,0.5); - }; - Def.SongMeterDisplay { - InitCommand=cmd(SetStreamWidth,THEME:GetMetric( "SongMeterDisplay", 'StreamWidth' )); - Stream=LoadActor( THEME:GetPathG( 'SongMeterDisplay', 'stream ' .. PlayerNumberToString(PLAYER_1) ) )..{ - InitCommand=cmd(diffuse,Color("Orange");diffusealpha,0.5;blend,Blend.Add;); - }; - Tip=LoadActor( THEME:GetPathG( 'SongMeterDisplay', 'tip ' .. PlayerNumberToString(PLAYER_1) ) ) .. { InitCommand=cmd(visible,false); }; - }; - CreateStops(); -}; if( not GAMESTATE:IsCourseMode() ) then t[#t+1] = Def.Actor{ JudgmentMessageCommand = function(self, params) diff --git a/Themes/default/BGAnimations/ScreenGameplay next course song/default.lua b/Themes/default/BGAnimations/ScreenGameplay next course song/default.lua index de7cf0b949..732b6a912d 100644 --- a/Themes/default/BGAnimations/ScreenGameplay next course song/default.lua +++ b/Themes/default/BGAnimations/ScreenGameplay next course song/default.lua @@ -7,7 +7,7 @@ t[#t+1] = Def.Sprite { BeforeLoadingNextCourseSongMessageCommand=function(self) self:LoadFromSongBackground( SCREENMAN:GetTopScreen():GetNextCourseSong() ) end; ChangeCourseSongInMessageCommand=cmd(scaletoclipped,SCREEN_WIDTH,SCREEN_HEIGHT); StartCommand=cmd(diffusealpha,0;decelerate,0.5;diffusealpha,1;); - FinishCommand=cmd(linear,0.1;glow,Colors.Alpha(Color("White"),0.5);decelerate,0.4;glow,Color("Invisible");diffusealpha,0); + FinishCommand=cmd(linear,0.1;glow,Color.Alpha(Color("White"),0.5);decelerate,0.4;glow,Color("Invisible");diffusealpha,0); }; t[#t+1] = Def.ActorFrame { diff --git a/Themes/default/BGAnimations/ScreenPlayerOptions background.lua b/Themes/default/BGAnimations/ScreenPlayerOptions background.lua index a02c0291d9..f06580a070 100644 --- a/Themes/default/BGAnimations/ScreenPlayerOptions background.lua +++ b/Themes/default/BGAnimations/ScreenPlayerOptions background.lua @@ -6,7 +6,10 @@ t[#t+1] = Def.ActorFrame { Condition=not GAMESTATE:IsCourseMode(); OnCommand=function(self) if GAMESTATE:GetCurrentSong() then - self:LoadBackground( GAMESTATE:GetCurrentSong():GetBackgroundPath() ); + local song = GAMESTATE:GetCurrentSong(); + if song:HasBackground() then + self:LoadBackground(song:GetBackgroundPath()); + end; self:scaletoclipped( SCREEN_WIDTH+1,SCREEN_HEIGHT ); (cmd(fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480))(self); else @@ -21,7 +24,7 @@ t[#t+1] = Def.ActorFrame { --[[ LoadActor(THEME:GetPathB("ScreenWithMenuElements","background/_grid")).. { InitCommand=cmd(customtexturerect,0,0,(SCREEN_WIDTH+1)/4,SCREEN_HEIGHT/4;SetTextureFiltering,true); OnCommand=cmd(zoomto,SCREEN_WIDTH+1,SCREEN_HEIGHT;diffuse,Color("Black");diffuseshift;effecttiming,(1/8)*4,0,(7/8)*4,0;effectclock,'beatnooffset'; - effectcolor2,Color("Black");effectcolor1,Colors.Alpha(Color("Black"),0.45);fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480;diffusealpha,0.345); + effectcolor2,Color("Black");effectcolor1,Color.Alpha(Color("Black"),0.45);fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480;diffusealpha,0.345); }; --]] LoadActor(THEME:GetPathB("ScreenWithMenuElements","background/_bg top")) .. { InitCommand=cmd(scaletoclipped,SCREEN_WIDTH+1,SCREEN_HEIGHT); diff --git a/Themes/default/BGAnimations/ScreenTitleMenu underlay.lua b/Themes/default/BGAnimations/ScreenTitleMenu underlay.lua index 3f4af5add1..665a830d61 100644 --- a/Themes/default/BGAnimations/ScreenTitleMenu underlay.lua +++ b/Themes/default/BGAnimations/ScreenTitleMenu underlay.lua @@ -8,5 +8,25 @@ t[#t+1] = StandardDecorationFromFileOptional("LifeDifficulty","LifeDifficulty"); t[#t+1] = StandardDecorationFromFileOptional("TimingDifficulty","TimingDifficulty"); t[#t+1] = StandardDecorationFromFileOptional("NetworkStatus","NetworkStatus"); t[#t+1] = StandardDecorationFromFileOptional("SystemDirection","SystemDirection"); +-- +t[#t+1] = StandardDecorationFromFileOptional("NumSongs","NumSongs") .. { + SetCommand=function(self) + local InstalledSongs, AdditionalSongs, InstalledCourses, AdditionalCourses, Groups, Unlocked = 0; + if SONGMAN:GetRandomSong() then + InstalledSongs, AdditionalSongs, InstalledCourses, AdditionalCourses, Groups, Unlocked = + SONGMAN:GetNumSongs(), + SONGMAN:GetNumAdditionalSongs(), + SONGMAN:GetNumCourses(), + SONGMAN:GetNumAdditionalCourses(), + SONGMAN:GetNumSongGroups(), + SONGMAN:GetNumUnlockedSongs(); + else + return + end + + self:settextf("%i Songs (%i Groups), %i Courses", InstalledSongs, Groups, InstalledCourses); +-- self:settextf("%i (+%i) Songs (%i Groups), %i (+%i) Courses", InstalledSongs, AdditionalSongs, Groups, InstalledCourses, AdditionalCourses); + end; +}; return t \ No newline at end of file diff --git a/Themes/default/BGAnimations/ScreenWithMenuElements aux.lua b/Themes/default/BGAnimations/ScreenWithMenuElements aux.lua new file mode 100644 index 0000000000..f808d9d5e4 --- /dev/null +++ b/Themes/default/BGAnimations/ScreenWithMenuElements aux.lua @@ -0,0 +1,80 @@ +local function Clock() + function UpdateVisible(self) + local screen = SCREENMAN:GetTopScreen() + local bShow = true + if screen then + local sClass = screen:GetName() + bShow = THEME:GetMetric(sClass, "ShowClock") + end + if bShow then + self:smooth(0.25) + self:y(12) + else + self:smooth(0.25) + self:y(-56) + end + end + -- clock + clock = Def.ActorFrame { + Name="Clock", + InitCommand=cmd(x,50;y,12;playcommand,"Update"), + ScreenChangedMessageCommand=UpdateVisible, + UpdateCommand=cmd(runcommandsonleaves,cmd(queuecommand,"Update")), + Def.RoundedBox(90,26)..{ InitCommand=cmd(x,-22;y,-4) }, + Def.ActorFrame { + Name="ClockText", + InitCommand=cmd(y,-2), + LoadFont("Common", "normal")..{ + Text="00:00:", + InitCommand=cmd(horizalign,right;shadowlength,0;diffusebottomedge,color("0.9,0.9,0.9")), + UpdateCommand=function(self) + local hour, min = Hour(), Minute() + if hour > 12 and GetUserPrefB("Use12HourClock") then + hour = hour - 12 + elseif hour == 0 and GetUserPrefB("Use12HourClock") then + hour = 12 + end + self:settext(string.format('%02i:%02i:', hour, min)) + self:sleep(1) + self:queuecommand("Update") + end + }, + LoadFont("Common", "normal")..{ + Text="00", + InitCommand=cmd(horizalign,left;shadowlength,0;diffusebottomedge,color("0.9,0.9,0.9")), + UpdateCommand=function(self) + local sec = Second() + self:settext(string.format('%02i', sec)) + self:sleep(1) + self:queuecommand("Update") + end, + }, + LoadFont("Common", "normal")..{ + Text="", + InitCommand=cmd(x,28;y,-3;horizalign,left;shadowlength,0;diffusebottomedge,color("0.9,0.9,0.9");visible,false;zoom,0.75), + UpdateCommand=function(self) + if not GetUserPrefB("Use12HourClock") then + self:visible(false) + return + end + local hour = Hour() + if hour < 12 then + self:settext("AM") + self:diffuse(color("1,0.85,0,1")) + self:diffusebottomedge(color("0.75,0.55,0,1")) + else + self:settext("PM") + self:diffuse(color("0,0.85,1,1")) + self:diffusebottomedge(color("0,0.55,1,1")) + end + self:visible(true) + self:sleep(1) + self:queuecommand("Update") + end + } + } + } + return clock; +end +local t = Def.ActorFrame {}; +return t; \ No newline at end of file diff --git a/Themes/default/BGAnimations/ScreenWithMenuElements background/default.lua b/Themes/default/BGAnimations/ScreenWithMenuElements background/default.lua index 2a5ef20e90..73c5519edb 100644 --- a/Themes/default/BGAnimations/ScreenWithMenuElements background/default.lua +++ b/Themes/default/BGAnimations/ScreenWithMenuElements background/default.lua @@ -33,7 +33,7 @@ t[#t+1] = Def.ActorFrame { --[[ LoadActor("_grid") .. { InitCommand=cmd(customtexturerect,0,0,(SCREEN_WIDTH+1)/4,SCREEN_HEIGHT/4;SetTextureFiltering,true); OnCommand=cmd(zoomto,SCREEN_WIDTH+1,SCREEN_HEIGHT;diffuse,Color("Orange");diffuseshift;effecttiming,(1/8)*2,0,(7/8)*2,0;effectclock,'beatnooffset'; - effectcolor2,Color("Orange");effectcolor1,Colors.Alpha(Color("Orange"),0.45);fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480); + effectcolor2,Color("Orange");effectcolor1,Color.Alpha(Color("Orange"),0.45);fadebottom,0.25;fadetop,0.25;croptop,48/480;cropbottom,48/480); }; --]] LoadActor("_bg top") .. { InitCommand=cmd(scaletoclipped,SCREEN_WIDTH+1,SCREEN_HEIGHT); diff --git a/Themes/default/BGAnimations/_ScreenWithMenuElements aux.lua b/Themes/default/BGAnimations/_ScreenWithMenuElements aux.lua deleted file mode 100644 index b45f994ddf..0000000000 --- a/Themes/default/BGAnimations/_ScreenWithMenuElements aux.lua +++ /dev/null @@ -1 +0,0 @@ -local t = Def.ActorFrame {}; diff --git a/Themes/default/Graphics/CombinedLifeMeterTug separator.redir b/Themes/default/Graphics/CombinedLifeMeterTug separator.redir index 04b2ead777..65de2f434b 100644 --- a/Themes/default/Graphics/CombinedLifeMeterTug separator.redir +++ b/Themes/default/Graphics/CombinedLifeMeterTug separator.redir @@ -1 +1 @@ -_blank \ No newline at end of file +_CombinedLifeMeterTug separator \ No newline at end of file diff --git a/Themes/default/Graphics/PaneDisplay text.lua b/Themes/default/Graphics/PaneDisplay text.lua index 5a9983b945..3cc39b0512 100644 --- a/Themes/default/Graphics/PaneDisplay text.lua +++ b/Themes/default/Graphics/PaneDisplay text.lua @@ -83,8 +83,8 @@ local function CreatePaneDisplayGraph( _pnPlayer, _sLabel, _rcRadarCategory ) end; }; LoadFont("Common Normal") .. { - InitCommand=cmd(x,40;zoom,0.5;); - OnCommand=cmd(shadowlength,1;); + InitCommand=cmd(x,14;zoom,0.45;halign,0;); + OnCommand=cmd(shadowlength,1;strokecolor,color("0.15,0.15,0.15,0.625")); CurrentSongChangedMessageCommand=cmd(playcommand,"Set"); CurrentStepsP1ChangedMessageCommand=cmd(playcommand,"Set"); CurrentStepsP2ChangedMessageCommand=cmd(playcommand,"Set"); diff --git a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/frame (doubleres).png b/Themes/default/Graphics/Player Badge FullCombo.png similarity index 54% rename from Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/frame (doubleres).png rename to Themes/default/Graphics/Player Badge FullCombo.png index 8f4fb1191a..46688dc572 100644 Binary files a/Themes/default-dev-midi/BGAnimations/ScreenGameplay underlay/frame (doubleres).png and b/Themes/default/Graphics/Player Badge FullCombo.png differ diff --git a/Themes/default/Graphics/Player toasty/default.lua b/Themes/default/Graphics/Player toasty/default.lua index bbc4c72c04..206e223510 100644 --- a/Themes/default/Graphics/Player toasty/default.lua +++ b/Themes/default/Graphics/Player toasty/default.lua @@ -13,7 +13,7 @@ return Def.ActorFrame { InitCommand=cmd(zoomto,fWidth,SCREEN_HEIGHT;diffuse,PlayerColor(Player);diffusealpha,0;fadeleft,32/(256+16);faderight,32/(256+16)); ToastyAchievedMessageCommand=function(self,params) if params.PlayerNumber == Player then - (cmd(stoptweening;linear,2.125;diffuse,Colors.Alpha( PlayerColor(Player), 0.345 );glow,color("1,1,1,0.5");decelerate,3;glow,Colors.Alpha( ColorDarkTone( PlayerColor(Player) ), 0 );diffuseramp; + (cmd(stoptweening;linear,2.125;diffuse,Color.Alpha( PlayerColor(Player), 0.345 );glow,color("1,1,1,0.5");decelerate,3;glow,Color.Alpha( ColorDarkTone( PlayerColor(Player) ), 0 );diffuseramp; effectcolor1,ColorLightTone( PlayerColor(Player) );effectcolor2,PlayerColor(Player); effectclock,'beat';effectperiod,2; ))(self); @@ -23,7 +23,7 @@ return Def.ActorFrame { ToastyDroppedMessageCommand=function(self,params) if params.PlayerNumber == Player then if HasToasty then - (cmd(finishtweening;stopeffect;glow,color("1,1,1,0.5");decelerate,0.35;diffuse,Colors.Alpha( Color("Black"), 0.25 );glow,color("1,1,1,0");linear,0.35*0.25;diffusealpha,0))(self); + (cmd(finishtweening;stopeffect;glow,color("1,1,1,0.5");decelerate,0.35;diffuse,Color.Alpha( Color("Black"), 0.25 );glow,color("1,1,1,0");linear,0.35*0.25;diffusealpha,0))(self); HasToasty = false; else return diff --git a/Themes/default/Graphics/ScreenGameplay BPMDisplay.lua b/Themes/default/Graphics/ScreenGameplay BPMDisplay.lua index bb61014df0..37f11b81e4 100644 --- a/Themes/default/Graphics/ScreenGameplay BPMDisplay.lua +++ b/Themes/default/Graphics/ScreenGameplay BPMDisplay.lua @@ -38,6 +38,10 @@ else local stepsP1 = GAMESTATE:GetCurrentSteps(PLAYER_1) local stepsP2 = GAMESTATE:GetCurrentSteps(PLAYER_2) + if not stepsP1 or not stepsP2 then + return displaySingle + end + local stP1 = stepsP1:GetStepsType() local stP2 = stepsP2:GetStepsType() diff --git a/Themes/default/Graphics/ScreenGameplay StageDisplay.lua b/Themes/default/Graphics/ScreenGameplay StageDisplay.lua index a20a1c542f..81761ccc77 100644 --- a/Themes/default/Graphics/ScreenGameplay StageDisplay.lua +++ b/Themes/default/Graphics/ScreenGameplay StageDisplay.lua @@ -13,6 +13,7 @@ end for s in ivalues(Stage) do stages[#stages+1] = MakeBitmapTest() .. { + InitCommand=cmd(shadowlength,2); SetCommand=function(self, params) local Stage = GAMESTATE:GetCurrentStage(); local StageIndex = GAMESTATE:GetCurrentStageIndex(); diff --git a/Themes/default/Graphics/ScreenMapControllers exit.lua b/Themes/default/Graphics/ScreenMapControllers exit.lua new file mode 100644 index 0000000000..dda8c0fd5c --- /dev/null +++ b/Themes/default/Graphics/ScreenMapControllers exit.lua @@ -0,0 +1,10 @@ +return LoadFont("Common Normal") .. { + Text="Exit"; + InitCommand=cmd(x,SCREEN_CENTER_X;zoom,0.75;shadowlength,0;diffuse,color("#880000");NoStroke); + OnCommand=cmd(diffusealpha,0;decelerate,0.5;diffusealpha,1); + OffCommand=cmd(stoptweening;accelerate,0.3;diffusealpha,0;queuecommand,"Hide"); + HideCommand=cmd(hidden,true); + + GainFocusCommand=cmd(diffuseshift;effectcolor1,color("#FF2222");effectcolor2,color("#880000");); + LoseFocusCommand=cmd(stopeffect); +}; diff --git a/Themes/default/Graphics/ScreenMapControllers exit.redir b/Themes/default/Graphics/ScreenMapControllers exit.redir deleted file mode 100644 index 04b2ead777..0000000000 --- a/Themes/default/Graphics/ScreenMapControllers exit.redir +++ /dev/null @@ -1 +0,0 @@ -_blank \ No newline at end of file diff --git a/Themes/default/Graphics/ScreenSelectMusic DifficultyDisplay/default.lua b/Themes/default/Graphics/ScreenSelectMusic DifficultyDisplay/default.lua index 966f417b67..eeb4c57c79 100644 --- a/Themes/default/Graphics/ScreenSelectMusic DifficultyDisplay/default.lua +++ b/Themes/default/Graphics/ScreenSelectMusic DifficultyDisplay/default.lua @@ -70,7 +70,7 @@ for idx,diff in pairs(Difficulty) do Text=(sDifficulty == "Edit") and "0 Edits" or "0"; ShowCommand=cmd(stoptweening;linear,0.1;diffuse,CustomDifficultyToColor( sDifficulty )); HideCommand=cmd(stoptweening;decelerate,0.2;diffuse,CustomDifficultyToDarkColor( sDifficulty )); - InitCommand=cmd(x,-64-8+tLocation[sDifficulty];shadowlength,1;zoom,0.5;diffuse,CustomDifficultyToColor( sDifficulty )); + InitCommand=cmd(x,-64-8+tLocation[sDifficulty];shadowlength,1;zoom,0.75;diffuse,CustomDifficultyToColor( sDifficulty )); }; }; end diff --git a/Themes/default/Graphics/ScreenTitleMenu NumAdditionalSongs.lua b/Themes/default/Graphics/ScreenTitleMenu NumAdditionalSongs.lua new file mode 100644 index 0000000000..784c3f5c19 --- /dev/null +++ b/Themes/default/Graphics/ScreenTitleMenu NumAdditionalSongs.lua @@ -0,0 +1,2 @@ +return LoadFont("Common Normal") .. { +}; \ No newline at end of file diff --git a/Themes/default/Graphics/ScreenTitleMenu NumSongs.lua b/Themes/default/Graphics/ScreenTitleMenu NumSongs.lua new file mode 100644 index 0000000000..784c3f5c19 --- /dev/null +++ b/Themes/default/Graphics/ScreenTitleMenu NumSongs.lua @@ -0,0 +1,2 @@ +return LoadFont("Common Normal") .. { +}; \ No newline at end of file diff --git a/Themes/default/Graphics/ScreenTitleMenu TimingDifficulty.lua b/Themes/default/Graphics/ScreenTitleMenu TimingDifficulty.lua index 0437d83b4d..1be2c9961f 100644 --- a/Themes/default/Graphics/ScreenTitleMenu TimingDifficulty.lua +++ b/Themes/default/Graphics/ScreenTitleMenu TimingDifficulty.lua @@ -2,7 +2,7 @@ return Def.ActorFrame { --[[ LoadActor(THEME:GetPathG("ScreenTitleMenu","PreferenceFrame")) .. { OnCommand=function(self) if GetTimingDifficulty() == 7 then - (cmd(glowshift;diffuse,Color("Yellow");diffuserightedge,Color("Red");effectcolor1,Colors.Alpha( Color("Red"), 0.5 );effectcolor2,Color("Invisible");effectperiod,1.25/2))(self); + (cmd(glowshift;diffuse,Color("Yellow");diffuserightedge,Color("Red");effectcolor1,Color.Alpha( Color("Red"), 0.5 );effectcolor2,Color("Invisible");effectperiod,1.25/2))(self); elseif GetTimingDifficulty() < 4 then (cmd(diffuseshift;effectcolor1,Color("Blue");effectcolor2,ColorDarkTone(Color("Blue"));effectperiod,1.25))(self); elseif GetTimingDifficulty() > 4 and GetTimingDifficulty < 6 then diff --git a/Themes/default/Graphics/ScreenTitleMenu VersionInfo.lua b/Themes/default/Graphics/ScreenTitleMenu VersionInfo.lua index aa46df3859..34c95f08ec 100644 --- a/Themes/default/Graphics/ScreenTitleMenu VersionInfo.lua +++ b/Themes/default/Graphics/ScreenTitleMenu VersionInfo.lua @@ -3,8 +3,8 @@ return Def.ActorFrame { OnCommand=cmd(diffuse,color("#f7941d");diffusetopedge,color("#fff200");diffusealpha,0.25); }; LoadFont("Common Normal") .. { - Text=ProductID(); - AltText=""; + Text="StepMania"; + AltText="StepMania"; InitCommand=cmd(y,-5;zoom,0.6); OnCommand=cmd(shadowlength,1); }; diff --git a/Themes/default/Graphics/ScreenWithMenuElements StageDisplay.lua b/Themes/default/Graphics/ScreenWithMenuElements StageDisplay.lua index abc1409fa6..9853636553 100644 --- a/Themes/default/Graphics/ScreenWithMenuElements StageDisplay.lua +++ b/Themes/default/Graphics/ScreenWithMenuElements StageDisplay.lua @@ -69,7 +69,7 @@ else self:settextf( "Stage %03i", RealStage); self:diffuse( StageToColor('Stage_1st') ); self:diffusebottomedge( ColorMidTone(StageToColor('Stage_1st')) ); - self:strokecolor( Colors.Alpha( ColorDarkTone(StageToColor('Stage_1st')), 0.75) ); + self:strokecolor( Color.Alpha( ColorDarkTone(StageToColor('Stage_1st')), 0.75) ); end; end; } diff --git a/Themes/default/Graphics/_SelectIcon Routine.png b/Themes/default/Graphics/_SelectIcon Routine.png new file mode 100644 index 0000000000..2732321931 Binary files /dev/null and b/Themes/default/Graphics/_SelectIcon Routine.png differ diff --git a/Themes/default/Scripts/03 ThemePrefs.lua b/Themes/default/Scripts/03 ThemePrefs.lua index d7c1555728..221ced5288 100644 --- a/Themes/default/Scripts/03 ThemePrefs.lua +++ b/Themes/default/Scripts/03 ThemePrefs.lua @@ -231,9 +231,9 @@ function UserPrefShowLotsaOptions() end function GetDefaultOptionLines() - local LineSets = { - "1,8,14,2,3,4,5,6,R,7,9,10,11,12,13,16,17,18", -- All - "1,8,14,2,7,13,16,17,18", -- DDR Essentials ( no turns, fx ) + local LineSets = { -- none of these include characters yet. + "1,8,14,2,3,4,5,6,R,7,9,10,11,12,13,16,17", -- All + "1,8,14,2,7,13,16,17", -- DDR Essentials ( no turns, fx ) }; local function IsExtra() if GAMESTATE:IsExtraStage() or GAMESTATE:IsExtraStage2() then @@ -242,15 +242,22 @@ function GetDefaultOptionLines() return false end end - if not IsExtra() then - if GetUserPrefB("UserPrefShowLotsaOptions") then - return GetUserPrefB("UserPrefShowLotsaOptions") and LineSets[1] or LineSets[2]; - else - return LineSets[2]; -- Just make sure! + + local function CheckCharacters(mods) + if CHARMAN:GetCharacterCount() > 0 then + return mods .. ",18"; --TODO: Better line name. end - else - return "1,8,14,2,7,13,16,17,18" -- "failsafe" list + return mods; end + + modLines = LineSets[2]; + + if not IsExtra() then + modLines = GetUserPrefB("UserPrefShowLotsaOptions") + and LineSets[1] or LineSets[2]; + end + + return CheckCharacters(modLines); end; function UserPrefAutoSetStyle() diff --git a/Themes/default/Sounds/ScreenCredits music.redir b/Themes/default/Sounds/ScreenCredits music.redir new file mode 100644 index 0000000000..cd560a087c --- /dev/null +++ b/Themes/default/Sounds/ScreenCredits music.redir @@ -0,0 +1 @@ +_Music credits (loop) \ No newline at end of file diff --git a/Themes/default/Sounds/_Music credits (loop).ogg b/Themes/default/Sounds/_Music credits (loop).ogg new file mode 100644 index 0000000000..2d5db646dd Binary files /dev/null and b/Themes/default/Sounds/_Music credits (loop).ogg differ diff --git a/Themes/default/metrics.ini b/Themes/default/metrics.ini index 65558ea9ca..11e368b4e4 100644 --- a/Themes/default/metrics.ini +++ b/Themes/default/metrics.ini @@ -70,8 +70,6 @@ NumberOnCommand=y,240-216-1.5;shadowlength,1;horizalign,right;vertalign,bottom;s LabelOnCommand=x,6;y,22.5;shadowlength,1;zoom,0.75;diffusebottomedge,color("0.75,0.75,0.75,1");horizalign,left;vertalign,bottom [HoldJudgment] -HoldJudgmentLetGoCommand=finishtweening;shadowlength,0;diffusealpha,1;zoom,1;y,-10;linear,0.8;y,10;sleep,0.5;linear,0.1;zoomy,0.5;zoomx,2;diffusealpha,0 -HoldJudgmentHeldCommand=finishtweening;shadowlength,0;diffusealpha,1;zoom,1.25;linear,0.3;zoomx,1;zoomy,1;sleep,0.5;linear,0.1;zoomy,0.5;zoomx,2;diffusealpha,0 [HelpDisplay] TipShowTime=7 @@ -112,7 +110,7 @@ ItemsSpacingY=24 NumShownItems=8 [FadingBanner] -BannerFadeFromCachedCommand=diffusealpha,1;stoptweening;accelerate,0.05;glow,Colors.Alpha( Color("White"), 0.45 );decelerate,0.175;diffusealpha,0;glow,Color("Invisible"); +BannerFadeFromCachedCommand=diffusealpha,1;stoptweening;accelerate,0.05;glow,Color.Alpha( Color("White"), 0.45 );decelerate,0.175;diffusealpha,0;glow,Color("Invisible"); [Gameplay] @@ -424,7 +422,7 @@ end; ShowAutogen=true AutogenX=0 AutogenY=0 -#AutogenOnCommand=diffuseshift;effectcolor1,Colors.Alpha( Color("Green") , 0.5 );effectcolor2,ColorLightTone( Color("Green") ); +#AutogenOnCommand=diffuseshift;effectcolor1,Color.Alpha( Color("Green") , 0.5 );effectcolor2,ColorLightTone( Color("Green") ); AutogenOnCommand=blend,Blend.Add;diffuseshift;effectcolor1,color("#FFCC00FF");effectcolor2,color("#FFCC0088"); # ShowStepsType=GetUserPrefB("UserPrefAutoSetStyle") @@ -481,6 +479,7 @@ Fallback="StepsDisplay" # end; PillTransformFunction=function(self,offsetFromCenter,itemIndex,numItems) \ local fItemWidth = ( 256 / numItems ) \ + self:x( ((itemIndex-(numItems/2))*fItemWidth) + ( numItems / 2 ) ); \ self:zoomtowidth(fItemWidth); \ end; # PillTransformFunction=function(self,offsetFromCenter,itemIndex,numItems) \ @@ -491,8 +490,8 @@ end; # self:effecttiming(1,0.01875*itemIndex,1,1-(0.01875*itemIndex)); \ # self:effectclock('beatnooffset'); \ # end; -TextureCoordScaleX=1 -NumPills=1 +TextureCoordScaleX=256/16 +NumPills=16 [TextBanner] TitleOnCommand=horizalign,left;shadowlength,1; @@ -507,6 +506,7 @@ ArtistPrependString="" [ScreenDebugOverlay] [ScreenSystemLayer] +ShowClock=true CreditsP1OnCommand=horizalign,left;vertalign,bottom;zoom,0.675;shadowlength,1;diffusebottomedge,PlayerColor(PLAYER_1); # CreditsP2OnCommand=horizalign,right;vertalign,bottom;zoom,0.675;shadowlength,1;diffusebottomedge,PlayerColor(PLAYER_2); @@ -612,6 +612,13 @@ CurrentGametypeY=SCREEN_HEIGHT*0.1575 CurrentGametypeOnCommand=vertalign,bottom; CurrentGametypeOffCommand=linear,0.5;cropleft,1 # +ShowNumSongs=true +NumSongsX=SCREEN_WIDTH*0.99 +NumSongsY=SCREEN_HEIGHT*0.1575+5 +NumSongsOnCommand=vertalign,bottom;horizalign,right;zoom,0.5;playcommand,"Set" +NumSongsOffCommand= +# +# ShowTimingDifficulty=true TimingDifficultyX=SCREEN_LEFT+84 TimingDifficultyY=SCREEN_TOP+22 @@ -705,7 +712,7 @@ IconChoiceDoubleX=SCREEN_CENTER_X-160 IconChoiceDoubleY=SCREEN_CENTER_Y IconChoiceDoubleOnCommand=zoom,0;bounceend,0.35;zoom,1 IconChoiceDoubleOffCommand=linear,0.1175;zoomx,0 -# +#### IconChoiceSoloX=SCREEN_CENTER_X-160 IconChoiceSoloY=SCREEN_CENTER_Y+96 IconChoiceSoloOnCommand=zoom,0;bounceend,0.35;zoom,1 @@ -715,17 +722,22 @@ IconChoiceHalfDoubleX=SCREEN_CENTER_X-160 IconChoiceHalfDoubleY=SCREEN_CENTER_Y+96 IconChoiceHalfDoubleOnCommand=zoom,0;bounceend,0.35;zoom,1 IconChoiceHalfDoubleOffCommand=linear,0.1175;zoomx,0 -# +#### IconChoiceVersusX=SCREEN_CENTER_X+160 -IconChoiceVersusY=SCREEN_CENTER_Y-48 +IconChoiceVersusY=string.find(THEME:GetMetric("ScreenSelectStyle","ChoiceNames"),"Routine") and SCREEN_CENTER_Y-96 or SCREEN_CENTER_Y-48 IconChoiceVersusOnCommand=zoom,0;bounceend,0.35;zoom,1 IconChoiceVersusOffCommand=linear,0.1175;zoomx,0 # IconChoiceCoupleX=SCREEN_CENTER_X+160 -IconChoiceCoupleY=SCREEN_CENTER_Y+48 +IconChoiceCoupleY=string.find(THEME:GetMetric("ScreenSelectStyle","ChoiceNames"),"Routine") and SCREEN_CENTER_Y or SCREEN_CENTER_Y+48 IconChoiceCoupleOnCommand=zoom,0;bounceend,0.35;zoom,1 IconChoiceCoupleOffCommand=linear,0.1175;zoomx,0 # +IconChoiceRoutineX=SCREEN_CENTER_X+160 +IconChoiceRoutineY=SCREEN_CENTER_Y+96 +IconChoiceRoutineOnCommand=zoom,0;bounceend,0.35;zoom,1 +IconChoiceRoutineOffCommand=linear,0.1175;zoomx,0 +# IconChoicekb7X=SCREEN_CENTER_X IconChoicekb7Y=SCREEN_CENTER_Y IconChoicekb7OnCommand=zoom,0;bounceend,0.35;zoom,1 @@ -1216,7 +1228,7 @@ ItemsLongRowSharedX=SCREEN_CENTER_X [ScreenTestInput] [ScreenOptionsSystemDirection] -LineNames="1,2,3,4,5,6,7,8,9,FlashyCombo,RollCombo,10,11,12,13,14,15,16,LF,17,18,19,20,21,22" +LineNames="1,2,3,4,5,6,7,8,9,FlashyCombo,RollCombo,10,11,12,13,14,16,LF,17,18,19,20,21,22" LineLF="lua,UserPrefLongFail()" LineRollCombo="lua,UserPrefComboOnRolls()" LineFlashyCombo="lua,UserPrefFlashyCombo()" @@ -1224,7 +1236,7 @@ LineFlashyCombo="lua,UserPrefFlashyCombo()" [ScreenOptionsGraphicsSound] [ScreenOptionsAdvanced] -LineNames="Score,3,4,8,11,13,14,15,16,28,29,30,RollCombo" +LineNames="Score,3,4,8,11,13,14,16,28,29,30,RollCombo" LineRollCombo="lua,UserPrefComboOnRolls()" [ScreenAppearanceOptions] @@ -1301,18 +1313,18 @@ SongMeterDisplayOffCommand= # ShowSongTitle=true SongTitleX=SCREEN_CENTER_X -SongTitleY=SCREEN_TOP+50+12 -SongTitleOnCommand=draworder,55;shadowlength,1;basezoom,0.5;zoomy,0;sleep,1.5+0.5;smooth,0.5;zoom,1;y,SCREEN_TOP+50+12 +SongTitleY=SCREEN_TOP+50 +SongTitleOnCommand=draworder,55;shadowlength,1;basezoom,0.5;zoomy,0;sleep,1.5+0.5;smooth,0.5;zoom,1;y,SCREEN_TOP+50 SongTitleOffCommand= # SongMeterDisplayP1X=SCREEN_LEFT+16 SongMeterDisplayP1Y=SCREEN_CENTER_Y -SongMeterDisplayP1OnCommand=rotationz,-90;zoom,0;addx,-24;sleep,1.5;decelerate,0.5;zoom,1;addx,24 +SongMeterDisplayP1OnCommand=draworder,5;rotationz,-90;zoom,0;addx,-24;sleep,1.5;decelerate,0.5;zoom,1;addx,24 SongMeterDisplayP1OffCommand= # SongMeterDisplayP2X=SCREEN_RIGHT-16 SongMeterDisplayP2Y=SCREEN_CENTER_Y -SongMeterDisplayP2OnCommand=rotationz,-90;zoom,0;addx,24;sleep,1.5;decelerate,0.5;zoom,1;addx,-24 +SongMeterDisplayP2OnCommand=draworder,5;rotationz,-90;zoom,0;addx,24;sleep,1.5;decelerate,0.5;zoom,1;addx,-24 SongMeterDisplayP2OffCommand= # ShowBPMDisplay=true @@ -1322,16 +1334,16 @@ BPMDisplayY=SCREEN_BOTTOM-16 BPMDisplayOnCommand=draworder,101 BPMDisplayOffCommand=bounceend,0.25;zoom,0 # -ShowStageDisplay=false +ShowStageDisplay=true StageDisplayX=SCREEN_CENTER_X StageDisplayY=SCREEN_TOP+24 -StageDisplayOnCommand=zoom,0.5; +StageDisplayOnCommand=zoom,0.675; StageDisplayOffCommand=bounceend,0.25;zoom,0 # ShowScoreFrame=GetUserPrefB("GameplayFooter"); ScoreFrameX=SCREEN_CENTER_X ScoreFrameY=SCREEN_BOTTOM+4 -ScoreFrameOnCommand=draworder,100;vertalign,bottom;zoomtowidth,SCREEN_WIDTH+4;diffuse,color("#ffd400");addy,80;sleep,2;decelerate,0.5;addy,-80; +ScoreFrameOnCommand=draworder,4;vertalign,bottom;zoomtowidth,SCREEN_WIDTH+4;diffuse,color("#ffd400");addy,80;sleep,2;decelerate,0.5;addy,-80; ScoreFrameOffCommand= # LifeP1X=Center1Player() and SCREEN_CENTER_X or THEME:GetMetric(Var "LoadingScreen","PlayerP1OnePlayerOneSideX") @@ -1499,7 +1511,7 @@ ShowJudgmentLineW2=true ShowJudgmentLineW3=true ShowJudgmentLineW4=true ShowJudgmentLineW5=true -ShowJudgmentLineHeld=true +ShowJudgmentLineHeld=(GAMESTATE:GetCurrentGame():GetName() ~= "pump") ShowJudgmentLineMiss=true ShowJudgmentLineMaxCombo=true ShowGradeArea=true diff --git a/Utils/CreatePackage.pl b/Utils/CreatePackage.pl index 81457e0f87..37881fd1e7 100755 --- a/Utils/CreatePackage.pl +++ b/Utils/CreatePackage.pl @@ -173,6 +173,7 @@ my @files = ( "NoteSkins/pump/default", "NoteSkins/pump/frame5p", "NoteSkins/pump/newextra", + "NoteSkins/pump/pad", "NoteSkins/pump/rhythm", "NoteSkins/pump/simple", # kb7 noteskins diff --git a/Xcode/Libraries/README b/Xcode/Libraries/README index c8dcc17f8a..176dad4352 100644 --- a/Xcode/Libraries/README +++ b/Xcode/Libraries/README @@ -1,7 +1,7 @@ Static Libraries: jpeg-6b libogg-1.1.2 -libpng-1.2.8 +libpng-1.5.1 libvorbis-1.1.1 libtheora-1.0alpha5 zlib-1.2.3 diff --git a/Xcode/scripts/mkrelease.pl b/Xcode/scripts/mkrelease.pl index c3580425e9..4f514e785e 100644 --- a/Xcode/scripts/mkrelease.pl +++ b/Xcode/scripts/mkrelease.pl @@ -9,7 +9,9 @@ use Cwd; my @docs = ( "Licenses.txt", + "Changelog_sm5.txt", "Changelog_sm-ssc.txt", + "Changelog_SSCformat.txt", "CommandLineArgs.txt", "credits.txt", "Themerdocs/" @@ -46,8 +48,8 @@ $destname =~ s/\s+/-/g; my $tmp = tempdir; # Copy StepMania and make smzip -system 'cp', '-r', "$srcdir/sm-ssc.app", $tmp and die "cp -r failed: $!\n"; -system 'strip', '-x', "$tmp/sm-ssc.app/Contents/MacOS/sm-ssc"; +system 'cp', '-r', "$srcdir/StepMania.app", $tmp and die "cp -r failed: $!\n"; +system 'strip', '-x', "$tmp/StepMania.app/Contents/MacOS/StepMania"; mkdir "$tmp/Packages"; system "$srcdir/Utils/CreatePackage.pl", $srcdir, "$tmp/Packages" and die "mksmdata.pl failed: $!\n"; diff --git a/Xcode/stepmania.xcodeproj/project.pbxproj b/Xcode/stepmania.xcodeproj/project.pbxproj index fbe2913e32..36f73f5a4b 100644 --- a/Xcode/stepmania.xcodeproj/project.pbxproj +++ b/Xcode/stepmania.xcodeproj/project.pbxproj @@ -45,9 +45,9 @@ 2B17AB8A13980FF6001AE57D /* pngwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BC6132113773C8E00CC8BBD /* pngwrite.c */; }; 2B17AB8B13980FF6001AE57D /* pngwtran.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BC6132213773C8E00CC8BBD /* pngwtran.c */; }; 2B17AB8C13980FF6001AE57D /* pngwutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 2BC6132313773C8E00CC8BBD /* pngwutil.c */; }; - 2B17AB9F13981271001AE57D /* libpng-1.5.1sm0.1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B17AB7213980FDF001AE57D /* libpng-1.5.1sm0.1.a */; }; + 2B17AB9F13981271001AE57D /* libpng-1.5.1-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B17AB7213980FDF001AE57D /* libpng-1.5.1-sm5.a */; }; 2B17ABC51398153F001AE57D /* glew.c in Sources */ = {isa = PBXBuildFile; fileRef = EE879BAA132E06C50078FDDC /* glew.c */; }; - 2B17ABCF139815E0001AE57D /* libglew.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B17ABC013981521001AE57D /* libglew.a */; }; + 2B17ABCF139815E0001AE57D /* libglew-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B17ABC013981521001AE57D /* libglew-sm5.a */; }; 2B17ABE51398179E001AE57D /* chartables.c in Sources */ = {isa = PBXBuildFile; fileRef = AA8B6C7904AFD87300D02EE9 /* chartables.c */; }; 2B17ABE61398179E001AE57D /* get.c in Sources */ = {isa = PBXBuildFile; fileRef = AA8B6C7A04AFD87300D02EE9 /* get.c */; }; 2B17ABE71398179E001AE57D /* internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AA8B6C7B04AFD87300D02EE9 /* internal.h */; }; @@ -55,8 +55,8 @@ 2B17ABE91398179E001AE57D /* pcre.c in Sources */ = {isa = PBXBuildFile; fileRef = AA8B6C7D04AFD87300D02EE9 /* pcre.c */; }; 2B17ABEA1398179E001AE57D /* pcre.h in Headers */ = {isa = PBXBuildFile; fileRef = AA8B6C7E04AFD87300D02EE9 /* pcre.h */; }; 2B17ABEB1398179E001AE57D /* study.c in Sources */ = {isa = PBXBuildFile; fileRef = AA8B6C7F04AFD87300D02EE9 /* study.c */; }; - 2B17ABFC139817D5001AE57D /* libpcre.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B17ABE013981756001AE57D /* libpcre.a */; }; - 2B17ABFD139817D6001AE57D /* libpcre.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B17ABE013981756001AE57D /* libpcre.a */; }; + 2B17ABFC139817D5001AE57D /* libpcre-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B17ABE013981756001AE57D /* libpcre-sm5.a */; }; + 2B17ABFD139817D6001AE57D /* libpcre-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B17ABE013981756001AE57D /* libpcre-sm5.a */; }; 2B30D6821315EA7E00044B68 /* MouseDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2B30D6801315EA7E00044B68 /* MouseDevice.cpp */; }; 2B30D6831315EA7E00044B68 /* MouseDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B30D6811315EA7E00044B68 /* MouseDevice.h */; }; 2B43509513949F37006FA051 /* TimingSegments.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B43509313949F37006FA051 /* TimingSegments.h */; }; @@ -321,7 +321,6 @@ AA29CDD50558741A00961A51 /* ScreenSelectCharacter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E005B047711F3005F316C /* ScreenSelectCharacter.cpp */; }; AA29CDDB0558741A00961A51 /* ScreenSelectMusic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E0069047711F3005F316C /* ScreenSelectMusic.cpp */; }; AA29CDDD0558741A00961A51 /* ScreenSongOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E006F047711F3005F316C /* ScreenSongOptions.cpp */; }; - AA29CDE10558741A00961A51 /* ScreenTestFonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E0079047711F3005F316C /* ScreenTestFonts.cpp */; }; AA29CDE20558741A00961A51 /* ScreenTestSound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E007B047711F3005F316C /* ScreenTestSound.cpp */; }; AA29CDE30558741A00961A51 /* ScreenTextEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E007D047711F3005F316C /* ScreenTextEntry.cpp */; }; AA29CDE40558741A00961A51 /* ScreenTitleMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E007F047711F3005F316C /* ScreenTitleMenu.cpp */; }; @@ -535,7 +534,6 @@ AA40D24209A08D650068C0D5 /* ScreenSelectCharacter.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6E005C047711F3005F316C /* ScreenSelectCharacter.h */; }; AA40D24609A08D650068C0D5 /* ScreenSelectMusic.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6E006A047711F3005F316C /* ScreenSelectMusic.h */; }; AA40D24809A08D650068C0D5 /* ScreenSongOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6E0070047711F3005F316C /* ScreenSongOptions.h */; }; - AA40D24A09A08D650068C0D5 /* ScreenTestFonts.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6E007A047711F3005F316C /* ScreenTestFonts.h */; }; AA40D24B09A08D650068C0D5 /* ScreenTestSound.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6E007C047711F3005F316C /* ScreenTestSound.h */; }; AA40D24C09A08D650068C0D5 /* ScreenTextEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6E007E047711F3005F316C /* ScreenTextEntry.h */; }; AA40D24D09A08D650068C0D5 /* ScreenTitleMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6E0080047711F3005F316C /* ScreenTitleMenu.h */; }; @@ -862,7 +860,6 @@ AA40D3FF09A08D650068C0D5 /* ScreenSelectCharacter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E005B047711F3005F316C /* ScreenSelectCharacter.cpp */; }; AA40D40309A08D650068C0D5 /* ScreenSelectMusic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E0069047711F3005F316C /* ScreenSelectMusic.cpp */; }; AA40D40509A08D650068C0D5 /* ScreenSongOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E006F047711F3005F316C /* ScreenSongOptions.cpp */; }; - AA40D40709A08D650068C0D5 /* ScreenTestFonts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E0079047711F3005F316C /* ScreenTestFonts.cpp */; }; AA40D40809A08D650068C0D5 /* ScreenTestSound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E007B047711F3005F316C /* ScreenTestSound.cpp */; }; AA40D40909A08D650068C0D5 /* ScreenTextEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E007D047711F3005F316C /* ScreenTextEntry.cpp */; }; AA40D40A09A08D650068C0D5 /* ScreenTitleMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6E007F047711F3005F316C /* ScreenTitleMenu.cpp */; }; @@ -1142,8 +1139,8 @@ AA77E76508B64B9A00FA24CA /* ScreenOptionsManageCourses.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA77E75B08B64B9A00FA24CA /* ScreenOptionsManageCourses.cpp */; }; AA77E76708B64B9A00FA24CA /* ScreenOptionsManageProfiles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA77E75D08B64B9A00FA24CA /* ScreenOptionsManageProfiles.cpp */; }; AA77E8B108B6ABD500FA24CA /* vecLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA77E8A108B6ABD500FA24CA /* vecLib.framework */; }; - AA7A2BAF0AE09CEC0054C5BA /* liblua-5.1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1.a */; }; - AA7A2BB00AE09CF10054C5BA /* liblua-5.1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1.a */; }; + AA7A2BAF0AE09CEC0054C5BA /* liblua-5.1-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1-sm5.a */; }; + AA7A2BB00AE09CF10054C5BA /* liblua-5.1-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1-sm5.a */; }; AA7ADC27072CAB7F00C50A7F /* RageSoundReader_Chain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA7ADC23072CAB7F00C50A7F /* RageSoundReader_Chain.cpp */; }; AA7ADC29072CAB7F00C50A7F /* RageSoundUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA7ADC25072CAB7F00C50A7F /* RageSoundUtil.cpp */; }; AA7C8AFC0B6744F700FD9940 /* bn_error.c in Sources */ = {isa = PBXBuildFile; fileRef = AA7C8A800B6744F600FD9940 /* bn_error.c */; }; @@ -1424,10 +1421,10 @@ AA7C8CF00B67467D00FD9940 /* sober128.c in Sources */ = {isa = PBXBuildFile; fileRef = AA7C8C520B67467D00FD9940 /* sober128.c */; }; AA7C8CF20B67467D00FD9940 /* sprng.c in Sources */ = {isa = PBXBuildFile; fileRef = AA7C8C540B67467D00FD9940 /* sprng.c */; }; AA7C8CF30B67467D00FD9940 /* yarrow.c in Sources */ = {isa = PBXBuildFile; fileRef = AA7C8C550B67467D00FD9940 /* yarrow.c */; }; - AA7C8D1F0B6748E300FD9940 /* libtommath.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA7C895F0B67444700FD9940 /* libtommath.a */; }; - AA7C8D200B6748E400FD9940 /* libtomcrypt.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA7C8B8B0B67460600FD9940 /* libtomcrypt.a */; }; - AA7C8D430B674F4E00FD9940 /* libtommath.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA7C895F0B67444700FD9940 /* libtommath.a */; }; - AA7C8D440B674F4F00FD9940 /* libtomcrypt.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA7C8B8B0B67460600FD9940 /* libtomcrypt.a */; }; + AA7C8D1F0B6748E300FD9940 /* libtommath-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA7C895F0B67444700FD9940 /* libtommath-sm5.a */; }; + AA7C8D200B6748E400FD9940 /* libtomcrypt-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA7C8B8B0B67460600FD9940 /* libtomcrypt-sm5.a */; }; + AA7C8D430B674F4E00FD9940 /* libtommath-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA7C895F0B67444700FD9940 /* libtommath-sm5.a */; }; + AA7C8D440B674F4F00FD9940 /* libtomcrypt-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA7C8B8B0B67460600FD9940 /* libtomcrypt-sm5.a */; }; AA7C8DAE0B68CB2200FD9940 /* GameplayAssist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA7C8DAC0B68CB2200FD9940 /* GameplayAssist.cpp */; }; AA7C8DAF0B68CB2200FD9940 /* GameplayAssist.h in Headers */ = {isa = PBXBuildFile; fileRef = AA7C8DAD0B68CB2200FD9940 /* GameplayAssist.h */; }; AA7C8DB00B68CB2200FD9940 /* GameplayAssist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA7C8DAC0B68CB2200FD9940 /* GameplayAssist.cpp */; }; @@ -1612,8 +1609,8 @@ AAE7804B060814AC0034E65F /* NetworkSyncManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAE78049060814AC0034E65F /* NetworkSyncManager.cpp */; }; AAE7808706081A000034E65F /* ezsockets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAE7808506081A000034E65F /* ezsockets.cpp */; }; AAE7812D0608249E0034E65F /* ActiveAttackList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAE7812B0608249E0034E65F /* ActiveAttackList.cpp */; }; - AAE782030AC7E64D00AEFC64 /* liblua-5.1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1.a */; }; - AAE782040AC7E65200AEFC64 /* liblua-5.1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1.a */; }; + AAE782030AC7E64D00AEFC64 /* liblua-5.1-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1-sm5.a */; }; + AAE782040AC7E65200AEFC64 /* liblua-5.1-sm5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1-sm5.a */; }; AAEBC6CC07A20AFE00793F0E /* RageSurface_Save_JPEG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAEBC6C607A20AFE00793F0E /* RageSurface_Save_JPEG.cpp */; }; AAEBC6CE07A20AFE00793F0E /* RageSurfaceUtils_Dither.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAEBC6C807A20AFE00793F0E /* RageSurfaceUtils_Dither.cpp */; }; AAEBC6D007A20AFE00793F0E /* RageSurfaceUtils_Zoom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAEBC6CA07A20AFE00793F0E /* RageSurfaceUtils_Zoom.cpp */; }; @@ -1661,6 +1658,8 @@ AAFF41A40F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF41A20F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h */; }; AAFF41A50F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAFF41A10F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.cpp */; }; AAFF41A60F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF41A20F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h */; }; + B71A60C0139B41DB00183A27 /* InGameLoadingWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B71A60BE139B41DB00183A27 /* InGameLoadingWindow.cpp */; }; + B71A60C1139B41DB00183A27 /* InGameLoadingWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = B71A60BF139B41DB00183A27 /* InGameLoadingWindow.h */; }; B75CE3B5137963350076A82D /* SongPosition.h in Headers */ = {isa = PBXBuildFile; fileRef = B75CE3B3137963350076A82D /* SongPosition.h */; }; B75CE3B6137963350076A82D /* SongPosition.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B75CE3B4137963350076A82D /* SongPosition.cpp */; }; EE2153A910A75BEE0074B01B /* NotesLoaderPMS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE2153A710A75BEE0074B01B /* NotesLoaderPMS.cpp */; }; @@ -1824,9 +1823,9 @@ 1215D7A108C6559A00B87D8B /* ScreenGameplayNormal.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScreenGameplayNormal.h; path = ../src/ScreenGameplayNormal.h; sourceTree = ""; }; 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; - 2B17AB7213980FDF001AE57D /* libpng-1.5.1sm0.1.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libpng-1.5.1sm0.1.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 2B17ABC013981521001AE57D /* libglew.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libglew.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 2B17ABE013981756001AE57D /* libpcre.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpcre.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 2B17AB7213980FDF001AE57D /* libpng-1.5.1-sm5.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libpng-1.5.1-sm5.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2B17ABC013981521001AE57D /* libglew-sm5.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libglew-sm5.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2B17ABE013981756001AE57D /* libpcre-sm5.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libpcre-sm5.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 2B30D6801315EA7E00044B68 /* MouseDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseDevice.cpp; sourceTree = ""; }; 2B30D6811315EA7E00044B68 /* MouseDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MouseDevice.h; sourceTree = ""; }; 2B43509313949F37006FA051 /* TimingSegments.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TimingSegments.h; path = ../src/TimingSegments.h; sourceTree = SOURCE_ROOT; }; @@ -2020,7 +2019,7 @@ AA28B47A058F2F5D0097C109 /* MemoryCardManager.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = MemoryCardManager.cpp; path = ../src/MemoryCardManager.cpp; sourceTree = ""; }; AA28B47B058F2F5D0097C109 /* MemoryCardManager.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = MemoryCardManager.h; path = ../src/MemoryCardManager.h; sourceTree = ""; }; AA29CE570558741A00961A51 /* Info-StepMania.plist */ = {isa = PBXFileReference; explicitFileType = text.plist; path = "Info-StepMania.plist"; sourceTree = SOURCE_ROOT; }; - AA29CE580558741A00961A51 /* sm-ssc.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "sm-ssc.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + AA29CE580558741A00961A51 /* StepMania.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StepMania.app; sourceTree = BUILT_PRODUCTS_DIR; }; AA2C9C9F0BAD6F54002441E9 /* CodeSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CodeSet.cpp; path = ../src/CodeSet.cpp; sourceTree = ""; }; AA2C9CA00BAD6F54002441E9 /* CodeSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CodeSet.h; path = ../src/CodeSet.h; sourceTree = ""; }; AA2CA89D0BB745BD002441E9 /* ScreenContinue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScreenContinue.cpp; path = ../src/ScreenContinue.cpp; sourceTree = ""; }; @@ -2161,8 +2160,6 @@ AA6E006A047711F3005F316C /* ScreenSelectMusic.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScreenSelectMusic.h; path = ../src/ScreenSelectMusic.h; sourceTree = ""; }; AA6E006F047711F3005F316C /* ScreenSongOptions.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ScreenSongOptions.cpp; path = ../src/ScreenSongOptions.cpp; sourceTree = ""; }; AA6E0070047711F3005F316C /* ScreenSongOptions.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScreenSongOptions.h; path = ../src/ScreenSongOptions.h; sourceTree = ""; }; - AA6E0079047711F3005F316C /* ScreenTestFonts.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ScreenTestFonts.cpp; path = ../src/ScreenTestFonts.cpp; sourceTree = ""; }; - AA6E007A047711F3005F316C /* ScreenTestFonts.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScreenTestFonts.h; path = ../src/ScreenTestFonts.h; sourceTree = ""; }; AA6E007B047711F3005F316C /* ScreenTestSound.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ScreenTestSound.cpp; path = ../src/ScreenTestSound.cpp; sourceTree = ""; }; AA6E007C047711F3005F316C /* ScreenTestSound.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ScreenTestSound.h; path = ../src/ScreenTestSound.h; sourceTree = ""; }; AA6E007D047711F3005F316C /* ScreenTextEntry.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ScreenTextEntry.cpp; path = ../src/ScreenTextEntry.cpp; sourceTree = ""; }; @@ -2421,7 +2418,7 @@ AA7ADC24072CAB7F00C50A7F /* RageSoundReader_Chain.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = RageSoundReader_Chain.h; path = ../src/RageSoundReader_Chain.h; sourceTree = ""; }; AA7ADC25072CAB7F00C50A7F /* RageSoundUtil.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = RageSoundUtil.cpp; path = ../src/RageSoundUtil.cpp; sourceTree = ""; }; AA7ADC26072CAB7F00C50A7F /* RageSoundUtil.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = RageSoundUtil.h; path = ../src/RageSoundUtil.h; sourceTree = ""; }; - AA7C895F0B67444700FD9940 /* libtommath.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtommath.a; sourceTree = BUILT_PRODUCTS_DIR; }; + AA7C895F0B67444700FD9940 /* libtommath-sm5.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libtommath-sm5.a"; sourceTree = BUILT_PRODUCTS_DIR; }; AA7C8A800B6744F600FD9940 /* bn_error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bn_error.c; sourceTree = ""; }; AA7C8A810B6744F600FD9940 /* bn_fast_mp_invmod.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bn_fast_mp_invmod.c; sourceTree = ""; }; AA7C8A820B6744F600FD9940 /* bn_fast_mp_montgomery_reduce.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bn_fast_mp_montgomery_reduce.c; sourceTree = ""; }; @@ -2544,7 +2541,7 @@ AA7C8AF90B6744F700FD9940 /* tommath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tommath.h; sourceTree = ""; }; AA7C8AFA0B6744F700FD9940 /* tommath_class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tommath_class.h; sourceTree = ""; }; AA7C8AFB0B6744F700FD9940 /* tommath_superclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tommath_superclass.h; sourceTree = ""; }; - AA7C8B8B0B67460600FD9940 /* libtomcrypt.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtomcrypt.a; sourceTree = BUILT_PRODUCTS_DIR; }; + AA7C8B8B0B67460600FD9940 /* libtomcrypt-sm5.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libtomcrypt-sm5.a"; sourceTree = BUILT_PRODUCTS_DIR; }; AA7C8B950B67467C00FD9940 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = ""; }; AA7C8B960B67467C00FD9940 /* aes_tab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes_tab.c; sourceTree = ""; }; AA7C8B990B67467C00FD9940 /* hash_memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hash_memory.c; sourceTree = ""; }; @@ -2971,7 +2968,7 @@ AAE7808606081A000034E65F /* ezsockets.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ezsockets.h; path = ../src/ezsockets.h; sourceTree = ""; }; AAE7812B0608249E0034E65F /* ActiveAttackList.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = ActiveAttackList.cpp; path = ../src/ActiveAttackList.cpp; sourceTree = ""; }; AAE7812C0608249E0034E65F /* ActiveAttackList.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ActiveAttackList.h; path = ../src/ActiveAttackList.h; sourceTree = ""; }; - AAE7817E0AC7E37B00AEFC64 /* liblua-5.1.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "liblua-5.1.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + AAE7817E0AC7E37B00AEFC64 /* liblua-5.1-sm5.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "liblua-5.1-sm5.a"; sourceTree = BUILT_PRODUCTS_DIR; }; AAEBC6C607A20AFE00793F0E /* RageSurface_Save_JPEG.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = RageSurface_Save_JPEG.cpp; path = ../src/RageSurface_Save_JPEG.cpp; sourceTree = ""; }; AAEBC6C707A20AFE00793F0E /* RageSurface_Save_JPEG.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = RageSurface_Save_JPEG.h; path = ../src/RageSurface_Save_JPEG.h; sourceTree = ""; }; AAEBC6C807A20AFE00793F0E /* RageSurfaceUtils_Dither.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = RageSurfaceUtils_Dither.cpp; path = ../src/RageSurfaceUtils_Dither.cpp; sourceTree = ""; }; @@ -3056,6 +3053,8 @@ AAFF55220549F43A00D02EE9 /* ComboGraph.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = ComboGraph.h; path = ../src/ComboGraph.h; sourceTree = ""; }; AAFF5541054E736D00D02EE9 /* Attack.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = Attack.cpp; path = ../src/Attack.cpp; sourceTree = ""; }; AAFF5542054E736D00D02EE9 /* Attack.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = Attack.h; path = ../src/Attack.h; sourceTree = ""; }; + B71A60BE139B41DB00183A27 /* InGameLoadingWindow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InGameLoadingWindow.cpp; path = ../src/InGameLoadingWindow.cpp; sourceTree = ""; }; + B71A60BF139B41DB00183A27 /* InGameLoadingWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InGameLoadingWindow.h; path = ../src/InGameLoadingWindow.h; sourceTree = ""; }; B75CE3B3137963350076A82D /* SongPosition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SongPosition.h; path = ../src/SongPosition.h; sourceTree = SOURCE_ROOT; }; B75CE3B4137963350076A82D /* SongPosition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SongPosition.cpp; path = ../src/SongPosition.cpp; sourceTree = SOURCE_ROOT; }; EE2153A710A75BEE0074B01B /* NotesLoaderPMS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NotesLoaderPMS.cpp; path = ../src/NotesLoaderPMS.cpp; sourceTree = SOURCE_ROOT; }; @@ -3117,15 +3116,15 @@ AA21E47B0A9826CD00684CEA /* libogg_link.a in Frameworks */, AA21E47D0A9826CD00684CEA /* libtheora_link.a in Frameworks */, AA21E47E0A9826CD00684CEA /* libvorbis_link.a in Frameworks */, - AAE782030AC7E64D00AEFC64 /* liblua-5.1.a in Frameworks */, - AA7C8D200B6748E400FD9940 /* libtomcrypt.a in Frameworks */, - AA7C8D1F0B6748E300FD9940 /* libtommath.a in Frameworks */, + AAE782030AC7E64D00AEFC64 /* liblua-5.1-sm5.a in Frameworks */, + AA7C8D200B6748E400FD9940 /* libtomcrypt-sm5.a in Frameworks */, + AA7C8D1F0B6748E300FD9940 /* libtommath-sm5.a in Frameworks */, AA059E2C0B8F0C67006F8139 /* libz_link.a in Frameworks */, AAA0704E0CE5082E005A3060 /* libffmpeg_link.a in Frameworks */, AAA071B40CE7C9C9005A3060 /* libmad-sm5.a in Frameworks */, - 2B17AB9F13981271001AE57D /* libpng-1.5.1sm0.1.a in Frameworks */, - 2B17ABCF139815E0001AE57D /* libglew.a in Frameworks */, - 2B17ABFC139817D5001AE57D /* libpcre.a in Frameworks */, + 2B17AB9F13981271001AE57D /* libpng-1.5.1-sm5.a in Frameworks */, + 2B17ABCF139815E0001AE57D /* libglew-sm5.a in Frameworks */, + 2B17ABFC139817D5001AE57D /* libpcre-sm5.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3147,12 +3146,12 @@ AA21E4810A9826CD00684CEA /* libogg_link.a in Frameworks */, AA21E4830A9826CD00684CEA /* libtheora_link.a in Frameworks */, AA21E4840A9826CD00684CEA /* libvorbis_link.a in Frameworks */, - AAE782040AC7E65200AEFC64 /* liblua-5.1.a in Frameworks */, - AA7C8D440B674F4F00FD9940 /* libtomcrypt.a in Frameworks */, - AA7C8D430B674F4E00FD9940 /* libtommath.a in Frameworks */, + AAE782040AC7E65200AEFC64 /* liblua-5.1-sm5.a in Frameworks */, + AA7C8D440B674F4F00FD9940 /* libtomcrypt-sm5.a in Frameworks */, + AA7C8D430B674F4E00FD9940 /* libtommath-sm5.a in Frameworks */, AA059E2B0B8F0C67006F8139 /* libz_link.a in Frameworks */, AAA0704F0CE5082E005A3060 /* libffmpeg_link.a in Frameworks */, - 2B17ABFD139817D6001AE57D /* libpcre.a in Frameworks */, + 2B17ABFD139817D6001AE57D /* libpcre-sm5.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3160,7 +3159,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AA7A2BAF0AE09CEC0054C5BA /* liblua-5.1.a in Frameworks */, + AA7A2BAF0AE09CEC0054C5BA /* liblua-5.1-sm5.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3168,7 +3167,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AA7A2BB00AE09CF10054C5BA /* liblua-5.1.a in Frameworks */, + AA7A2BB00AE09CF10054C5BA /* liblua-5.1-sm5.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3233,17 +3232,17 @@ 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( - AA29CE580558741A00961A51 /* sm-ssc.app */, + AA29CE580558741A00961A51 /* StepMania.app */, AA40D52B09A08D660068C0D5 /* sm-ssc.app */, - AAE7817E0AC7E37B00AEFC64 /* liblua-5.1.a */, + AAE7817E0AC7E37B00AEFC64 /* liblua-5.1-sm5.a */, AA7A2B940AE09B520054C5BA /* lua */, AA7A2BAB0AE09CD50054C5BA /* luac */, - AA7C895F0B67444700FD9940 /* libtommath.a */, - AA7C8B8B0B67460600FD9940 /* libtomcrypt.a */, + AA7C895F0B67444700FD9940 /* libtommath-sm5.a */, + AA7C8B8B0B67460600FD9940 /* libtomcrypt-sm5.a */, AAA070A90CE7B0DF005A3060 /* libmad-sm5.a */, - 2B17AB7213980FDF001AE57D /* libpng-1.5.1sm0.1.a */, - 2B17ABC013981521001AE57D /* libglew.a */, - 2B17ABE013981756001AE57D /* libpcre.a */, + 2B17AB7213980FDF001AE57D /* libpng-1.5.1-sm5.a */, + 2B17ABC013981521001AE57D /* libglew-sm5.a */, + 2B17ABE013981756001AE57D /* libpcre-sm5.a */, ); name = Products; sourceTree = ""; @@ -3536,8 +3535,6 @@ AA07A55E0843E72B00E33D21 /* ScreenSyncOverlay.h */, AA1145DB075DFADF0050A3D1 /* ScreenSystemLayer.cpp */, AA1145DC075DFADF0050A3D1 /* ScreenSystemLayer.h */, - AA6E0079047711F3005F316C /* ScreenTestFonts.cpp */, - AA6E007A047711F3005F316C /* ScreenTestFonts.h */, AAC622FA05389A0500D02EE9 /* ScreenTestInput.cpp */, AAC622FB05389A0500D02EE9 /* ScreenTestInput.h */, AAF7435906110E8D00B19AD1 /* ScreenTestLights.cpp */, @@ -4094,6 +4091,8 @@ AA6EFE9104770E7C005F316C /* GrooveRadar.h */, AA6EFE9404770E7C005F316C /* HelpDisplay.cpp */, AA6EFE9504770E7C005F316C /* HelpDisplay.h */, + B71A60BE139B41DB00183A27 /* InGameLoadingWindow.cpp */, + B71A60BF139B41DB00183A27 /* InGameLoadingWindow.h */, AA729C460599B54D00779F33 /* MemoryCardDisplay.cpp */, AA729C470599B54D00779F33 /* MemoryCardDisplay.h */, AA6EFE9A04770E7C005F316C /* MenuTimer.cpp */, @@ -5148,6 +5147,7 @@ 2B9C2E8E137A138B004C92F3 /* NotesLoaderJson.h in Headers */, 2B9C2E90137A138B004C92F3 /* NotesWriterJson.h in Headers */, 2B43509513949F37006FA051 /* TimingSegments.h in Headers */, + B71A60C1139B41DB00183A27 /* InGameLoadingWindow.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5276,7 +5276,6 @@ AA40D24209A08D650068C0D5 /* ScreenSelectCharacter.h in Headers */, AA40D24609A08D650068C0D5 /* ScreenSelectMusic.h in Headers */, AA40D24809A08D650068C0D5 /* ScreenSongOptions.h in Headers */, - AA40D24A09A08D650068C0D5 /* ScreenTestFonts.h in Headers */, AA40D24B09A08D650068C0D5 /* ScreenTestSound.h in Headers */, AA40D24C09A08D650068C0D5 /* ScreenTextEntry.h in Headers */, AA40D24D09A08D650068C0D5 /* ScreenTitleMenu.h in Headers */, @@ -5673,7 +5672,7 @@ ); name = png; productName = png; - productReference = 2B17AB7213980FDF001AE57D /* libpng-1.5.1sm0.1.a */; + productReference = 2B17AB7213980FDF001AE57D /* libpng-1.5.1-sm5.a */; productType = "com.apple.product-type.library.static"; }; 2B17ABBF13981521001AE57D /* glew */ = { @@ -5690,7 +5689,7 @@ ); name = glew; productName = glew; - productReference = 2B17ABC013981521001AE57D /* libglew.a */; + productReference = 2B17ABC013981521001AE57D /* libglew-sm5.a */; productType = "com.apple.product-type.library.static"; }; 2B17ABDF13981756001AE57D /* pcre */ = { @@ -5707,7 +5706,7 @@ ); name = pcre; productName = pcre; - productReference = 2B17ABE013981756001AE57D /* libpcre.a */; + productReference = 2B17ABE013981756001AE57D /* libpcre-sm5.a */; productType = "com.apple.product-type.library.static"; }; AA29CC240558741A00961A51 /* stepmania */ = { @@ -5737,7 +5736,7 @@ name = stepmania; productInstallPath = "$(HOME)/Applications"; productName = "SDL App"; - productReference = AA29CE580558741A00961A51 /* sm-ssc.app */; + productReference = AA29CE580558741A00961A51 /* StepMania.app */; productType = "com.apple.product-type.application"; }; AA40D1B409A08D650068C0D5 /* stepmania-bare */ = { @@ -5815,7 +5814,7 @@ ); name = tommath; productName = tommath; - productReference = AA7C895F0B67444700FD9940 /* libtommath.a */; + productReference = AA7C895F0B67444700FD9940 /* libtommath-sm5.a */; productType = "com.apple.product-type.library.static"; }; AA7C8B8A0B67460600FD9940 /* tomcrypt */ = { @@ -5832,7 +5831,7 @@ ); name = tomcrypt; productName = tomcrypt; - productReference = AA7C8B8B0B67460600FD9940 /* libtomcrypt.a */; + productReference = AA7C8B8B0B67460600FD9940 /* libtomcrypt-sm5.a */; productType = "com.apple.product-type.library.static"; }; AAA070A80CE7B0DF005A3060 /* mad */ = { @@ -5866,7 +5865,7 @@ ); name = "lua-5.1"; productName = "lua-5.1"; - productReference = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1.a */; + productReference = AAE7817E0AC7E37B00AEFC64 /* liblua-5.1-sm5.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ @@ -6200,7 +6199,6 @@ AA29CDD50558741A00961A51 /* ScreenSelectCharacter.cpp in Sources */, AA29CDDB0558741A00961A51 /* ScreenSelectMusic.cpp in Sources */, AA29CDDD0558741A00961A51 /* ScreenSongOptions.cpp in Sources */, - AA29CDE10558741A00961A51 /* ScreenTestFonts.cpp in Sources */, AA29CDE20558741A00961A51 /* ScreenTestSound.cpp in Sources */, AA29CDE30558741A00961A51 /* ScreenTextEntry.cpp in Sources */, AA29CDE40558741A00961A51 /* ScreenTitleMenu.cpp in Sources */, @@ -6489,6 +6487,7 @@ 2BD06FF2137242680018CB9F /* json_value.cpp in Sources */, 2BD06FF4137242680018CB9F /* json_writer.cpp in Sources */, 2B43509613949F37006FA051 /* TimingSegments.cpp in Sources */, + B71A60C0139B41DB00183A27 /* InGameLoadingWindow.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6607,7 +6606,6 @@ AA40D3FF09A08D650068C0D5 /* ScreenSelectCharacter.cpp in Sources */, AA40D40309A08D650068C0D5 /* ScreenSelectMusic.cpp in Sources */, AA40D40509A08D650068C0D5 /* ScreenSongOptions.cpp in Sources */, - AA40D40709A08D650068C0D5 /* ScreenTestFonts.cpp in Sources */, AA40D40809A08D650068C0D5 /* ScreenTestSound.cpp in Sources */, AA40D40909A08D650068C0D5 /* ScreenTextEntry.cpp in Sources */, AA40D40A09A08D650068C0D5 /* ScreenTitleMenu.cpp in Sources */, @@ -7344,6 +7342,7 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7373,7 +7372,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = "png-1.5.1sm0.1"; + PRODUCT_NAME = "png-1.5.1-sm5"; USER_HEADER_SEARCH_PATHS = ""; }; name = Native; @@ -7387,6 +7386,7 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7416,7 +7416,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = "png-1.5.1sm0.1"; + PRODUCT_NAME = "png-1.5.1-sm5"; USER_HEADER_SEARCH_PATHS = ""; }; name = PerformanceDebug; @@ -7430,6 +7430,7 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7459,7 +7460,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = "png-1.5.1sm0.1"; + PRODUCT_NAME = "png-1.5.1-sm5"; USER_HEADER_SEARCH_PATHS = ""; }; name = Universal; @@ -7476,6 +7477,7 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7505,7 +7507,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = "png-1.5.1sm0.1"; + PRODUCT_NAME = "png-1.5.1-sm5"; USER_HEADER_SEARCH_PATHS = ""; }; name = Debug; @@ -7519,6 +7521,7 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7547,7 +7550,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = glew; + PRODUCT_NAME = "glew-sm5"; USER_HEADER_SEARCH_PATHS = ""; }; name = Native; @@ -7561,6 +7564,7 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7589,7 +7593,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = glew; + PRODUCT_NAME = "glew-sm5"; USER_HEADER_SEARCH_PATHS = ""; }; name = PerformanceDebug; @@ -7603,6 +7607,7 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7631,7 +7636,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = glew; + PRODUCT_NAME = "glew-sm5"; USER_HEADER_SEARCH_PATHS = ""; }; name = Universal; @@ -7648,6 +7653,7 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7676,7 +7682,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = glew; + PRODUCT_NAME = "glew-sm5"; USER_HEADER_SEARCH_PATHS = ""; }; name = Debug; @@ -7690,6 +7696,7 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = ""; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7717,7 +7724,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = pcre; + PRODUCT_NAME = "pcre-sm5"; }; name = Native; }; @@ -7730,6 +7737,7 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = ""; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7757,7 +7765,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = pcre; + PRODUCT_NAME = "pcre-sm5"; }; name = PerformanceDebug; }; @@ -7770,6 +7778,7 @@ GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = ""; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7797,7 +7806,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = pcre; + PRODUCT_NAME = "pcre-sm5"; }; name = Universal; }; @@ -7813,6 +7822,7 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = ""; GCC_PREFIX_HEADER = ""; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO; @@ -7840,7 +7850,7 @@ INSTALL_PATH = /usr/local/lib; OTHER_LDFLAGS = ""; PREBINDING = NO; - PRODUCT_NAME = pcre; + PRODUCT_NAME = "pcre-sm5"; }; name = Debug; }; @@ -7876,11 +7886,13 @@ buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; FULL_NAME = "$(PRODUCT_NAME).$(WRAPPER_EXTENSION)"; + GCC_AUTO_VECTORIZATION = NO; GCC_ENABLE_SSE3_EXTENSIONS = NO; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; GCC_PREFIX_HEADER = "$(SRCROOT)/../src/archutils/Darwin/StepMania.pch"; GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../src", "$(SRCROOT)/../src/ffmpeg/include", @@ -7903,11 +7915,10 @@ OTHER_CPLUSPLUSFLAGS = ( "-finline-limit=300", "-fconstant-cfstrings", - "-fsingle-precision-constant", "-fno-exceptions", "-falign-loops=16", ); - PRODUCT_NAME = "$(value)"; + PRODUCT_NAME = StepMania; SYMROOT = "$(SRCROOT)/.."; WRAPPER_EXTENSION = app; }; @@ -7938,7 +7949,7 @@ GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; GCC_STRICT_ALIASING = YES; GCC_UNROLL_LOOPS = YES; - GCC_VERSION = 4.0; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; @@ -7992,6 +8003,7 @@ NO_MP3_SUPPORT, WITHOUT_NETWORKING, ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../src", "$(SRCROOT)/Frameworks/ffmpeg.framework/Headers", @@ -8040,6 +8052,7 @@ NO_MP3_SUPPORT, WITHOUT_NETWORKING, ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../src", "$(SRCROOT)/Frameworks/ffmpeg.framework/Headers", @@ -8090,6 +8103,7 @@ WITHOUT_NETWORKING, "$(value)", ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../src", "$(SRCROOT)/Frameworks/ffmpeg.framework/Headers", @@ -8133,6 +8147,7 @@ LUA_USE_MACOSX, "$(value)", ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "$(HOME)/bin"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/build/$(CONFIGURATION)"; OBJROOT = "$(SRCROOT)/build"; @@ -8151,6 +8166,7 @@ LUA_USE_MACOSX, "$(value)", ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "$(HOME)/bin"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/build/$(CONFIGURATION)"; OBJROOT = "$(SRCROOT)/build"; @@ -8169,6 +8185,7 @@ LUA_USE_MACOSX, "$(value)", ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "$(HOME)/bin"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/build/$(CONFIGURATION)"; OBJROOT = "$(SRCROOT)/build"; @@ -8184,6 +8201,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; GCC_PREPROCESSOR_DEFINITIONS = LUA_USE_MACOSX; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "$(HOME)/bin"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/build/$(CONFIGURATION)"; OBJROOT = "$(SRCROOT)/build"; @@ -8199,6 +8217,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; GCC_PREPROCESSOR_DEFINITIONS = LUA_USE_MACOSX; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "$(HOME)/bin"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/build/$(CONFIGURATION)"; OBJROOT = "$(SRCROOT)/build"; @@ -8214,6 +8233,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; GCC_PREPROCESSOR_DEFINITIONS = LUA_USE_MACOSX; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "$(HOME)/bin"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/build/$(CONFIGURATION)"; OBJROOT = "$(SRCROOT)/build"; @@ -8253,11 +8273,12 @@ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)"; GCC_DYNAMIC_NO_PIC = YES; GCC_MODEL_TUNING = G5; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; GCC_WARN_PROTOTYPE_CONVERSION = NO; INSTALL_PATH = /usr/local/lib; - PRODUCT_NAME = tommath; + PRODUCT_NAME = "tommath-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = Native; @@ -8268,11 +8289,12 @@ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)"; GCC_DYNAMIC_NO_PIC = YES; GCC_MODEL_TUNING = G5; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; GCC_WARN_PROTOTYPE_CONVERSION = NO; INSTALL_PATH = /usr/local/lib; - PRODUCT_NAME = tommath; + PRODUCT_NAME = "tommath-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = Universal; @@ -8285,11 +8307,12 @@ GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; GCC_WARN_PROTOTYPE_CONVERSION = NO; INSTALL_PATH = /usr/local/lib; - PRODUCT_NAME = tommath; + PRODUCT_NAME = "tommath-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = Debug; @@ -8302,11 +8325,12 @@ GCC_DYNAMIC_NO_PIC = YES; GCC_ENABLE_CPP_RTTI = NO; GCC_NO_COMMON_BLOCKS = YES; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; GCC_WARN_PROTOTYPE_CONVERSION = NO; INSTALL_PATH = /usr/local/lib; KEEP_PRIVATE_EXTERNS = YES; - PRODUCT_NAME = tomcrypt; + PRODUCT_NAME = "tomcrypt-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = Native; @@ -8319,11 +8343,12 @@ GCC_DYNAMIC_NO_PIC = YES; GCC_ENABLE_CPP_RTTI = NO; GCC_NO_COMMON_BLOCKS = YES; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; GCC_WARN_PROTOTYPE_CONVERSION = NO; INSTALL_PATH = /usr/local/lib; KEEP_PRIVATE_EXTERNS = YES; - PRODUCT_NAME = tomcrypt; + PRODUCT_NAME = "tomcrypt-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = Universal; @@ -8336,11 +8361,16 @@ GCC_DYNAMIC_NO_PIC = YES; GCC_ENABLE_CPP_RTTI = NO; GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + LTC_NO_ROLC, + "DEBUG=1", + ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; GCC_WARN_PROTOTYPE_CONVERSION = NO; INSTALL_PATH = /usr/local/lib; KEEP_PRIVATE_EXTERNS = YES; - PRODUCT_NAME = tomcrypt; + PRODUCT_NAME = "tomcrypt-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = Debug; @@ -8366,6 +8396,7 @@ "SIZEOF_LONG=4", "$(FPM)", ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; @@ -8402,6 +8433,7 @@ "SIZEOF_LONG=4", "$(FPM)", ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; @@ -8438,6 +8470,7 @@ "SIZEOF_LONG=4", "$(FPM)", ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; @@ -8477,6 +8510,7 @@ "SIZEOF_LONG=4", "$(FPM)", ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; @@ -8515,7 +8549,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_STRICT_ALIASING = YES; GCC_UNROLL_LOOPS = YES; - GCC_VERSION = 4.0; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; @@ -8562,12 +8596,14 @@ COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = stabs; FULL_NAME = "$(PRODUCT_NAME).$(WRAPPER_EXTENSION)"; + GCC_AUTO_VECTORIZATION = NO; GCC_ENABLE_SSE3_EXTENSIONS = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; GCC_PREFIX_HEADER = "$(SRCROOT)/../src/archutils/Darwin/StepMania.pch"; GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../src", "$(SRCROOT)/../src/ffmpeg/include", @@ -8590,11 +8626,10 @@ OTHER_CPLUSPLUSFLAGS = ( "-finline-limit=300", "-fconstant-cfstrings", - "-fsingle-precision-constant", "-fno-exceptions", "-falign-loops=16", ); - PRODUCT_NAME = "$(value)"; + PRODUCT_NAME = StepMania; STRIP_INSTALLED_PRODUCT = NO; SYMROOT = "$(SRCROOT)/.."; WRAPPER_EXTENSION = app; @@ -8642,6 +8677,7 @@ NO_MP3_SUPPORT, WITHOUT_NETWORKING, ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../src", "$(SRCROOT)/Frameworks/ffmpeg.framework/Headers", @@ -8687,6 +8723,7 @@ "$(value)", LUA_USE_MACOSX, ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; @@ -8695,7 +8732,7 @@ INSTALL_PATH = /usr/local/lib; OBJROOT = "$(SRCROOT)/build"; PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; - PRODUCT_NAME = "lua-5.1"; + PRODUCT_NAME = "lua-5.1-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = PerformanceDebug; @@ -8710,6 +8747,7 @@ LUA_USE_MACOSX, "$(value)", ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "$(HOME)/bin"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/build/$(CONFIGURATION)"; OBJROOT = "$(SRCROOT)/build"; @@ -8725,6 +8763,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = NO; GCC_PREFIX_HEADER = ""; GCC_PREPROCESSOR_DEFINITIONS = LUA_USE_MACOSX; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INSTALL_PATH = "$(HOME)/bin"; LIBRARY_SEARCH_PATHS = "$(SRCROOT)/build/$(CONFIGURATION)"; OBJROOT = "$(SRCROOT)/build"; @@ -8746,11 +8785,12 @@ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)"; GCC_DYNAMIC_NO_PIC = YES; GCC_MODEL_TUNING = G5; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; GCC_WARN_PROTOTYPE_CONVERSION = NO; INSTALL_PATH = /usr/local/lib; - PRODUCT_NAME = tommath; + PRODUCT_NAME = "tommath-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = PerformanceDebug; @@ -8763,11 +8803,12 @@ GCC_DYNAMIC_NO_PIC = YES; GCC_ENABLE_CPP_RTTI = NO; GCC_NO_COMMON_BLOCKS = YES; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; GCC_WARN_PROTOTYPE_CONVERSION = NO; INSTALL_PATH = /usr/local/lib; KEEP_PRIVATE_EXTERNS = YES; - PRODUCT_NAME = tomcrypt; + PRODUCT_NAME = "tomcrypt-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = PerformanceDebug; @@ -8804,9 +8845,12 @@ buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; FULL_NAME = "$(PRODUCT_NAME).$(WRAPPER_EXTENSION)"; - GCC_ENABLE_SSE3_EXTENSIONS = NO; + GCC_AUTO_VECTORIZATION = YES; + GCC_ENABLE_SSE3_EXTENSIONS = YES; + GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES; GCC_PREFIX_HEADER = "$(SRCROOT)/../src/archutils/Darwin/StepMania.pch"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../src", "$(SRCROOT)/../src/ffmpeg/include", @@ -8829,11 +8873,10 @@ OTHER_CPLUSPLUSFLAGS = ( "-finline-limit=300", "-fconstant-cfstrings", - "-fsingle-precision-constant", "-fno-exceptions", "-falign-loops=16", ); - PRODUCT_NAME = "$(value)"; + PRODUCT_NAME = StepMania; SYMROOT = "$(SRCROOT)/.."; WRAPPER_EXTENSION = app; }; @@ -8862,7 +8905,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_STRICT_ALIASING = YES; GCC_UNROLL_LOOPS = YES; - GCC_VERSION = 4.0; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; @@ -8933,9 +8976,12 @@ buildSettings = { CONFIGURATION_BUILD_DIR = "$(SYMROOT)"; FULL_NAME = "$(PRODUCT_NAME).$(WRAPPER_EXTENSION)"; + GCC_AUTO_VECTORIZATION = NO; GCC_ENABLE_OBJC_EXCEPTIONS = NO; + GCC_ENABLE_SSE3_EXTENSIONS = NO; GCC_PREFIX_HEADER = "$(SRCROOT)/../src/archutils/Darwin/StepMania.pch"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( "$(SRCROOT)/../src", "$(SRCROOT)/../src/ffmpeg/include", @@ -8958,11 +9004,10 @@ OTHER_CPLUSPLUSFLAGS = ( "-finline-limit=300", "-fconstant-cfstrings", - "-fsingle-precision-constant", "-fno-exceptions", "-falign-loops=16", ); - PRODUCT_NAME = "$(value)"; + PRODUCT_NAME = StepMania; SYMROOT = "$(SRCROOT)/.."; WRAPPER_EXTENSION = app; }; @@ -8992,7 +9037,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_STRICT_ALIASING = YES; GCC_UNROLL_LOOPS = YES; - GCC_VERSION = 4.0; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; @@ -9043,6 +9088,7 @@ "$(value)", LUA_USE_MACOSX, ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; @@ -9051,7 +9097,7 @@ INSTALL_PATH = /usr/local/lib; OBJROOT = "$(SRCROOT)/build"; PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; - PRODUCT_NAME = "lua-5.1"; + PRODUCT_NAME = "lua-5.1-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = Native; @@ -9068,6 +9114,7 @@ "$(value)", LUA_USE_MACOSX, ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; @@ -9076,7 +9123,7 @@ INSTALL_PATH = /usr/local/lib; OBJROOT = "$(SRCROOT)/build"; PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; - PRODUCT_NAME = "lua-5.1"; + PRODUCT_NAME = "lua-5.1-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = Universal; @@ -9093,6 +9140,7 @@ "$(value)", LUA_USE_MACOSX, ); + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO; @@ -9101,7 +9149,7 @@ INSTALL_PATH = /usr/local/lib; OBJROOT = "$(SRCROOT)/build"; PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; - PRODUCT_NAME = "lua-5.1"; + PRODUCT_NAME = "lua-5.1-sm5"; SYMROOT = "$(SRCROOT)/build"; }; name = Debug; diff --git a/Themes/default/~res/24x24 icon.psd b/_assets/Themes/default/~res/24x24 icon.psd similarity index 100% rename from Themes/default/~res/24x24 icon.psd rename to _assets/Themes/default/~res/24x24 icon.psd diff --git a/Themes/default/~res/BannerFrame.7z b/_assets/Themes/default/~res/BannerFrame.7z similarity index 100% rename from Themes/default/~res/BannerFrame.7z rename to _assets/Themes/default/~res/BannerFrame.7z diff --git a/Themes/default/~res/Common fallback background.7z b/_assets/Themes/default/~res/Common fallback background.7z similarity index 100% rename from Themes/default/~res/Common fallback background.7z rename to _assets/Themes/default/~res/Common fallback background.7z diff --git a/Themes/default/~res/Common fallback banners.psd b/_assets/Themes/default/~res/Common fallback banners.psd similarity index 100% rename from Themes/default/~res/Common fallback banners.psd rename to _assets/Themes/default/~res/Common fallback banners.psd diff --git a/Themes/default/~res/EvaluationFrame.7z b/_assets/Themes/default/~res/EvaluationFrame.7z similarity index 100% rename from Themes/default/~res/EvaluationFrame.7z rename to _assets/Themes/default/~res/EvaluationFrame.7z diff --git a/Themes/default/~res/Footer.7z b/_assets/Themes/default/~res/Footer.7z similarity index 100% rename from Themes/default/~res/Footer.7z rename to _assets/Themes/default/~res/Footer.7z diff --git a/Themes/default/~res/FoundationLogo.7z b/_assets/Themes/default/~res/FoundationLogo.7z similarity index 100% rename from Themes/default/~res/FoundationLogo.7z rename to _assets/Themes/default/~res/FoundationLogo.7z diff --git a/Themes/default/~res/Header.7z b/_assets/Themes/default/~res/Header.7z similarity index 100% rename from Themes/default/~res/Header.7z rename to _assets/Themes/default/~res/Header.7z diff --git a/Themes/default/~res/HoldJudgment label 1x2.psd b/_assets/Themes/default/~res/HoldJudgment label 1x2.psd similarity index 100% rename from Themes/default/~res/HoldJudgment label 1x2.psd rename to _assets/Themes/default/~res/HoldJudgment label 1x2.psd diff --git a/Themes/default/~res/Judgments.7z b/_assets/Themes/default/~res/Judgments.7z similarity index 100% rename from Themes/default/~res/Judgments.7z rename to _assets/Themes/default/~res/Judgments.7z diff --git a/Themes/default/~res/Judgments.psd b/_assets/Themes/default/~res/Judgments.psd similarity index 100% rename from Themes/default/~res/Judgments.psd rename to _assets/Themes/default/~res/Judgments.psd diff --git a/Themes/default/~res/LifeMeterBar.7z b/_assets/Themes/default/~res/LifeMeterBar.7z similarity index 100% rename from Themes/default/~res/LifeMeterBar.7z rename to _assets/Themes/default/~res/LifeMeterBar.7z diff --git a/Themes/default/~res/MenuTimer frame.7z b/_assets/Themes/default/~res/MenuTimer frame.7z similarity index 100% rename from Themes/default/~res/MenuTimer frame.7z rename to _assets/Themes/default/~res/MenuTimer frame.7z diff --git a/Themes/default/~res/PaneDisplay frame.psd b/_assets/Themes/default/~res/PaneDisplay frame.psd similarity index 100% rename from Themes/default/~res/PaneDisplay frame.psd rename to _assets/Themes/default/~res/PaneDisplay frame.psd diff --git a/_assets/Themes/default/~res/Player fc badge.psd b/_assets/Themes/default/~res/Player fc badge.psd new file mode 100644 index 0000000000..644ae13dbb Binary files /dev/null and b/_assets/Themes/default/~res/Player fc badge.psd differ diff --git a/Themes/default/~res/ScreenGameplay SongMeterDisplay parts.psd b/_assets/Themes/default/~res/ScreenGameplay SongMeterDisplay parts.psd similarity index 100% rename from Themes/default/~res/ScreenGameplay SongMeterDisplay parts.psd rename to _assets/Themes/default/~res/ScreenGameplay SongMeterDisplay parts.psd diff --git a/Themes/default/~res/ScreenGameplay ready.7z b/_assets/Themes/default/~res/ScreenGameplay ready.7z similarity index 100% rename from Themes/default/~res/ScreenGameplay ready.7z rename to _assets/Themes/default/~res/ScreenGameplay ready.7z diff --git a/Themes/default/~res/ScreenGameplay ready.psd b/_assets/Themes/default/~res/ScreenGameplay ready.psd similarity index 100% rename from Themes/default/~res/ScreenGameplay ready.psd rename to _assets/Themes/default/~res/ScreenGameplay ready.psd diff --git a/Themes/default/~res/ScreenOptions page.7z b/_assets/Themes/default/~res/ScreenOptions page.7z similarity index 100% rename from Themes/default/~res/ScreenOptions page.7z rename to _assets/Themes/default/~res/ScreenOptions page.7z diff --git a/Themes/default/~res/ScreenQuickSetupOverview icon.psd b/_assets/Themes/default/~res/ScreenQuickSetupOverview icon.psd similarity index 100% rename from Themes/default/~res/ScreenQuickSetupOverview icon.psd rename to _assets/Themes/default/~res/ScreenQuickSetupOverview icon.psd diff --git a/Themes/default/~res/ScreenSelect generic icons.7z b/_assets/Themes/default/~res/ScreenSelect generic icons.7z similarity index 100% rename from Themes/default/~res/ScreenSelect generic icons.7z rename to _assets/Themes/default/~res/ScreenSelect generic icons.7z diff --git a/Themes/default/~res/ScreenSelectMusic DifficultyDisplay.psd b/_assets/Themes/default/~res/ScreenSelectMusic DifficultyDisplay.psd similarity index 100% rename from Themes/default/~res/ScreenSelectMusic DifficultyDisplay.psd rename to _assets/Themes/default/~res/ScreenSelectMusic DifficultyDisplay.psd diff --git a/Themes/default/~res/ScreenSelectMusic DifficultyDisplayLarge.psd b/_assets/Themes/default/~res/ScreenSelectMusic DifficultyDisplayLarge.psd similarity index 100% rename from Themes/default/~res/ScreenSelectMusic DifficultyDisplayLarge.psd rename to _assets/Themes/default/~res/ScreenSelectMusic DifficultyDisplayLarge.psd diff --git a/Themes/default/~res/ScreenSelectPlayMode scroller background.psd b/_assets/Themes/default/~res/ScreenSelectPlayMode scroller background.psd similarity index 100% rename from Themes/default/~res/ScreenSelectPlayMode scroller background.psd rename to _assets/Themes/default/~res/ScreenSelectPlayMode scroller background.psd diff --git a/Themes/default/~res/ScreenSelectPlayMode scroller icons.psd b/_assets/Themes/default/~res/ScreenSelectPlayMode scroller icons.psd similarity index 100% rename from Themes/default/~res/ScreenSelectPlayMode scroller icons.psd rename to _assets/Themes/default/~res/ScreenSelectPlayMode scroller icons.psd diff --git a/Themes/default/~res/ScreenSelectProfile Card.psd b/_assets/Themes/default/~res/ScreenSelectProfile Card.psd similarity index 100% rename from Themes/default/~res/ScreenSelectProfile Card.psd rename to _assets/Themes/default/~res/ScreenSelectProfile Card.psd diff --git a/Themes/default/~res/ScreenStageInformation stage.psd b/_assets/Themes/default/~res/ScreenStageInformation stage.psd similarity index 100% rename from Themes/default/~res/ScreenStageInformation stage.psd rename to _assets/Themes/default/~res/ScreenStageInformation stage.psd diff --git a/Themes/default/~res/SelectIcons.7z b/_assets/Themes/default/~res/SelectIcons.7z similarity index 100% rename from Themes/default/~res/SelectIcons.7z rename to _assets/Themes/default/~res/SelectIcons.7z diff --git a/Themes/default/~res/SelectIcons.psd b/_assets/Themes/default/~res/SelectIcons.psd similarity index 100% rename from Themes/default/~res/SelectIcons.psd rename to _assets/Themes/default/~res/SelectIcons.psd diff --git a/Themes/default/~res/SnapDisplay icon 9x1.7z b/_assets/Themes/default/~res/SnapDisplay icon 9x1.7z similarity index 100% rename from Themes/default/~res/SnapDisplay icon 9x1.7z rename to _assets/Themes/default/~res/SnapDisplay icon 9x1.7z diff --git a/Themes/default/~res/StepsDisplay StepsType.psd b/_assets/Themes/default/~res/StepsDisplay StepsType.psd similarity index 100% rename from Themes/default/~res/StepsDisplay StepsType.psd rename to _assets/Themes/default/~res/StepsDisplay StepsType.psd diff --git a/Themes/default/~res/StepsDisplay frame.7z b/_assets/Themes/default/~res/StepsDisplay frame.7z similarity index 100% rename from Themes/default/~res/StepsDisplay frame.7z rename to _assets/Themes/default/~res/StepsDisplay frame.7z diff --git a/Themes/default/~res/StepsDisplayListRow Cursor.7z b/_assets/Themes/default/~res/StepsDisplayListRow Cursor.7z similarity index 100% rename from Themes/default/~res/StepsDisplayListRow Cursor.7z rename to _assets/Themes/default/~res/StepsDisplayListRow Cursor.7z diff --git a/Themes/default/~res/StepsDisplayListRow arrow.7z b/_assets/Themes/default/~res/StepsDisplayListRow arrow.7z similarity index 100% rename from Themes/default/~res/StepsDisplayListRow arrow.7z rename to _assets/Themes/default/~res/StepsDisplayListRow arrow.7z diff --git a/Themes/default/~res/StepsDisplayMusic frame.7z b/_assets/Themes/default/~res/StepsDisplayMusic frame.7z similarity index 100% rename from Themes/default/~res/StepsDisplayMusic frame.7z rename to _assets/Themes/default/~res/StepsDisplayMusic frame.7z diff --git a/Themes/default/~res/StepsDisplayMusic frame.psd b/_assets/Themes/default/~res/StepsDisplayMusic frame.psd similarity index 100% rename from Themes/default/~res/StepsDisplayMusic frame.psd rename to _assets/Themes/default/~res/StepsDisplayMusic frame.psd diff --git a/Themes/default/~res/musicwheel.7z b/_assets/Themes/default/~res/musicwheel.7z similarity index 100% rename from Themes/default/~res/musicwheel.7z rename to _assets/Themes/default/~res/musicwheel.7z diff --git a/Themes/default/~res/musicwheel.psd b/_assets/Themes/default/~res/musicwheel.psd similarity index 100% rename from Themes/default/~res/musicwheel.psd rename to _assets/Themes/default/~res/musicwheel.psd diff --git a/Themes/default/~res/pills.7z b/_assets/Themes/default/~res/pills.7z similarity index 100% rename from Themes/default/~res/pills.7z rename to _assets/Themes/default/~res/pills.7z diff --git a/Themes/default/~res/sm-ssc logo.7z b/_assets/Themes/default/~res/sm-ssc logo.7z similarity index 100% rename from Themes/default/~res/sm-ssc logo.7z rename to _assets/Themes/default/~res/sm-ssc logo.7z diff --git a/Themes/default/~res/uf_footer.7z b/_assets/Themes/default/~res/uf_footer.7z similarity index 100% rename from Themes/default/~res/uf_footer.7z rename to _assets/Themes/default/~res/uf_footer.7z diff --git a/Themes/default/~res/uf_header.7z b/_assets/Themes/default/~res/uf_header.7z similarity index 100% rename from Themes/default/~res/uf_header.7z rename to _assets/Themes/default/~res/uf_header.7z diff --git a/Themes/default/~res/uf_shared bg.7z b/_assets/Themes/default/~res/uf_shared bg.7z similarity index 100% rename from Themes/default/~res/uf_shared bg.7z rename to _assets/Themes/default/~res/uf_shared bg.7z diff --git a/_assets/fonts/frutiger 24px [polish-stroke] 8x2.psd b/_assets/fonts/frutiger 24px [polish-stroke] 8x2.psd new file mode 100644 index 0000000000..da93af035a Binary files /dev/null and b/_assets/fonts/frutiger 24px [polish-stroke] 8x2.psd differ diff --git a/_assets/fonts/frutiger 24px [polish] 8x2.psd b/_assets/fonts/frutiger 24px [polish] 8x2.psd new file mode 100644 index 0000000000..7d8c554687 Binary files /dev/null and b/_assets/fonts/frutiger 24px [polish] 8x2.psd differ diff --git a/_assets/logo.psd b/_assets/logo.psd index d59c9f8de8..312e23b9ea 100644 Binary files a/_assets/logo.psd and b/_assets/logo.psd differ diff --git a/autoconf/m4/opengl.m4 b/autoconf/m4/opengl.m4 index e213addf18..e982d76c75 100644 --- a/autoconf/m4/opengl.m4 +++ b/autoconf/m4/opengl.m4 @@ -1,34 +1,36 @@ AC_DEFUN([SM_X_WITH_OPENGL], [ - AC_PATH_X - - XCFLAGS= - XLIBS= + AC_PATH_X - if test "$no_x" != "yes"; then + XCFLAGS= + XLIBS= + + if test "$no_x" != "yes"; then if test -n "$x_includes"; then - XCFLAGS="-I$x_includes" + XCFLAGS="-I$x_includes" fi if test -n "$x_libraries"; then - XLIBS="-L$x_libraries -lX11" + XLIBS="-L$x_libraries" fi + XLIBS+="-lX11" + if test -n "$x_includes"; then - # See if we can compile X applications without using $XCFLAGS. - AC_MSG_CHECKING(if $XCFLAGS is really necessary) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[]])],[XCFLAGS= + # See if we can compile X applications without using $XCFLAGS. + AC_MSG_CHECKING(if $XCFLAGS is really necessary) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[]])],[XCFLAGS= AC_MSG_RESULT(no)],[AC_MSG_RESULT(yes)]) fi # Check for libXtst. AC_CHECK_LIB(Xtst, XTestQueryExtension, - XLIBS="$XLIBS -lXtst" - [AC_DEFINE(HAVE_LIBXTST, 1, [libXtst available])], - , - [$XLIBS]) + XLIBS="$XLIBS -lXtst" + [AC_DEFINE(HAVE_LIBXTST, 1, [libXtst available])], + , + [$XLIBS]) AC_DEFINE(HAVE_X11, 1, [X11 libraries present]) - fi + fi # Check for Xrandr # Can someone fix this for me? This is producing bizarre warnings from @@ -53,15 +55,15 @@ AC_DEFUN([SM_X_WITH_OPENGL], AM_CONDITIONAL(HAVE_X11, test "$no_x" != "yes") - AC_SUBST(XCFLAGS) - AC_SUBST(XLIBS) + AC_SUBST(XCFLAGS) + AC_SUBST(XLIBS) - # Check for libGL and libGLU. - AC_CHECK_LIB(GL, glPushMatrix, XLIBS="$XLIBS -lGL", + # Check for libGL and libGLU. + AC_CHECK_LIB(GL, glPushMatrix, XLIBS="$XLIBS -lGL", AC_MSG_ERROR([No OpenGL library could be found.]), [$XLIBS]) - AC_CHECK_LIB(GLU, gluGetString, XLIBS="$XLIBS -lGLU", + AC_CHECK_LIB(GLU, gluGetString, XLIBS="$XLIBS -lGLU", AC_MSG_ERROR([No GLU library could be found.]), [$XLIBS]) - AC_SUBST(XLIBS) + AC_SUBST(XLIBS) ]) diff --git a/configure.ac b/configure.ac index 7917055408..dbf0199dca 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.59) -AC_INIT(sm-ssc, experimental, [http://ssc.ajworld.net/sm-ssc/], StepMania) +AC_INIT(StepMania 5, experimental, [http://ssc.ajworld.net/sm-ssc/], StepMania) AC_CONFIG_SRCDIR([src/StepMania.cpp]) AC_CONFIG_AUX_DIR(autoconf) AC_CANONICAL_TARGET diff --git a/extern/libjpeg/xboxjpeg.lib b/extern/libjpeg/xboxjpeg.lib deleted file mode 100644 index cfd6a92d07..0000000000 Binary files a/extern/libjpeg/xboxjpeg.lib and /dev/null differ diff --git a/sm-ssc.nsi b/sm-ssc.nsi index a7560744b1..f0644064db 100644 --- a/sm-ssc.nsi +++ b/sm-ssc.nsi @@ -42,7 +42,7 @@ ; don't forget to change this before releasing a new verson. ; wish this could be automated, but it requires "X.Y.Z.a" format. -aj - VIProductVersion "1.2.3.0" + VIProductVersion "5.0.0.3" VIAddVersionKey "ProductName" "${PRODUCT_ID}" VIAddVersionKey "FileVersion" "${PRODUCT_VER}" VIAddVersionKey "FileDescription" "${PRODUCT_ID} Installer" @@ -52,8 +52,16 @@ SetDateSave on ; (can be on to have files restored to their orginal date) ; I think it may need actual admin privs for writing to the registry... -aj - ; RequestExecutionLevel user - ; this folder may not be the best idea for Windows Vista/7. -aj + ;RequestExecutionLevel user + + ;GetVersion::WindowsServicePackMajor + ;Pop $R0 + ;${If} $R0 >= 6 + ; vista & 7 + ;${Else} + ; xp and below + ;${EndIf} + InstallDir "$PROGRAMFILES\${PRODUCT_ID}" InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${PRODUCT_ID}" "" @@ -211,8 +219,8 @@ Section "Main Section" SecMain WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\${PRODUCT_ID}" "" "$INSTDIR" WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_ID}" "DisplayName" "$(TEXT_IO_REMOVE_ONLY)" WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_ID}" "DisplayVersion" "$(PRODUCT_VER)" - WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_ID}" "Comments" "sm-ssc is a rhythm game simulator (forked from StepMania)." - WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_ID}" "Publisher" "the spinal shark collective" + WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_ID}" "Comments" "StepMania 5 is a rhythm game simulator." + WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_ID}" "Publisher" "StepMania Team" WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_ID}" "URLInfoAbout" "http://code.google.com/p/sm-ssc/" WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_ID}" "URLUpdateInfo" "http://code.google.com/p/sm-ssc/" WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_ID}" "UninstallString" '"$INSTDIR\uninstall.exe"' @@ -295,6 +303,7 @@ Section "Main Section" SecMain RMDir /r "$INSTDIR\NoteSkins\dance\midi" ; we may also want to remove the new ones. RMDir /r "$INSTDIR\NoteSkins\dance\midi-note" + RMDir /r "$INSTDIR\NoteSkins\dance\midi-note-3d" RMDir /r "$INSTDIR\NoteSkins\dance\midi-solo" RMDir /r "$INSTDIR\NoteSkins\dance\midi-vivid" RMDir /r "$INSTDIR\NoteSkins\dance\midi-rhythm-p1" @@ -382,6 +391,7 @@ Section "Main Section" SecMain CreateDirectory "$INSTDIR\Songs" SetOutPath "$INSTDIR\Songs" ;File "Songs\Instructions.txt" + File /r /x CVS /x .svn "Songs\*" ; remove and install themes RMDir /r "$INSTDIR\Themes\_fallback" @@ -456,6 +466,7 @@ Section "Main Section" SecMain File "Docs\Changelog_sm5.txt" File "Docs\Changelog_SSCformat.txt" File "Docs\CommandLineArgs.txt" + File "Docs\CourseFormat.txt" File /r /x CVS /x .svn "Docs\license-ext" File /r /x CVS /x .svn "Docs\Luadoc" File /r /x CVS /x .svn "Docs\Themerdocs" @@ -532,21 +543,21 @@ Function ShowAutorun IfFileExists "$R1" show_play_and_reinstall show_only_install: - GetDlgItem $1 $hwnd 1201 ; Second cutom control + GetDlgItem $1 $hwnd 1201 ; Second custom control ShowWindow $1 0 - GetDlgItem $1 $hwnd 1202 ; Third cutom control + GetDlgItem $1 $hwnd 1202 ; Third custom control ShowWindow $1 0 Goto done show_play_and_reinstall: - GetDlgItem $1 $hwnd 1200 ; First cutom control + GetDlgItem $1 $hwnd 1200 ; First custom control ShowWindow $1 0 done: ; Now show the dialog and wait for it to finish InstallOptions::show - + ; Finally fetch the InstallOptions status value (we don't care what it is though) Pop $0 @@ -574,7 +585,7 @@ Function LeaveAutorun play_error: MessageBox MB_ICONEXCLAMATION "$(TEXT_IO_COULD_NOT_EXECUTE)" abort - + proceed: GetDlgItem $1 $HWNDPARENT 1 ; Next button ShowWindow $1 1 @@ -741,6 +752,7 @@ Section "Uninstall" RMDir /r "$INSTDIR\NoteSkins\dance\default" RMDir /r "$INSTDIR\NoteSkins\dance\Delta" RMDir /r "$INSTDIR\NoteSkins\dance\midi-note" + RMDir /r "$INSTDIR\NoteSkins\dance\midi-note-3d" RMDir /r "$INSTDIR\NoteSkins\dance\midi-routine-p1" RMDir /r "$INSTDIR\NoteSkins\dance\midi-routine-p2" RMDir /r "$INSTDIR\NoteSkins\dance\midi-solo" @@ -751,8 +763,13 @@ Section "Uninstall" RMDir "$INSTDIR\NoteSkins\dance" RMDir /r "$INSTDIR\NoteSkins\pump\cmd" + RMDir /r "$INSTDIR\NoteSkins\pump\cmd-routine-p1" + RMDir /r "$INSTDIR\NoteSkins\pump\cmd-routine-p2" RMDir /r "$INSTDIR\NoteSkins\pump\complex" RMDir /r "$INSTDIR\NoteSkins\pump\default" + RMDir /r "$INSTDIR\NoteSkins\pump\frame5p" + RMDir /r "$INSTDIR\NoteSkins\pump\newextra" + RMDir /r "$INSTDIR\NoteSkins\pump\rhythm" RMDir /r "$INSTDIR\NoteSkins\pump\simple" RMDir "$INSTDIR\NoteSkins\pump" @@ -824,7 +841,7 @@ Section "Uninstall" Delete "$INSTDIR\Program\zlib1.dll" RMDir "$INSTDIR\Program" - Delete "$INSTDIR\Licenses.txt" + Delete "$INSTDIR\Docs\Licenses.txt" RMDir /r "$INSTDIR\Manual" !endif @@ -837,8 +854,37 @@ Section "Uninstall" RMDir "$INSTDIR" ; will delete only if empty SetShellVarContext current - Delete "$DESKTOP\Play StepMania CVS.lnk" - Delete "$DESKTOP\${PRODUCT_DISPLAY}.lnk" + + ; kill shortcuts + !ifdef MAKE_DESKTOP_SHORTCUT + Delete "$DESKTOP\$(TEXT_IO_RUN).lnk" + !endif + !ifdef MAKE_DESKTOP_SHORTCUT + Delete "$DESKTOP\$(TEXT_IO_RUN).lnk" + !endif + + Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_RUN).lnk" + Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_RUN_WITHOUT_SSE2).lnk" + + !ifdef MAKE_OPEN_PROGRAM_FOLDER_SHORTCUT + Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_OPEN_PROGRAM_FOLDER).lnk" + !endif + !ifdef MAKE_OPEN_SETTINGS_FOLDER_SHORTCUT + Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_OPEN_SETTINGS_FOLDER).lnk" + !endif + + ;Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_VIEW_STATISTICS).lnk" + ;Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_TOOLS).lnk" + Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_MANUAL).lnk" + Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_UNINSTALL).lnk" + Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_WEB_SITE).lnk" + Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_TEXTURE_FONT_GENERATOR).lnk" + !ifdef MAKE_UPDATES_SHORTCUT + Delete "$SMPROGRAMS\${PRODUCT_ID}\$(TEXT_IO_CHECK_FOR_UPDATES).lnk" + !endif + Delete "$INSTDIR\${PRODUCT_ID}.lnk" + Delete "$INSTDIR\${PRODUCT_ID} (non-SSE2).lnk" + ; I'm being paranoid here: Delete "$SMPROGRAMS\${PRODUCT_ID}\*.*" RMDir "$SMPROGRAMS\${PRODUCT_ID}" diff --git a/src/Actor.cpp b/src/Actor.cpp index 3191d98d56..d7e8f3f4b2 100644 --- a/src/Actor.cpp +++ b/src/Actor.cpp @@ -105,9 +105,9 @@ void Actor::InitState() #endif m_fSecsIntoEffect = 0; m_fEffectDelta = 0; - m_fEffectRampUp = 0.5; + m_fEffectRampUp = 0.5f; m_fEffectHoldAtHalf = 0; - m_fEffectRampDown = 0.5; + m_fEffectRampDown = 0.5f; m_fEffectHoldAtZero = 0; m_fEffectOffset = 0; m_EffectClock = CLOCK_TIMER; @@ -118,7 +118,7 @@ void Actor::InitState() m_bVisible = true; m_fShadowLengthX = 0; m_fShadowLengthY = 0; - m_ShadowColor = RageColor(0,0,0,0.5); + m_ShadowColor = RageColor(0,0,0,0.5f); m_bIsAnimating = true; m_fHibernateSecondsLeft = 0; m_iDrawOrder = 0; diff --git a/src/AdjustSync.cpp b/src/AdjustSync.cpp index bee582b4bf..7e7ec96247 100644 --- a/src/AdjustSync.cpp +++ b/src/AdjustSync.cpp @@ -256,7 +256,7 @@ void AdjustSync::AutosyncTempo() // keep only a fraction of the data, such as the 80% with the lowest // error. However, throwing away the ones with high error should // be enough in most cases. - float fFilteredError = 0.0; + float fFilteredError = 0; s_iStepsFiltered = s_vAutosyncTempoData.size(); FilterHighErrorPoints( s_vAutosyncTempoData, fSlope, fIntercept, ERROR_TOO_HIGH ); s_iStepsFiltered -= s_vAutosyncTempoData.size(); @@ -266,14 +266,23 @@ void AdjustSync::AutosyncTempo() GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += fIntercept; const float fScaleBPM = 1.0f/(1.0f - fSlope); - FOREACH( BPMSegment, GAMESTATE->m_pCurSong->m_SongTiming.m_BPMSegments, i ) - i->SetBPM( i->GetBPM() * fScaleBPM ); + TimingData &timing = GAMESTATE->m_pCurSong->m_SongTiming; + vector &bpms = timing.allTimingSegments[SEGMENT_BPM]; + for (unsigned i = 0; i < bpms.size(); i++) + { + BPMSegment *b = static_cast(bpms[i]); + b->SetBPM(b->GetBPM() * fScaleBPM); + } /* We assume that the stops were measured as a number of beats. * Therefore, if we change the bpms, we need to make a similar * change to the stops. */ - FOREACH( StopSegment, GAMESTATE->m_pCurSong->m_SongTiming.m_StopSegments, i ) - i->SetPause(i->GetPause() * (1.0f - fSlope)); + vector &stops = timing.allTimingSegments[SEGMENT_STOP_DELAY]; + for (unsigned i = 0; i < stops.size(); i++) + { + StopSegment *s = static_cast(stops[i]); + s->SetPause(s->GetPause() * (1.0f - fSlope)); + } SCREENMAN->SystemMessage( AUTOSYNC_CORRECTION_APPLIED.GetValue() ); } @@ -343,10 +352,14 @@ void AdjustSync::GetSyncChangeTextSong( vector &vsAddTo ) } } - for( unsigned i=0; i< testing.m_BPMSegments.size(); i++ ) + vector &bpmTest = testing.allTimingSegments[SEGMENT_BPM]; + vector &bpmOrig = original.allTimingSegments[SEGMENT_BPM]; + for( unsigned i=0; i< bpmTest.size(); i++ ) { - float fOld = Quantize( original.m_BPMSegments[i].GetBPM(), 0.001f ); - float fNew = Quantize( testing.m_BPMSegments[i].GetBPM(), 0.001f ); + BPMSegment *bT = static_cast(bpmTest[i]); + BPMSegment *bO = static_cast(bpmOrig[i]); + float fOld = Quantize( bO->GetBPM(), 0.001f ); + float fNew = Quantize( bT->GetBPM(), 0.001f ); float fDelta = fNew - fOld; if( fabsf(fDelta) > 0.0001f ) @@ -364,10 +377,14 @@ void AdjustSync::GetSyncChangeTextSong( vector &vsAddTo ) } } - for( unsigned i=0; i< testing.m_StopSegments.size(); i++ ) + vector &stopTest = testing.allTimingSegments[SEGMENT_STOP_DELAY]; + vector &stopOrig = original.allTimingSegments[SEGMENT_STOP_DELAY]; + for( unsigned i=0; i< stopTest.size(); i++ ) { - float fOld = Quantize( original.m_StopSegments[i].GetPause(), 0.001f ); - float fNew = Quantize( testing.m_StopSegments[i].GetPause(), 0.001f ); + StopSegment *sT = static_cast(stopTest[i]); + StopSegment *sO = static_cast(stopOrig[i]); + float fOld = Quantize( sO->GetPause(), 0.001f ); + float fNew = Quantize( sT->GetPause(), 0.001f ); float fDelta = fNew - fOld; if( fabsf(fDelta) > 0.0001f ) diff --git a/src/ArrowEffects.cpp b/src/ArrowEffects.cpp index fb8da38fb5..a01f30d11d 100644 --- a/src/ArrowEffects.cpp +++ b/src/ArrowEffects.cpp @@ -56,10 +56,12 @@ static ThemeMetric DRUNK_OFFSET_FREQUENCY( "ArrowEffects", "DrunkOffsetFr static ThemeMetric DRUNK_ARROW_MAGNITUDE( "ArrowEffects", "DrunkArrowMagnitude" ); static ThemeMetric BEAT_OFFSET_HEIGHT( "ArrowEffects", "BeatOffsetHeight" ); static ThemeMetric BEAT_PI_HEIGHT( "ArrowEffects", "BeatPIHeight" ); -static ThemeMetric MINI_PERCENT_BASE( "ArrowEffects", "MiniPercentBase" ); -static ThemeMetric MINI_PERCENT_GATE( "ArrowEffects", "MiniPercentGate" ); +static ThemeMetric TINY_PERCENT_BASE( "ArrowEffects", "TinyPercentBase" ); +static ThemeMetric TINY_PERCENT_GATE( "ArrowEffects", "TinyPercentGate" ); static ThemeMetric DIZZY_HOLD_HEADS( "ArrowEffects", "DizzyHoldHeads" ); +float ArrowGetPercentVisible( const PlayerState* pPlayerState, float fYPosWithoutReverse ); + static float GetNoteFieldHeight( const PlayerState* pPlayerState ) { return SCREEN_HEIGHT + fabsf(pPlayerState->m_PlayerOptions.GetCurrent().m_fPerspectiveTilt)*200; @@ -236,7 +238,10 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float if( bShowEffects ) fBeatsUntilStep = pCurSteps->m_Timing.GetDisplayedBeat(fNoteBeat) - pCurSteps->m_Timing.GetDisplayedBeat(fSongBeat); float fYOffsetBeatSpacing = fBeatsUntilStep; - float fSpeedMultiplier = bShowEffects ? pCurSteps->m_Timing.GetDisplayedSpeedPercent( position.m_fSongBeatVisible, position.m_fMusicSecondsVisible ) : 1.0; + float fSpeedMultiplier = bShowEffects ? + pCurSteps->m_Timing.GetDisplayedSpeedPercent( + position.m_fSongBeatVisible, + position.m_fMusicSecondsVisible ) : 1.0f; fYOffset += fSpeedMultiplier * fYOffsetBeatSpacing * (1-pPlayerState->m_PlayerOptions.GetCurrent().m_fTimeSpacing); } @@ -340,8 +345,8 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float static void ArrowGetReverseShiftAndScale( const PlayerState* pPlayerState, int iCol, float fYReverseOffsetPixels, float &fShiftOut, float &fScaleOut ) { // XXX: Hack: we need to scale the reverse shift by the zoom. - float fTinyPercent = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_TINY]; - float fZoom = 1 - fTinyPercent*0.5f; + float fMiniPercent = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_MINI]; + float fZoom = 1 - fMiniPercent*0.5f; // don't divide by 0 if( fabsf(fZoom) < 0.01 ) @@ -484,12 +489,12 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float fPixelOffsetFromCenter += pCols[iColNum].fXOffset; - if( fEffects[PlayerOptions::EFFECT_MINI] != 0 ) + if( fEffects[PlayerOptions::EFFECT_TINY] != 0 ) { - // Allow Mini to pull tracks together, but not to push them apart. - float fMiniPercent = fEffects[PlayerOptions::EFFECT_MINI]; - fMiniPercent = min( powf(MINI_PERCENT_BASE, fMiniPercent), (float)MINI_PERCENT_GATE ); - fPixelOffsetFromCenter *= fMiniPercent; + // Allow Tiny to pull tracks together, but not to push them apart. + float fTinyPercent = fEffects[PlayerOptions::EFFECT_TINY]; + fTinyPercent = min( powf(TINY_PERCENT_BASE, fTinyPercent), (float)TINY_PERCENT_GATE ); + fPixelOffsetFromCenter *= fTinyPercent; } return fPixelOffsetFromCenter; @@ -560,7 +565,7 @@ static float GetCenterLine( const PlayerState* pPlayerState ) { /* Another mini hack: if EFFECT_MINI is on, then our center line is at * eg. 320, not 160. */ - const float fMiniPercent = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_TINY]; + const float fMiniPercent = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_MINI]; const float fZoom = 1 - fMiniPercent*0.5f; return CENTER_LINE_Y / fZoom; } @@ -736,11 +741,11 @@ float ArrowEffects::GetZoom( const PlayerState* pPlayerState ) (GAMESTATE->GetNumSidesJoined()==2 || GAMESTATE->AnyPlayersAreCpu()) ) fZoom *= 0.6f; - float fMiniPercent = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_MINI]; - if( fMiniPercent != 0 ) + float fTinyPercent = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_TINY]; + if( fTinyPercent != 0 ) { - fMiniPercent = powf( 0.5f, fMiniPercent ); - fZoom *= fMiniPercent; + fTinyPercent = powf( 0.5f, fTinyPercent ); + fZoom *= fTinyPercent; } return fZoom; } diff --git a/src/Attack.cpp b/src/Attack.cpp index 1bf2c8623b..25a19415c9 100644 --- a/src/Attack.cpp +++ b/src/Attack.cpp @@ -91,6 +91,27 @@ bool AttackArray::ContainsTransformOrTurn() const return false; } +vector AttackArray::ToVectorString() const +{ + vector ret; + FOREACH_CONST( Attack, *this, a ) + { + ret.push_back(ssprintf("TIME=%f:LEN=%f:MODS=%s", + a->fStartSecond, + a->fSecsRemaining, + a->sModifiers.c_str())); + } + return ret; +} + +void AttackArray::UpdateStartTimes(float delta) +{ + FOREACH(Attack, *this, a) + { + a->fStartSecond += delta; + } +} + /* * (c) 2003-2004 Chris Danford * All rights reserved. diff --git a/src/Attack.h b/src/Attack.h index 7eadbe4937..fe61a48723 100644 --- a/src/Attack.h +++ b/src/Attack.h @@ -71,6 +71,16 @@ struct AttackArray : public vector * @brief Determine if the list of attacks contains a transform or turn mod. * @return true if it does, or false otherwise. */ bool ContainsTransformOrTurn() const; + + /** + * @brief Return a string representation used for simfiles. + * @return the string representation. */ + vector ToVectorString() const; + + /** + * @brief Adjust the starting time of all attacks. + * @param delta the amount to change. */ + void UpdateStartTimes(float delta); }; #endif diff --git a/src/AttackDisplay.h b/src/AttackDisplay.h index 1a411ea55a..5e4dccf3d3 100644 --- a/src/AttackDisplay.h +++ b/src/AttackDisplay.h @@ -6,6 +6,8 @@ #include "GameConstantsAndTypes.h" // for TapNoteScore #include "RageTexturePreloader.h" +RString GetAttackPieceName( const RString &sAttack ); + class PlayerState; /** @brief A graphical display for attacks. */ class AttackDisplay : public ActorFrame diff --git a/src/AutoKeysounds.cpp b/src/AutoKeysounds.cpp index 79ec773973..b536a3aa95 100644 --- a/src/AutoKeysounds.cpp +++ b/src/AutoKeysounds.cpp @@ -49,7 +49,7 @@ void AutoKeysounds::LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain ) * Add all current autoplay sounds in both players to the chain. If a sound is * common to both players, don't pan it; otherwise pan it to that player's side. */ - int iNumTracks = m_ndAutoKeysoundsOnly[GAMESTATE->m_MasterPlayerNumber].GetNumTracks(); + int iNumTracks = m_ndAutoKeysoundsOnly[GAMESTATE->GetMasterPlayerNumber()].GetNumTracks(); for( int t = 0; t < iNumTracks; t++ ) { int iRow = -1; @@ -63,6 +63,10 @@ void AutoKeysounds::LoadAutoplaySoundsInto( RageSoundReader_Chain *pChain ) if( t >= m_ndAutoKeysoundsOnly[pn].GetNumTracks() ) continue; int iNextRowForPlayer = iRow; + /* XXX: If a BMS file only has one tap note per track, + * this will prevent any keysounds from loading. + * This leads to failure later on. + * We need a better way to prevent this. */ if( m_ndAutoKeysoundsOnly[pn].GetNextTapNoteRowForTrack( t, iNextRowForPlayer ) ) iNextRow = min( iNextRow, iNextRowForPlayer ); } @@ -274,7 +278,7 @@ void AutoKeysounds::FinishLoading() delete pChain; } } - ASSERT( m_pSharedSound ); + ASSERT_M( m_pSharedSound, ssprintf("No keysounds were loaded for the song %s!", pSong->m_sMainTitle.c_str() )); m_pSharedSound = new RageSoundReader_PitchChange( m_pSharedSound ); m_pSharedSound = new RageSoundReader_PostBuffering( m_pSharedSound ); @@ -297,7 +301,7 @@ void AutoKeysounds::FinishLoading() apSounds.push_back( m_pPlayerSounds[1] ); } - if( GAMESTATE->GetNumPlayersEnabled() == 1 && GAMESTATE->m_MasterPlayerNumber == PLAYER_2 ) + if( GAMESTATE->GetNumPlayersEnabled() == 1 && GAMESTATE->GetMasterPlayerNumber() == PLAYER_2 ) swap( m_pPlayerSounds[PLAYER_1], m_pPlayerSounds[PLAYER_2] ); if( apSounds.size() > 1 ) diff --git a/src/Background.cpp b/src/Background.cpp index 2761fd3b18..c987102faa 100644 --- a/src/Background.cpp +++ b/src/Background.cpp @@ -27,7 +27,6 @@ static ThemeMetric LEFT_EDGE ("Background","LeftEdge"); static ThemeMetric TOP_EDGE ("Background","TopEdge"); static ThemeMetric RIGHT_EDGE ("Background","RightEdge"); static ThemeMetric BOTTOM_EDGE ("Background","BottomEdge"); -#define RECT_BACKGROUND RectF (LEFT_EDGE,TOP_EDGE,RIGHT_EDGE,BOTTOM_EDGE) static ThemeMetric CLAMP_OUTPUT_PERCENT ("Background","ClampOutputPercent"); static ThemeMetric SHOW_DANCING_CHARACTERS ("Background","ShowDancingCharacters"); static ThemeMetric USE_STATIC_BG ("Background","UseStaticBackground"); @@ -422,35 +421,41 @@ void BackgroundImpl::LoadFromRandom( float fFirstBeat, float fEndBeat, const Bac const TimingData &timing = m_pSong->m_SongTiming; // change BG every time signature change or 4 measures - FOREACH_CONST( TimeSignatureSegment, timing.m_vTimeSignatureSegments, iter ) + const vector &tSigs = timing.allTimingSegments[SEGMENT_TIME_SIG]; + + for (unsigned i = 0; i < tSigs.size(); i++) { - vector::const_iterator next = iter; - next++; - int iSegmentEndRow = (next == timing.m_vTimeSignatureSegments.end()) ? iEndRow : next->GetRow(); + TimeSignatureSegment *ts = static_cast(tSigs[i]); + int iSegmentEndRow = (i + 1 == tSigs.size()) ? iEndRow : tSigs[i+1]->GetRow(); - for( int i=max(iter->GetRow(),iStartRow); iGetNoteRowsPerMeasure() ) + + for(int j=max(ts->GetRow(),iStartRow); + jGetNoteRowsPerMeasure()) { // Don't fade. It causes frame rate dip, especially on slower machines. - BackgroundDef bd = m_Layer[0].CreateRandomBGA( m_pSong, change.m_def.m_sEffect, m_RandomBGAnimations, this ); + BackgroundDef bd = m_Layer[0].CreateRandomBGA(m_pSong, + change.m_def.m_sEffect, + m_RandomBGAnimations, this); if( !bd.IsEmpty() ) { BackgroundChange c = change; c.m_def = bd; - c.m_fStartBeat = NoteRowToBeat(i); + c.m_fStartBeat = NoteRowToBeat(j); m_Layer[0].m_aBGChanges.push_back( c ); } } } // change BG every BPM change that is at the beginning of a measure - for( unsigned i=0; i &bpms = timing.allTimingSegments[SEGMENT_BPM]; + for( unsigned i=0; iGetRow()) % iter->GetNoteRowsPerMeasure() == 0 ) + TimeSignatureSegment *ts = static_cast(tSigs[j]); + if ((bpms[i]->GetRow() - ts->GetRow()) % ts->GetNoteRowsPerMeasure() == 0) { bAtBeginningOfMeasure = true; break; @@ -461,7 +466,7 @@ void BackgroundImpl::LoadFromRandom( float fFirstBeat, float fEndBeat, const Bac continue; // skip // start so that we don't create a BGChange right on top of fEndBeat - bool bInRange = bpmseg.GetRow() >= iStartRow && bpmseg.GetRow() < iEndRow; + bool bInRange = bpms[i]->GetRow() >= iStartRow && bpms[i]->GetRow() < iEndRow; if( !bInRange ) continue; // skip @@ -471,7 +476,7 @@ void BackgroundImpl::LoadFromRandom( float fFirstBeat, float fEndBeat, const Bac BackgroundChange c = change; c.m_def.m_sFile1 = bd.m_sFile1; c.m_def.m_sFile2 = bd.m_sFile2; - c.m_fStartBeat = bpmseg.GetBeat(); + c.m_fStartBeat = bpms[i]->GetBeat(); m_Layer[0].m_aBGChanges.push_back( c ); } } @@ -578,13 +583,15 @@ void BackgroundImpl::LoadFromSong( const Song* pSong ) else // pSong doesn't have an animation plan { Layer &layer = m_Layer[0]; + float firstBeat = pSong->GetFirstBeat(); + float lastBeat = pSong->GetLastBeat(); - LoadFromRandom( pSong->m_fFirstBeat, pSong->m_fLastBeat, BackgroundChange() ); + LoadFromRandom( firstBeat, lastBeat, BackgroundChange() ); // end showing the static song background BackgroundChange change; change.m_def = m_StaticBackgroundDef; - change.m_fStartBeat = pSong->m_fLastBeat; + change.m_fStartBeat = lastBeat; layer.m_aBGChanges.push_back( change ); } @@ -643,7 +650,7 @@ void BackgroundImpl::LoadFromSong( const Song* pSong ) continue; float fStartBeat = change.m_fStartBeat; - float fEndBeat = pSong->m_fLastBeat; + float fEndBeat = pSong->GetLastBeat(); if( i+1 < mainlayer.m_aBGChanges.size() ) fEndBeat = mainlayer.m_aBGChanges[i+1].m_fStartBeat; diff --git a/src/BackgroundUtil.cpp b/src/BackgroundUtil.cpp index 6644d1593d..d101be23e1 100644 --- a/src/BackgroundUtil.cpp +++ b/src/BackgroundUtil.cpp @@ -68,6 +68,25 @@ RString BackgroundChange::GetTextDescription() const return s; } +RString BackgroundChange::ToString() const +{ + /* TODO: Technically we need to double-escape the filename + * (because it might contain '=') and then unescape the value + * returned by the MsdFile. */ + return ssprintf("%.3f=%s=%.3f=%d=%d=%d=%s=%s=%s=%s=%s", + this->m_fStartBeat, + SmEscape(this->m_def.m_sFile1).c_str(), + this->m_fRate, + this->m_sTransition == SBT_CrossFade, // backward compat + this->m_def.m_sEffect == SBE_StretchRewind, // backward compat + this->m_def.m_sEffect != SBE_StretchNoLoop, // backward compat + this->m_def.m_sEffect.c_str(), + this->m_def.m_sFile2.c_str(), + this->m_sTransition.c_str(), + SmEscape(RageColor::NormalizeColorString(this->m_def.m_sColor1)).c_str(), + SmEscape(RageColor::NormalizeColorString(this->m_def.m_sColor2)).c_str()); +} + const RString BACKGROUND_EFFECTS_DIR = "BackgroundEffects/"; const RString BACKGROUND_TRANSITIONS_DIR = "BackgroundTransitions/"; diff --git a/src/BackgroundUtil.h b/src/BackgroundUtil.h index 80d36b8a92..c4907b590c 100644 --- a/src/BackgroundUtil.h +++ b/src/BackgroundUtil.h @@ -64,6 +64,11 @@ struct BackgroundChange RString m_sTransition; RString GetTextDescription() const; + + /** + * @brief Get the string representation of the change. + * @return the string representation. */ + RString ToString() const; }; /** @brief Shared background-related routines. */ namespace BackgroundUtil diff --git a/src/BeginnerHelper.cpp b/src/BeginnerHelper.cpp index 9bc73247ba..e6361729cf 100644 --- a/src/BeginnerHelper.cpp +++ b/src/BeginnerHelper.cpp @@ -242,7 +242,7 @@ void BeginnerHelper::DrawPrimitives() DISPLAY->SetLighting( true ); DISPLAY->SetLightDirectional( 0, - RageColor(0.5,0.5,0.5,1), + RageColor(0.5f,0.5f,0.5f,1), RageColor(1,1,1,1), RageColor(0,0,0,1), RageVector3(0, 0, 1) ); @@ -271,7 +271,7 @@ void BeginnerHelper::DrawPrimitives() DISPLAY->SetLighting( true ); DISPLAY->SetLightDirectional( 0, - RageColor(0.5,0.5,0.5,1), + RageColor(0.5f,0.5f,0.5f,1), RageColor(1,1,1,1), RageColor(0,0,0,1), RageVector3(0, 0, 1) ); diff --git a/src/Character.cpp b/src/Character.cpp index 209d3c7fa3..bb7d0e0797 100644 --- a/src/Character.cpp +++ b/src/Character.cpp @@ -5,6 +5,8 @@ #include "RageTextureID.h" #include "ActorUtil.h" +RString GetRandomFileInDir( RString sDir ); + Character::Character(): m_sCharDir(""), m_sCharacterID(""), m_sDisplayName(""), m_sCardPath(""), m_sIconPath(""), m_bUsableInRave(false), m_iPreloadRefcount(0) {} diff --git a/src/CharacterManager.cpp b/src/CharacterManager.cpp index 10cf6a26d6..8b70d9139f 100644 --- a/src/CharacterManager.cpp +++ b/src/CharacterManager.cpp @@ -89,7 +89,7 @@ Character* CharacterManager::GetDefaultCharacter() } /* We always have the default character. */ - ASSERT(0); + FAIL_M("There must be a default character available!"); return NULL; } @@ -152,6 +152,13 @@ public: LuaHelpers::CreateTableFromArray(vChars, L); return 1; } + static int GetCharacterCount(T* p, lua_State *L) + { + vector chars; + p->GetCharacters(chars); + lua_pushnumber(L, chars.size()); + return 1; + } LunaCharacterManager() { @@ -159,6 +166,7 @@ public: // sm-ssc adds: ADD_METHOD( GetRandomCharacter ); ADD_METHOD( GetAllCharacters ); + ADD_METHOD( GetCharacterCount ); } }; diff --git a/src/CharacterManager.h b/src/CharacterManager.h index bd49c20c5e..4a687ee9d3 100644 --- a/src/CharacterManager.h +++ b/src/CharacterManager.h @@ -1,19 +1,24 @@ -/* CharacterManager - Manage characters. */ - #ifndef CHARACTER_MANAGER_H #define CHARACTER_MANAGER_H class Character; struct lua_State; +/** @brief Manage all of the Characters. */ class CharacterManager { public: + /** @brief Set up the character manager. */ CharacterManager(); + /** @brief Destroy the character manager. */ ~CharacterManager(); void GetCharacters( vector &vpCharactersOut ); + /** @brief Get one installed character at random. + * @return The random character. */ Character* GetRandomCharacter(); + /** @brief Get the character assigned as the default. + * @return The default character. */ Character* GetDefaultCharacter(); Character* GetCharacterFromID( RString sCharacterID ); diff --git a/src/CommandLineActions.cpp b/src/CommandLineActions.cpp index ef5f26b10c..3a45380b87 100644 --- a/src/CommandLineActions.cpp +++ b/src/CommandLineActions.cpp @@ -108,7 +108,7 @@ static void Version() #endif // WIN32 } -void CommandLineActions::Handle(LoadingWindow* pLW) +void CommandLineActions::Handle() { CommandLineArgs args; for(int i=0; im_MasterPlayerNumber == PlayerNumber_Invalid ) + if( GAMESTATE->GetMasterPlayerNumber() == PlayerNumber_Invalid ) return; - const Trail *pMasterTrail = GAMESTATE->m_pCurTrail[GAMESTATE->m_MasterPlayerNumber]; + const Trail *pMasterTrail = GAMESTATE->m_pCurTrail[GAMESTATE->GetMasterPlayerNumber()]; if( pMasterTrail == NULL ) return; unsigned uNumEntriesToShow = pMasterTrail->m_vEntries.size(); diff --git a/src/CourseLoaderCRS.cpp b/src/CourseLoaderCRS.cpp index 77a055eb56..d4ae2a026e 100644 --- a/src/CourseLoaderCRS.cpp +++ b/src/CourseLoaderCRS.cpp @@ -163,18 +163,39 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou // infer entry::Type from the first param // todo: make sure these aren't generating bogus entries due // to a lack of songs. -aj + int iNumSongs = SONGMAN->GetNumSongs(); LOG->Trace("[CourseLoaderCRS] sParams[1] = %s",sParams[1].c_str()); // most played if( sParams[1].Left(strlen("BEST")) == "BEST" ) { - new_entry.iChooseIndex = StringToInt( sParams[1].Right(sParams[1].size()-strlen("BEST")) ) - 1; + int iChooseIndex = StringToInt( sParams[1].Right(sParams[1].size()-strlen("BEST")) ) - 1; + if( iChooseIndex > iNumSongs ) + { + // looking up a song that doesn't exist. + LOG->UserLog( "Course file", sPath, "is trying to load BEST%i with only %i songs installed. " + "This entry will be ignored.", iChooseIndex, iNumSongs); + out.m_bIncomplete = true; + continue; // skip this #SONG + } + + new_entry.iChooseIndex = iChooseIndex; CLAMP( new_entry.iChooseIndex, 0, 500 ); new_entry.songSort = SongSort_MostPlays; } // least played else if( sParams[1].Left(strlen("WORST")) == "WORST" ) { - new_entry.iChooseIndex = StringToInt( sParams[1].Right(sParams[1].size()-strlen("WORST")) ) - 1; + int iChooseIndex = StringToInt( sParams[1].Right(sParams[1].size()-strlen("BEST")) ) - 1; + if( iChooseIndex > iNumSongs ) + { + // looking up a song that doesn't exist. + LOG->UserLog( "Course file", sPath, "is trying to load WORST%i with only %i songs installed. " + "This entry will be ignored.", iChooseIndex, iNumSongs); + out.m_bIncomplete = true; + continue; // skip this #SONG + } + + new_entry.iChooseIndex = iChooseIndex; CLAMP( new_entry.iChooseIndex, 0, 500 ); new_entry.songSort = SongSort_FewestPlays; } diff --git a/src/CourseUtil.h b/src/CourseUtil.h index e338c9c3e7..6be86abe77 100644 --- a/src/CourseUtil.h +++ b/src/CourseUtil.h @@ -11,6 +11,10 @@ class XNode; class CourseEntry; class Song; +bool CompareCoursePointersBySortValueAscending( const Course *pSong1, const Course *pSong2 ); +bool CompareCoursePointersBySortValueDescending( const Course *pSong1, const Course *pSong2 ); +bool CompareCoursePointersByTitle( const Course *pCourse1, const Course *pCourse2 ); + /** @brief Utility functions that deal with Courses. */ namespace CourseUtil { diff --git a/src/DancingCharacters.cpp b/src/DancingCharacters.cpp index 8b5be828c3..403277580c 100644 --- a/src/DancingCharacters.cpp +++ b/src/DancingCharacters.cpp @@ -11,6 +11,8 @@ #include "PrefsManager.h" #include "Model.h" +int Neg1OrPos1(); + #define DC_X( choice ) THEME->GetMetricF("DancingCharacters",ssprintf("2DCharacterXP%d",choice+1)) #define DC_Y( choice ) THEME->GetMetricF("DancingCharacters",ssprintf("2DCharacterYP%d",choice+1)) @@ -164,7 +166,7 @@ void DancingCharacters::LoadNextSong() m_fThisCameraEndBeat = 0; ASSERT( GAMESTATE->m_pCurSong ); - m_fThisCameraEndBeat = GAMESTATE->m_pCurSong->m_fFirstBeat; + m_fThisCameraEndBeat = GAMESTATE->m_pCurSong->GetFirstBeat(); FOREACH_PlayerNumber( p ) if( GAMESTATE->IsPlayerEnabled(p) ) @@ -210,9 +212,9 @@ void DancingCharacters::Update( float fDelta ) bWasGameplayStarting = bGameplayStarting; static float fLastBeat = GAMESTATE->m_Position.m_fSongBeat; + float firstBeat = GAMESTATE->m_pCurSong->GetFirstBeat(); float fThisBeat = GAMESTATE->m_Position.m_fSongBeat; - if( fLastBeat < GAMESTATE->m_pCurSong->m_fFirstBeat && - fThisBeat >= GAMESTATE->m_pCurSong->m_fFirstBeat ) + if( fLastBeat < firstBeat && fThisBeat >= firstBeat ) { FOREACH_PlayerNumber( p ) m_pCharacter[p]->PlayAnimation( "dance" ); @@ -344,7 +346,7 @@ void DancingCharacters::DrawPrimitives() ambient, diffuse, specular, - RageVector3(-3, -7.5, +9) ); + RageVector3(-3, -7.5f, +9) ); if( PREFSMAN->m_bCelShadeModels ) { diff --git a/src/DateTime.h b/src/DateTime.h index 58f2cbe6ff..2d77da95bd 100644 --- a/src/DateTime.h +++ b/src/DateTime.h @@ -4,6 +4,8 @@ #include "EnumHelper.h" #include +int StringToDayInYear( RString sDayInYear ); + /** @brief The number of days we check for previously. */ const int NUM_LAST_DAYS = 7; /** @brief The number of weeks we check for previously. */ diff --git a/src/Difficulty.cpp b/src/Difficulty.cpp index e37c5a4745..c5e3390c98 100644 --- a/src/Difficulty.cpp +++ b/src/Difficulty.cpp @@ -67,49 +67,34 @@ RString GetCustomDifficulty( StepsType st, Difficulty dc, CourseType ct ) return DifficultyToString( dc ); } - const StepsTypeInfo &sti = GAMEMAN->GetStepsTypeInfo( st ); - - switch( sti.m_StepsTypeCategory ) + if( dc == Difficulty_Edit ) { - DEFAULT_FAIL(sti.m_StepsTypeCategory); - case StepsTypeCategory_Single: - case StepsTypeCategory_Double: - if( dc == Difficulty_Edit ) + return "Edit"; + } + // OPTIMIZATION OPPORTUNITY: cache these metrics and cache the splitting + vector vsNames; + split( NAMES, ",", vsNames ); + FOREACH( RString, vsNames, sName ) + { + ThemeMetric STEPS_TYPE("CustomDifficulty",(*sName)+"StepsType"); + if( STEPS_TYPE == StepsType_Invalid || st == STEPS_TYPE ) // match { - return "Edit"; - } - else - { - // OPTIMIZATION OPPORTUNITY: cache these metrics and cache the splitting - vector vsNames; - split( NAMES, ",", vsNames ); - FOREACH( RString, vsNames, sName ) + ThemeMetric DIFFICULTY("CustomDifficulty",(*sName)+"Difficulty"); + if( DIFFICULTY == Difficulty_Invalid || dc == DIFFICULTY ) // match { - ThemeMetric STEPS_TYPE("CustomDifficulty",(*sName)+"StepsType"); - if( STEPS_TYPE == StepsType_Invalid || st == STEPS_TYPE ) // match + ThemeMetric COURSE_TYPE("CustomDifficulty",(*sName)+"CourseType"); + if( COURSE_TYPE == CourseType_Invalid || ct == COURSE_TYPE ) // match { - ThemeMetric DIFFICULTY("CustomDifficulty",(*sName)+"Difficulty"); - if( DIFFICULTY == Difficulty_Invalid || dc == DIFFICULTY ) // match - { - ThemeMetric COURSE_TYPE("CustomDifficulty",(*sName)+"CourseType"); - if( COURSE_TYPE == CourseType_Invalid || ct == COURSE_TYPE ) // match - { - ThemeMetric STRING("CustomDifficulty",(*sName)+"String"); - return STRING.GetValue(); - } - } + ThemeMetric STRING("CustomDifficulty",(*sName)+"String"); + return STRING.GetValue(); } } - // no matching CustomDifficulty, so use a regular difficulty name - if( dc == Difficulty_Invalid ) - return RString(); - return DifficultyToString( dc ); } - case StepsTypeCategory_Couple: - return "Couple"; - case StepsTypeCategory_Routine: - return "Routine"; } + // no matching CustomDifficulty, so use a regular difficulty name + if( dc == Difficulty_Invalid ) + return RString(); + return DifficultyToString( dc ); } LuaFunction( GetCustomDifficulty, GetCustomDifficulty(Enum::Check(L,1), Enum::Check(L, 2), Enum::Check(L, 3, true)) ); diff --git a/src/DifficultyList.cpp b/src/DifficultyList.cpp index 2b79d6fe10..52695cd16f 100644 --- a/src/DifficultyList.cpp +++ b/src/DifficultyList.cpp @@ -11,18 +11,10 @@ #include "SongUtil.h" #include "XmlFile.h" -// MAX_METERS was previously set to NUM_Difficulty + MAX_EDITS_PER_SONG. -// This was all fine and well until AutoSetStyle was created. In certain -// gametypes (technomotion for example), if autogen is on, the number of -// available stepcharts exceeds MAX_METERS, resulting in a crash. -// My first thought to fix this was: -// (NUM_Difficulty (6) * NUM_StepsType (32)) + MAX_EDITS_PER_SONG (5*profileSlot (2)) = 202 -// However, 202 rows may be a bit overkill. -// Dance has 6 stepstypes counting 3panel, Pump and Techno have 5. -// (6 difficulties * 6 stepstypes) + MAX_EDITS_PER_SONG (which is 5 * profileSlots) = 46 rows -// 46 seems to be a good enough number for this. If we get a crash again, up the -// "magic" 6. -aj -#define MAX_METERS (NUM_Difficulty * 6) + MAX_EDITS_PER_SONG +/** @brief Specifies the max number of charts available for a song. + * + * This includes autogenned charts. */ +#define MAX_METERS (NUM_Difficulty * NUM_StepsType) + MAX_EDITS_PER_SONG REGISTER_ACTOR_CLASS( StepsDisplayList ); diff --git a/src/EditMenu.cpp b/src/EditMenu.cpp index 8b39585144..274ff975b8 100644 --- a/src/EditMenu.cpp +++ b/src/EditMenu.cpp @@ -60,7 +60,7 @@ void EditMenu::GetSongsToShowForGroup( const RString &sGroup, vector &vpS for( int i=vpSongsOut.size()-1; i>=0; i-- ) { const Song* pSong = vpSongsOut[i]; - if( !pSong->NormallyDisplayed() || pSong->IsTutorial() || SONGMAN->WasLoadedFromAdditionalSongs(pSong) ) + if( !pSong->NormallyDisplayed() || pSong->IsTutorial() ) vpSongsOut.erase( vpSongsOut.begin()+i ); } break; diff --git a/src/EditMenu.h b/src/EditMenu.h index 28c9730d81..dac6767899 100644 --- a/src/EditMenu.h +++ b/src/EditMenu.h @@ -10,6 +10,7 @@ #include "EnumHelper.h" #include "ThemeMetric.h" +/** @brief What type of row is needed for the EditMenu? */ enum EditMenuRow { ROW_GROUP, @@ -19,11 +20,19 @@ enum EditMenuRow ROW_SOURCE_STEPS_TYPE, ROW_SOURCE_STEPS, ROW_ACTION, - NUM_EditMenuRow + NUM_EditMenuRow /**< The number of EditMenuRows available. */ }; /** @brief Loop through each EditMenuRow. */ #define FOREACH_EditMenuRow( r ) FOREACH_ENUM( EditMenuRow, r ) +/** + * @brief Turn the EditMenuRow into a string. + * @param r the row. + * @return the string. */ const RString& EditMenuRowToString( EditMenuRow r ); +/** + * @brief Turn the EditMenuRow into a localized string. + * @param r the row. + * @return the localized string. */ const RString& EditMenuRowToLocalizedString( EditMenuRow r ); /** @brief The different actions one can take on a step. */ @@ -38,9 +47,18 @@ enum EditMenuAction }; /** @brief Loop through each EditMenuAction. */ #define FOREACH_EditMenuAction( ema ) FOREACH_ENUM( EditMenuAction, ema ) +/** + * @brief Turn the EditMenuAction into a string. + * @param ema the action. + * @return the string. */ const RString& EditMenuActionToString( EditMenuAction ema ); +/** + * @brief Turn the EditMenuAction into a localized string. + * @param ema the action. + * @return the localized string. */ const RString& EditMenuActionToLocalizedString( EditMenuAction ema ); +/** @brief How many arrows are used for the EditMenu? */ const int NUM_ARROWS = 2; /** @@ -50,39 +68,110 @@ const int NUM_ARROWS = 2; class EditMenu: public ActorFrame { public: + /** @brief Set up the EditMenu. */ EditMenu(); + /** @brief Destroy the EditMenu. */ ~EditMenu(); void Load( const RString &sType ); + /** @brief Determine if we can move up. + * @return true if we can, false otherwise. */ bool CanGoUp(); + /** @brief Determine if we can move down. + * @return true if we can, false otherwise. */ bool CanGoDown(); + /** @brief Determine if we can move left. + * @return true if we can, false otherwise. */ bool CanGoLeft(); + /** @brief Determine if we can move right. + * @return true if we can, false otherwise. */ bool CanGoRight(); + /** @brief Determine if the EditMenuRow is selectable. + * @param row the row in question. + * @return true if it can be selected, false otherwise. */ bool RowIsSelectable( EditMenuRow row ); + /** @brief Move up to the next selection. */ void Up(); + /** @brief Move down to the next selection. */ void Down(); + /** @brief Move left to the next selection. */ void Left(); + /** @brief Move right to the next selection. */ void Right(); void RefreshAll(); - RString GetSelectedGroup() const + /** @brief Retrieve the currently selected group. + * @return the current group. */ + RString GetSelectedGroup() const { if( !SHOW_GROUPS.GetValue() ) return GROUP_ALL; - ASSERT_M((int)m_iSelection[ROW_GROUP] < (int)m_sGroups.size(), - ssprintf("Group selection %d < Number of groups %d", m_iSelection[ROW_GROUP], (int)m_sGroups.size())); + int groups = static_cast(m_sGroups.size()); + ASSERT_M(m_iSelection[ROW_GROUP] < groups, + ssprintf("Group selection %d < Number of groups %d", + m_iSelection[ROW_GROUP], + groups)); return m_sGroups[m_iSelection[ROW_GROUP]]; } - Song* GetSelectedSong() const { ASSERT(m_iSelection[ROW_SONG] < (int)m_pSongs.size()); return m_pSongs[m_iSelection[ROW_SONG]]; } - StepsType GetSelectedStepsType() const { ASSERT(m_iSelection[ROW_STEPS_TYPE] < (int)m_StepsTypes.size()); return m_StepsTypes[m_iSelection[ROW_STEPS_TYPE]]; } - Steps* GetSelectedSteps() const { ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size()); return m_vpSteps[m_iSelection[ROW_STEPS]].pSteps; } - Difficulty GetSelectedDifficulty() const { ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size()); return m_vpSteps[m_iSelection[ROW_STEPS]].dc; } - StepsType GetSelectedSourceStepsType() const { ASSERT(m_iSelection[ROW_SOURCE_STEPS_TYPE] < (int)m_StepsTypes.size()); return m_StepsTypes[m_iSelection[ROW_SOURCE_STEPS_TYPE]]; } - Steps* GetSelectedSourceSteps() const { ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size()); return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].pSteps; } - Difficulty GetSelectedSourceDifficulty() const { ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size()); return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].dc; } - EditMenuAction GetSelectedAction() const { ASSERT(m_iSelection[ROW_ACTION] < (int)m_Actions.size()); return m_Actions[m_iSelection[ROW_ACTION]]; } - + /** @brief Retrieve the currently selected song. + * @return the current song. */ + Song* GetSelectedSong() const + { + ASSERT(m_iSelection[ROW_SONG] < (int)m_pSongs.size()); + return m_pSongs[m_iSelection[ROW_SONG]]; + } + /** @brief Retrieve the currently selected steps type. + * @return the current steps type. */ + StepsType GetSelectedStepsType() const + { + ASSERT(m_iSelection[ROW_STEPS_TYPE] < (int)m_StepsTypes.size()); + return m_StepsTypes[m_iSelection[ROW_STEPS_TYPE]]; + } + /** @brief Retrieve the currently selected steps. + * @return the current steps. */ + Steps* GetSelectedSteps() const + { + ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size()); + return m_vpSteps[m_iSelection[ROW_STEPS]].pSteps; + } + /** @brief Retrieve the currently selected difficulty. + * @return the current difficulty. */ + Difficulty GetSelectedDifficulty() const + { + ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size()); + return m_vpSteps[m_iSelection[ROW_STEPS]].dc; + } + /** @brief Retrieve the currently selected source steps type. + * @return the current source steps type. */ + StepsType GetSelectedSourceStepsType() const + { + ASSERT(m_iSelection[ROW_SOURCE_STEPS_TYPE] < (int)m_StepsTypes.size()); + return m_StepsTypes[m_iSelection[ROW_SOURCE_STEPS_TYPE]]; + } + /** @brief Retrieve the currently selected source steps. + * @return the current source steps. */ + Steps* GetSelectedSourceSteps() const + { + ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size()); + return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].pSteps; + } + /** @brief Retrieve the currently selected difficulty. + * @return the current difficulty. */ + Difficulty GetSelectedSourceDifficulty() const + { + ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size()); + return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].dc; + } + /** @brief Retrieve the currently selected action. + * @return the current action. */ + EditMenuAction GetSelectedAction() const + { + ASSERT(m_iSelection[ROW_ACTION] < (int)m_Actions.size()); + return m_Actions[m_iSelection[ROW_ACTION]]; + } + /** @brief Retrieve the currently selected row. + * @return the current row. */ EditMenuRow GetSelectedRow() const { return m_SelectedRow; } private: diff --git a/src/EnumHelper.h b/src/EnumHelper.h index 57e81d16c4..dc1049cc0c 100644 --- a/src/EnumHelper.h +++ b/src/EnumHelper.h @@ -15,7 +15,12 @@ extern "C" /** @brief A general foreach loop for enumerators. */ #define FOREACH_ENUM( e, var ) for( e var=(e)0; var( var, +1 ) ) -int CheckEnum( lua_State *L, LuaReference &table, int iPos, int iInvalid, const char *szType, bool bAllowInvalid ); +int CheckEnum(lua_State *L, + LuaReference &table, + int iPos, + int iInvalid, + const char *szType, + bool bAllowInvalid); template struct EnumTraits @@ -33,7 +38,12 @@ namespace Enum template static T Check( lua_State *L, int iPos, bool bAllowInvalid = false ) { - return (T) CheckEnum( L, EnumTraits::StringToEnum, iPos, EnumTraits::Invalid, EnumTraits::szName, bAllowInvalid ); + return (T) CheckEnum(L, + EnumTraits::StringToEnum, + iPos, + EnumTraits::Invalid, + EnumTraits::szName, + bAllowInvalid); } template static void Push( lua_State *L, T iVal ) @@ -57,37 +67,47 @@ namespace Enum const RString &EnumToString( int iVal, int iMax, const char **szNameArray, auto_ptr *pNameCache ); // XToString helper #define XToString(X) \ - COMPILE_ASSERT( NUM_##X == ARRAYLEN(X##Names) ); \ - const RString& X##ToString( X x ) \ - { \ - static auto_ptr as_##X##Name[NUM_##X+2]; \ - return EnumToString( x, NUM_##X, X##Names, as_##X##Name ); \ - } \ - namespace StringConversion { template<> RString ToString( const X &value ) { return X##ToString(value); } } +const RString& X##ToString(X x); \ +COMPILE_ASSERT( NUM_##X == ARRAYLEN(X##Names) ); \ +const RString& X##ToString( X x ) \ +{ \ + static auto_ptr as_##X##Name[NUM_##X+2]; \ + return EnumToString( x, NUM_##X, X##Names, as_##X##Name ); \ +} \ +namespace StringConversion { template<> RString ToString( const X &value ) { return X##ToString(value); } } #define XToLocalizedString(X) \ - const RString &X##ToLocalizedString( X x ) \ - { \ - static auto_ptr g_##X##Name[NUM_##X]; \ - if( g_##X##Name[0].get() == NULL ) { \ - for( unsigned i = 0; i < NUM_##X; ++i ) \ - { \ - auto_ptr ap( new LocalizedString(#X, X##ToString((X)i)) ); \ - g_##X##Name[i] = ap; \ - } \ +const RString &X##ToLocalizedString(X x); \ +const RString &X##ToLocalizedString( X x ) \ +{ \ + static auto_ptr g_##X##Name[NUM_##X]; \ + if( g_##X##Name[0].get() == NULL ) { \ + for( unsigned i = 0; i < NUM_##X; ++i ) \ + { \ + auto_ptr ap( new LocalizedString(#X, X##ToString((X)i)) ); \ + g_##X##Name[i] = ap; \ } \ - return g_##X##Name[x]->GetValue(); \ - } + } \ + return g_##X##Name[x]->GetValue(); \ +} #define StringToX(X) \ - X StringTo##X( const RString& s ) \ - { \ - for( unsigned i = 0; i < ARRAYLEN(X##Names); ++i ) \ - if( !s.CompareNoCase(X##Names[i]) ) \ - return (X)i; \ - return X##_Invalid; \ +X StringTo##X(const RString&); \ +X StringTo##X( const RString& s ) \ +{ \ + for( unsigned i = 0; i < ARRAYLEN(X##Names); ++i ) \ + if( !s.CompareNoCase(X##Names[i]) ) \ + return (X)i; \ + return X##_Invalid; \ +} \ +namespace StringConversion \ +{ \ + template<> bool FromString( const RString &sValue, X &out ) \ + { \ + out = StringTo##X(sValue); \ + return out != X##_Invalid; \ } \ - namespace StringConversion { template<> bool FromString( const RString &sValue, X &out ) { out = StringTo##X(sValue); return out != X##_Invalid; } } +} // currently unused #define LuaDeclareType(X) @@ -123,8 +143,21 @@ static void Lua##X(lua_State* L) \ REGISTER_WITH_LUA_FUNCTION( Lua##X ); \ template<> X EnumTraits::Invalid = X##_Invalid; \ template<> const char *EnumTraits::szName = #X; \ -namespace LuaHelpers { template<> bool FromStack( lua_State *L, X &Object, int iOffset ) { Object = Enum::Check( L, iOffset, true ); return Object != EnumTraits::Invalid; } } \ -namespace LuaHelpers { template<> void Push( lua_State *L, const X &Object ) { Enum::Push( L, Object ); } } +namespace LuaHelpers \ +{ \ + template<> bool FromStack( lua_State *L, X &Object, int iOffset ) \ + { \ + Object = Enum::Check( L, iOffset, true ); \ + return Object != EnumTraits::Invalid; \ + } \ +} \ +namespace LuaHelpers \ +{ \ + template<> void Push( lua_State *L, const X &Object ) \ + { \ + Enum::Push( L, Object ); \ + } \ +} #endif diff --git a/src/GameCommand.h b/src/GameCommand.h index 8cd135dde4..50f9ae5050 100644 --- a/src/GameCommand.h +++ b/src/GameCommand.h @@ -19,6 +19,9 @@ class Style; class Game; struct lua_State; +int GetNumCreditsPaid(); +int GetCreditsRequiredToPlayStyle( const Style *style ); + class GameCommand { public: diff --git a/src/GameConstantsAndTypes.cpp b/src/GameConstantsAndTypes.cpp index e1cbb161e4..3d557fdbb8 100644 --- a/src/GameConstantsAndTypes.cpp +++ b/src/GameConstantsAndTypes.cpp @@ -11,6 +11,7 @@ #include "PlayerNumber.h" #include +RString StepsTypeToString( StepsType st ); static vector GenerateRankingToFillInMarker() { @@ -359,12 +360,17 @@ float DisplayBpms::GetMin() const } float DisplayBpms::GetMax() const +{ + return this->GetMaxWithin(); +} + +float DisplayBpms::GetMaxWithin(float highest) const { float fMax = 0; FOREACH_CONST( float, vfBpms, f ) { if( *f != -1 ) - fMax = max( fMax, *f ); + fMax = clamp(max( fMax, *f ), 0, highest); } return fMax; } diff --git a/src/GameConstantsAndTypes.h b/src/GameConstantsAndTypes.h index 7242f4009d..1d86aa9b27 100644 --- a/src/GameConstantsAndTypes.h +++ b/src/GameConstantsAndTypes.h @@ -4,6 +4,7 @@ #define GAME_CONSTANTS_AND_TYPES_H #include "EnumHelper.h" +#include // need the max for default. // Note definitions /** @brief Define the mininum difficulty value allowed. */ @@ -513,6 +514,13 @@ struct DisplayBpms * @return the maximum BPM. */ float GetMax() const; + /** + * @brief Retrieve the maximum BPM of the set, + * but no higher than a certain value. + * @param highest the highest BPM to use. + * @return the maximum BPM. + */ + float GetMaxWithin(float highest = FLT_MAX) const; /** * @brief Determine if the BPM is really constant. * @return Whether the BPM is constant or not. diff --git a/src/GameManager.cpp b/src/GameManager.cpp index 2ff129892c..a9178b5433 100644 --- a/src/GameManager.cpp +++ b/src/GameManager.cpp @@ -251,7 +251,7 @@ static const Style g_Style_Dance_Double = static const Style g_Style_Dance_Couple = { // STYLE_DANCE_COUPLE true, // m_bUsedForGameplay - true, // m_bUsedForEdit + false, // m_bUsedForEdit false, // m_bUsedForDemonstration false, // m_bUsedForHowToPlay "couple", // m_szName @@ -324,6 +324,50 @@ static const Style g_Style_Dance_Solo = false, // m_bLockDifficulties }; +static const Style g_Style_Dance_Couple_Edit = +{ // STYLE_DANCE_COUPLE + false, // m_bUsedForGameplay + true, // m_bUsedForEdit + false, // m_bUsedForDemonstration + false, // m_bUsedForHowToPlay + "couple-edit", // m_szName + StepsType_dance_couple, // m_StepsType + StyleType_OnePlayerTwoSides, // m_StyleType + 8, // m_iColsPerPlayer + { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; + { // PLAYER_1 + { TRACK_1, -DANCE_COL_SPACING*4.f, NULL }, + { TRACK_2, -DANCE_COL_SPACING*3.f, NULL }, + { TRACK_3, -DANCE_COL_SPACING*2.f, NULL }, + { TRACK_4, -DANCE_COL_SPACING*1.f, NULL }, + { TRACK_5, +DANCE_COL_SPACING*1.f, NULL }, + { TRACK_6, +DANCE_COL_SPACING*2.f, NULL }, + { TRACK_7, +DANCE_COL_SPACING*3.f, NULL }, + { TRACK_8, +DANCE_COL_SPACING*4.f, NULL }, + }, + { // PLAYER_2 + { TRACK_1, -DANCE_COL_SPACING*4.f, NULL }, + { TRACK_2, -DANCE_COL_SPACING*3.f, NULL }, + { TRACK_3, -DANCE_COL_SPACING*2.f, NULL }, + { TRACK_4, -DANCE_COL_SPACING*1.f, NULL }, + { TRACK_5, +DANCE_COL_SPACING*1.f, NULL }, + { TRACK_6, +DANCE_COL_SPACING*2.f, NULL }, + { TRACK_7, +DANCE_COL_SPACING*3.f, NULL }, + { TRACK_8, +DANCE_COL_SPACING*4.f, NULL }, + }, + }, + { // m_iInputColumn[NUM_GameController][NUM_GameButton] + { 0, 3, 2, 1, Style::END_MAPPING }, + { 4, 7, 6, 5, Style::END_MAPPING }, + }, + { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER]; + 0,1,2,3,4,5,6,7 + }, + false, // m_bNeedsZoomOutWith2Players + false, // m_bCanUseBeginnerHelper + false, // m_bLockDifficulties +}; + static const Style g_Style_Dance_ThreePanel = { // STYLE_DANCE_THREEPANEL true, // m_bUsedForGameplay @@ -449,6 +493,7 @@ static const Style *g_apGame_Dance_Styles[] = &g_Style_Dance_Double, &g_Style_Dance_Couple, &g_Style_Dance_Solo, + &g_Style_Dance_Couple_Edit, &g_Style_Dance_Routine, &g_Style_Dance_ThreePanel, NULL @@ -725,7 +770,7 @@ static const Style g_Style_Pump_Couple_Edit = false, // m_bUsedForHowToPlay "couple-edit", // m_szName StepsType_pump_couple, // m_StepsType - StyleType_OnePlayerOneSide, // m_StyleType + StyleType_OnePlayerTwoSides, // m_StyleType 10, // m_iColsPerPlayer { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; { // PLAYER_1 @@ -741,19 +786,24 @@ static const Style g_Style_Pump_Couple_Edit = { TRACK_10, +PUMP_COL_SPACING*5.0f+4, NULL }, }, { // PLAYER_2 - { TRACK_1, -PUMP_COL_SPACING*2.0f, NULL }, - { TRACK_2, -PUMP_COL_SPACING*1.0f, NULL }, - { TRACK_3, +PUMP_COL_SPACING*0.0f, NULL }, - { TRACK_4, +PUMP_COL_SPACING*1.0f, NULL }, - { TRACK_5, +PUMP_COL_SPACING*2.0f, NULL }, + { TRACK_1, -PUMP_COL_SPACING*5.0f-4, NULL }, + { TRACK_2, -PUMP_COL_SPACING*4.0f-4, NULL }, + { TRACK_3, -PUMP_COL_SPACING*3.0f-4, NULL }, + { TRACK_4, -PUMP_COL_SPACING*2.0f-4, NULL }, + { TRACK_5, -PUMP_COL_SPACING*1.0f-4, NULL }, + { TRACK_6, +PUMP_COL_SPACING*1.0f+4, NULL }, + { TRACK_7, +PUMP_COL_SPACING*2.0f+4, NULL }, + { TRACK_8, +PUMP_COL_SPACING*3.0f+4, NULL }, + { TRACK_9, +PUMP_COL_SPACING*4.0f+4, NULL }, + { TRACK_10, +PUMP_COL_SPACING*5.0f+4, NULL }, }, }, { // m_iInputColumn[NUM_GameController][NUM_GameButton] - { 1, 3, 2, 0, 4, 6, 8, 7, 5, 9, Style::END_MAPPING }, - { 1, 3, 2, 0, 4, 6, 8, 7, 5, 9, Style::END_MAPPING }, + { 1, 3, 2, 0, 4, Style::END_MAPPING }, + { 6, 8, 7, 5, 9, Style::END_MAPPING }, }, { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER]; - 2,1,3,0,4 + 2,1,3,0,4, 2+5,1+5,3+5,0+5,4+5 }, false, // m_bNeedsZoomOutWith2Players false, // m_bCanUseBeginnerHelper diff --git a/src/GameSoundManager.cpp b/src/GameSoundManager.cpp index a9e71fce24..183b3ccf48 100644 --- a/src/GameSoundManager.cpp +++ b/src/GameSoundManager.cpp @@ -60,8 +60,8 @@ struct MusicPlaying RageSound *m_Music; MusicPlaying( RageSound *Music ) { - m_Timing.AddBPMSegment( BPMSegment(0,120) ); - m_NewTiming.AddBPMSegment( BPMSegment(0,120) ); + m_Timing.AddSegment( SEGMENT_BPM, new BPMSegment(0,120) ); + m_NewTiming.AddSegment( SEGMENT_BPM, new BPMSegment(0,120) ); m_bHasTiming = false; m_bTimingDelayed = false; m_bApplyMusicRate = false; @@ -142,8 +142,10 @@ static void StartMusic( MusicToPlay &ToPlay ) { LOG->Trace( "Found '%s'", ToPlay.m_sTimingFile.c_str() ); Song song; - if( GetExtension(ToPlay.m_sTimingFile) == ".ssc" && - SSCLoader::LoadFromSSCFile(ToPlay.m_sTimingFile, song) ) + SSCLoader loaderSSC; + SMLoader loaderSM; + if(GetExtension(ToPlay.m_sTimingFile) == ".ssc" && + loaderSSC.LoadFromSimfile(ToPlay.m_sTimingFile, song) ) { ToPlay.HasTiming = true; ToPlay.m_TimingData = song.m_SongTiming; @@ -152,8 +154,8 @@ static void StartMusic( MusicToPlay &ToPlay ) if( pStepsCabinetLights ) pStepsCabinetLights->GetNoteData( ToPlay.m_LightsData ); } - else if( GetExtension(ToPlay.m_sTimingFile) == ".sm" && - SMLoader::LoadFromSMFile(ToPlay.m_sTimingFile, song) ) + else if(GetExtension(ToPlay.m_sTimingFile) == ".sm" && + loaderSM.LoadFromSimfile(ToPlay.m_sTimingFile, song) ) { ToPlay.HasTiming = true; ToPlay.m_TimingData = song.m_SongTiming; diff --git a/src/GameSoundManager.h b/src/GameSoundManager.h index 6ce38ca39e..1187924a37 100644 --- a/src/GameSoundManager.h +++ b/src/GameSoundManager.h @@ -6,6 +6,9 @@ class TimingData; class RageSound; struct lua_State; + +int MusicThread_start( void *p ); + /** @brief High-level sound utilities. */ class GameSoundManager { diff --git a/src/GameState.cpp b/src/GameState.cpp index dbca4fc9a3..35d61decd0 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -106,6 +106,7 @@ static Preference g_Premium( "Premium", Premium_Off ); Preference GameState::m_bAutoJoin( "AutoJoin", false ); GameState::GameState() : + processedTiming( NULL ), m_pCurGame( Message_CurrentGameChanged ), m_pCurStyle( Message_CurrentStyleChanged ), m_PlayMode( Message_PlayModeChanged ), @@ -122,14 +123,14 @@ GameState::GameState() : m_pCurTrail( Message_CurrentTrailP1Changed ), m_bGameplayLeadIn( Message_GameplayLeadInChanged ), m_bDidModeChangeNoteSkin( false ), + m_bIsUsingStepTiming( true ), + m_bInStepEditor( false ), m_stEdit( Message_EditStepsTypeChanged ), m_cdEdit( Message_EditCourseDifficultyChanged ), m_pEditSourceSteps( Message_EditSourceStepsChanged ), m_stEditSource( Message_EditSourceStepsTypeChanged ), m_iEditCourseEntryIndex( Message_EditCourseEntryIndexChanged ), - m_sEditLocalProfileID( Message_EditLocalProfileIDChanged ), - m_bIsUsingStepTiming( true ), - m_bInStepEditor( false ) + m_sEditLocalProfileID( Message_EditLocalProfileIDChanged ) { g_pImpl = new GameStateImpl; @@ -188,6 +189,27 @@ GameState::~GameState() SAFE_DELETE( m_Environment ); SAFE_DELETE( g_pImpl ); + SAFE_DELETE( processedTiming ); +} + +PlayerNumber GameState::GetMasterPlayerNumber() const +{ + return this->masterPlayerNumber; +} + +void GameState::SetMasterPlayerNumber(const PlayerNumber p) +{ + this->masterPlayerNumber = p; +} + +TimingData * GameState::GetProcessedTimingData() const +{ + return this->processedTiming; +} + +void GameState::SetProcessedTimingData(TimingData * t) +{ + this->processedTiming = t; } void GameState::ApplyGameCommand( const RString &sCommand, PlayerNumber pn ) @@ -244,7 +266,7 @@ void GameState::ResetPlayer( PlayerNumber pn ) void GameState::Reset() { - m_MasterPlayerNumber = PLAYER_INVALID; // must initialize for UnjoinPlayer + this->SetMasterPlayerNumber(PLAYER_INVALID); // must initialize for UnjoinPlayer FOREACH_PlayerNumber( pn ) UnjoinPlayer( pn ); @@ -334,14 +356,14 @@ void GameState::JoinPlayer( PlayerNumber pn ) * give the new player the same number of stage tokens that the old player * has. */ if( GetCoinMode() == CoinMode_Pay && GetPremium() == Premium_2PlayersFor1Credit && GetNumSidesJoined() == 1 ) - m_iPlayerStageTokens[pn] = m_iPlayerStageTokens[m_MasterPlayerNumber]; + m_iPlayerStageTokens[pn] = m_iPlayerStageTokens[this->GetMasterPlayerNumber()]; else m_iPlayerStageTokens[pn] = PREFSMAN->m_iSongsPerPlay; m_bSideIsJoined[pn] = true; - if( m_MasterPlayerNumber == PLAYER_INVALID ) - m_MasterPlayerNumber = pn; + if( this->GetMasterPlayerNumber() == PLAYER_INVALID ) + this->SetMasterPlayerNumber(pn); // if first player to join, set start time if( GetNumSidesJoined() == 1 ) @@ -385,8 +407,8 @@ void GameState::UnjoinPlayer( PlayerNumber pn ) ResetPlayer( pn ); - if( m_MasterPlayerNumber == pn ) - m_MasterPlayerNumber = GetFirstHumanPlayer(); + if( this->GetMasterPlayerNumber() == pn ) + this->SetMasterPlayerNumber(GetFirstHumanPlayer()); /* Unjoin STATSMAN first, so steps used by this player are released * and can be released by PROFILEMAN. */ @@ -398,7 +420,7 @@ void GameState::UnjoinPlayer( PlayerNumber pn ) MESSAGEMAN->Broadcast( msg ); // If there are no players left, reset some non-player-specific stuff, too. - if( m_MasterPlayerNumber == PLAYER_INVALID ) + if( this->GetMasterPlayerNumber() == PLAYER_INVALID ) { SongOptions so; GetDefaultSongOptions( so ); @@ -635,8 +657,8 @@ int GameState::GetNumStagesForCurrentSongAndStepsOrCourse() const if( pStyle == NULL ) { const Steps *pSteps = NULL; - if( m_MasterPlayerNumber != PlayerNumber_Invalid ) - pSteps = m_pCurSteps[m_MasterPlayerNumber]; + if( this->GetMasterPlayerNumber() != PlayerNumber_Invalid ) + pSteps = m_pCurSteps[this->GetMasterPlayerNumber()]; // Don't call GetFirstCompatibleStyle if numSidesJoined == 0. // This happens because on SContinue when players are unjoined, // pCurSteps will still be set while no players are joined. -Chris @@ -690,7 +712,11 @@ void GameState::BeginStage() if( !ARE_STAGE_PLAYER_MODS_FORCED ) { FOREACH_PlayerNumber( p ) - m_pPlayerState[p]->m_PlayerOptions.Assign( ModsLevel_Stage, m_pPlayerState[p]->m_PlayerOptions.GetPreferred() ); + { + ModsGroup &po = m_pPlayerState[p]->m_PlayerOptions; + po.Assign(ModsLevel_Stage, + m_pPlayerState[p]->m_PlayerOptions.GetPreferred()); + } } if( !ARE_STAGE_SONG_MODS_FORCED ) m_SongOptions.Assign( ModsLevel_Stage, m_SongOptions.GetPreferred() ); @@ -969,7 +995,8 @@ update player position code goes here float GameState::GetSongPercent( float beat ) const { // 0 = first step; 1 = last step - return (beat - m_pCurSong->m_fFirstBeat) / m_pCurSong->m_fLastBeat; + float curTime = this->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat(beat); + return (curTime - m_pCurSong->GetFirstSecond()) / m_pCurSong->GetLastSecond(); } int GameState::GetNumStagesLeft( PlayerNumber pn ) const @@ -994,9 +1021,9 @@ bool GameState::IsFinalStageForAnyHumanPlayer() const bool GameState::IsAnExtraStage() const { - if( m_MasterPlayerNumber == PlayerNumber_Invalid ) + if( this->GetMasterPlayerNumber() == PlayerNumber_Invalid ) return false; - return !IsEventMode() && !IsCourseMode() && m_iAwardedExtraStages[m_MasterPlayerNumber] > 0; + return !IsEventMode() && !IsCourseMode() && m_iAwardedExtraStages[this->GetMasterPlayerNumber()] > 0; } static ThemeMetric LOCK_EXTRA_STAGE_SELECTION("GameState","LockExtraStageSelection"); @@ -1007,16 +1034,16 @@ bool GameState::IsAnExtraStageAndSelectionLocked() const bool GameState::IsExtraStage() const { - if( m_MasterPlayerNumber == PlayerNumber_Invalid ) + if( this->GetMasterPlayerNumber() == PlayerNumber_Invalid ) return false; - return !IsEventMode() && !IsCourseMode() && m_iAwardedExtraStages[m_MasterPlayerNumber] == 1; + return !IsEventMode() && !IsCourseMode() && m_iAwardedExtraStages[this->GetMasterPlayerNumber()] == 1; } bool GameState::IsExtraStage2() const { - if( m_MasterPlayerNumber == PlayerNumber_Invalid ) + if( this->GetMasterPlayerNumber() == PlayerNumber_Invalid ) return false; - return !IsEventMode() && !IsCourseMode() && m_iAwardedExtraStages[m_MasterPlayerNumber] == 2; + return !IsEventMode() && !IsCourseMode() && m_iAwardedExtraStages[this->GetMasterPlayerNumber()] == 2; } Stage GameState::GetCurrentStage() const @@ -1059,7 +1086,7 @@ int GameState::GetCourseSongIndex() const } else { - return STATSMAN->m_CurStageStats.m_player[m_MasterPlayerNumber].m_iSongsPlayed-1; + return STATSMAN->m_CurStageStats.m_player[this->GetMasterPlayerNumber()].m_iSongsPlayed-1; } } @@ -1131,7 +1158,7 @@ void GameState::SetCurrentStyle( const Style *pStyle ) if( INPUTMAPPER ) { if( GetCurrentStyle() && GetCurrentStyle()->m_StyleType == StyleType_OnePlayerTwoSides ) - INPUTMAPPER->SetJoinControllers( m_MasterPlayerNumber ); + INPUTMAPPER->SetJoinControllers( this->GetMasterPlayerNumber() ); else INPUTMAPPER->SetJoinControllers( PLAYER_INVALID ); } @@ -1192,7 +1219,7 @@ bool GameState::IsHumanPlayer( PlayerNumber pn ) const return true; case StyleType_OnePlayerOneSide: case StyleType_OnePlayerTwoSides: - return pn == m_MasterPlayerNumber; + return pn == this->GetMasterPlayerNumber(); default: ASSERT(0); // invalid style type return false; @@ -1276,7 +1303,7 @@ EarnedExtraStage GameState::CalculateEarnedExtraStage() const if( GetSmallestNumStagesLeftForAnyHumanPlayer() > 0 ) return EarnedExtraStage_No; - if( m_iAwardedExtraStages[m_MasterPlayerNumber] >= 2 ) + if( m_iAwardedExtraStages[this->GetMasterPlayerNumber()] >= 2 ) return EarnedExtraStage_No; FOREACH_EnabledPlayer( pn ) @@ -2124,7 +2151,7 @@ public: DEFINE_METHOD( IsPlayerEnabled, IsPlayerEnabled(Enum::Check(L, 1)) ) DEFINE_METHOD( IsHumanPlayer, IsHumanPlayer(Enum::Check(L, 1)) ) DEFINE_METHOD( GetPlayerDisplayName, GetPlayerDisplayName(Enum::Check(L, 1)) ) - DEFINE_METHOD( GetMasterPlayerNumber, m_MasterPlayerNumber ) + DEFINE_METHOD( GetMasterPlayerNumber, GetMasterPlayerNumber() ) DEFINE_METHOD( GetMultiplayer, m_bMultiplayer ) static int SetMultiplayer( T* p, lua_State *L ) { diff --git a/src/GameState.h b/src/GameState.h index 5e925e05ff..51abbac141 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -32,9 +32,15 @@ class Style; class TimingData; class Trail; +SortOrder GetDefaultSort(); + /** @brief Holds game data that is not saved between sessions. */ class GameState { + /** @brief The player number used with Styles where one player controls both sides. */ + PlayerNumber masterPlayerNumber; + /** @brief The TimingData that is used for processing certain functions. */ + TimingData * processedTiming; public: /** @brief Set up the GameState with initial values. */ GameState(); @@ -91,8 +97,6 @@ public: * to get one credit, only to have to put in another four coins to get * the three credits needed to begin the game. */ BroadcastOnChange m_iCoins; - /** @brief The player number used with Styles where one player controls both sides. */ - PlayerNumber m_MasterPlayerNumber; bool m_bMultiplayer; int m_iNumMultiplayerNoteFields; bool DifficultiesLocked() const; @@ -139,6 +143,26 @@ public: PlayerNumber GetFirstDisabledPlayer() const; bool IsCpuPlayer( PlayerNumber pn ) const; bool AnyPlayersAreCpu() const; + + /** + * @brief Retrieve the present master player number. + * @return The master player number. */ + PlayerNumber GetMasterPlayerNumber() const; + + /** + * @brief Set the master player number. + * @param p the master player number. */ + void SetMasterPlayerNumber(const PlayerNumber p); + + /** + * @brief Retrieve the present timing data being processed. + * @return the timing data pointer. */ + TimingData * GetProcessedTimingData() const; + + /** + * @brief Set the timing data to be used with processing. + * @param t the timing data. */ + void SetProcessedTimingData(TimingData * t); bool IsCourseMode() const; bool IsBattleMode() const; // not Rave diff --git a/src/GameplayAssist.cpp b/src/GameplayAssist.cpp index 4ecd6be014..e42920f15c 100644 --- a/src/GameplayAssist.cpp +++ b/src/GameplayAssist.cpp @@ -47,7 +47,7 @@ void GameplayAssist::PlayTicks( const NoteData &nd, const PlayerState *ps ) if( nd.IsThereATapOrHoldHeadAtRow( r ) ) iClapRow = r; - if( iClapRow != -1 && !timing.IsWarpAtRow( iClapRow ) && !timing.IsFakeAtRow( iClapRow ) ) + if( iClapRow != -1 && timing.IsJudgableAtRow(iClapRow)) { const float fTickBeat = NoteRowToBeat( iClapRow ); const float fTickSecond = timing.GetElapsedTimeFromBeatNoOffset( fTickBeat ); diff --git a/src/GhostArrowRow.cpp b/src/GhostArrowRow.cpp index 8a2b9f0b4a..f81eef75d6 100644 --- a/src/GhostArrowRow.cpp +++ b/src/GhostArrowRow.cpp @@ -88,7 +88,9 @@ void GhostArrowRow::Update( float fDeltaTime ) void GhostArrowRow::DrawPrimitives() { for( unsigned c=0; cDraw(); + } } void GhostArrowRow::DidTapNote( int iCol, TapNoteScore tns, bool bBright ) diff --git a/src/InGameLoadingWindow.cpp b/src/InGameLoadingWindow.cpp new file mode 100644 index 0000000000..39c06fa44c --- /dev/null +++ b/src/InGameLoadingWindow.cpp @@ -0,0 +1,31 @@ +#include "global.h" +#include "InGameLoadingWindow.h" +#include "ScreenManager.h" +#include "ThemeManager.h" +#include "ActorUtil.h" + +//REGISTER_ACTOR_CLASS( InGameLoadingWindow ); + +InGameLoadingWindow::InGameLoadingWindow() { + SetName("InGameLoadingWindow"); + m_Text.SetName("LoadingText"); + m_Text.LoadFromFont( THEME->GetPathF(m_sName, "LoadingText") ); + m_Text.SetXY(0,0); + AddChild(&m_Text); +} + +InGameLoadingWindow::~InGameLoadingWindow() { + RemoveChild(&m_Text); +} + +void InGameLoadingWindow::SetText( RString str ) { + textChanged=true; + currentText=str; +} + +void InGameLoadingWindow::Update(float delta) { + if(textChanged) { + m_Text.SetText( currentText ); + textChanged=false; + } +} diff --git a/src/InGameLoadingWindow.h b/src/InGameLoadingWindow.h new file mode 100644 index 0000000000..431be5119f --- /dev/null +++ b/src/InGameLoadingWindow.h @@ -0,0 +1,21 @@ +#include "arch/LoadingWindow/LoadingWindow.h" +#include "BitmapText.h" +#include "RageTimer.h" +#include "global.h" +#include "ActorFrame.h" + +class InGameLoadingWindow: public LoadingWindow, public ActorFrame { + +public: + InGameLoadingWindow(); + ~InGameLoadingWindow(); + + void SetText( RString str ); + void Update ( float delta ); + +private: + bool textChanged; + RString currentText; + BitmapText m_Text; +}; + diff --git a/src/InputMapper.cpp b/src/InputMapper.cpp index 90e65ae879..1b0a71e77c 100644 --- a/src/InputMapper.cpp +++ b/src/InputMapper.cpp @@ -64,7 +64,7 @@ static const AutoMappings g_DefaultKeyMappings = AutoMappings( AutoMappingEntry( 0, KEY_KP_C2, GAME_BUTTON_MENUDOWN, true ), AutoMappingEntry( 0, KEY_KP_ENTER, GAME_BUTTON_START, true ), AutoMappingEntry( 0, KEY_KP_C0, GAME_BUTTON_SELECT, true ), - AutoMappingEntry( 0, KEY_NUMLOCK, GAME_BUTTON_BACK, true ), + AutoMappingEntry( 0, KEY_HYPHEN, GAME_BUTTON_BACK, true ), // laptop keyboards. AutoMappingEntry( 0, KEY_F1, GAME_BUTTON_COIN, false ), AutoMappingEntry( 0, KEY_SCRLLOCK, GAME_BUTTON_OPERATOR, false ) ); diff --git a/src/Inventory.cpp b/src/Inventory.cpp index 3b7eb88b32..b45b779449 100644 --- a/src/Inventory.cpp +++ b/src/Inventory.cpp @@ -11,6 +11,7 @@ #include "ThemeMetric.h" #include "PlayerState.h" +void ReloadItems(); #define NUM_ITEM_TYPES THEME->GetMetricF("Inventory","NumItemTypes") #define ITEM_DURATION_SECONDS THEME->GetMetricF("Inventory","ItemDurationSeconds") @@ -118,10 +119,10 @@ void Inventory::Update( float fDelta ) } } - + Song &song = *GAMESTATE->m_pCurSong; // use items if this player is CPU-controlled if( m_pPlayerState->m_PlayerController != PC_HUMAN && - GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fLastBeat ) + GAMESTATE->m_Position.m_fSongBeat < song.GetLastBeat() ) { // every 1 seconds, try to use an item int iLastSecond = (int)(RageTimer::GetTimeSinceStartFast() - fDelta); diff --git a/src/JsonUtil.cpp b/src/JsonUtil.cpp index be736ea4b5..755036e770 100644 --- a/src/JsonUtil.cpp +++ b/src/JsonUtil.cpp @@ -14,8 +14,7 @@ bool JsonUtil::LoadFromString(Json::Value &root, RString sData, RString &sErrorO if (!parsingSuccessful) { RString err = reader.getFormatedErrorMessages(); - sErrorOut = ssprintf("JSON: LoadFromFileShowErrors failed: %s", err.c_str()); - LOG->Warn(sErrorOut); + LOG->Warn("JSON: LoadFromFileShowErrors failed: %s", err.c_str()); return false; } return true; diff --git a/src/JsonUtil.h b/src/JsonUtil.h index 87942336e0..22c33ae4ec 100644 --- a/src/JsonUtil.h +++ b/src/JsonUtil.h @@ -31,6 +31,24 @@ namespace JsonUtil for(unsigned i=0; i + static void SerializeVectorPointers(const vector &v, void fn(const T &, Json::Value &), Json::Value &root) + { + root = Json::Value(Json::arrayValue); + root.resize(v.size()); + for(unsigned i=0; i + static void SerializeVectorPointers(const vector &v, void fn(const T *, Json::Value &), Json::Value &root) + { + root = Json::Value(Json::arrayValue); + root.resize(v.size()); + for(unsigned i=0; i static void SerializeArray(const V &v, void fn(const T &, Json::Value &), Json::Value &root) @@ -149,6 +167,19 @@ namespace JsonUtil fn(*v[i], root[i]); } } + + template + static void DeserializeVectorPointers(vector &v, void fn(T *, const Json::Value &), const Json::Value &root) + { + for(unsigned i=0; i static void DeserializeArrayValues(vector &v, const Json::Value &root) diff --git a/src/LifeMeterBar.cpp b/src/LifeMeterBar.cpp index 8256732b89..bbc101058a 100644 --- a/src/LifeMeterBar.cpp +++ b/src/LifeMeterBar.cpp @@ -172,7 +172,7 @@ void LifeMeterBar::ChangeLife( HoldNoteScore score, TapNoteScore tscore ) switch( score ) { case HNS_Held: fDeltaLife = +0; break; - case HNS_LetGo: fDeltaLife = -1.0; break; + case HNS_LetGo: fDeltaLife = -1.0f; break; default: ASSERT(0); } diff --git a/src/LifeMeterBattery.cpp b/src/LifeMeterBattery.cpp index 009d920e50..3f49487a17 100644 --- a/src/LifeMeterBattery.cpp +++ b/src/LifeMeterBattery.cpp @@ -26,6 +26,14 @@ void LifeMeterBattery::Load( const PlayerState *pPlayerState, PlayerStageStats * const RString sType = "LifeMeterBattery"; PlayerNumber pn = pPlayerState->m_PlayerNumber; + MIN_SCORE_TO_KEEP_LIFE.Load(sType, "MinScoreToKeepLife"); + DANGER_THRESHOLD.Load(sType, "DangerThreshold"); + SUBTRACT_LIVES.Load(sType, "SubtractLives"); + MINES_SUBTRACT_LIVES.Load(sType, "MinesSubtractLives"); + HELD_ADD_LIVES.Load(sType, "HeldAddLives"); + LET_GO_SUBTRACT_LIVES.Load(sType, "LetGoSubtractLives"); + + LIVES_FORMAT.Load(sType, "NumLivesFormat"); BATTERY_BLINK_TIME.Load(sType, "BatteryBlinkTime"); // 1.2f by default bool bPlayerEnabled = GAMESTATE->IsPlayerEnabled( pPlayerState ); @@ -101,42 +109,54 @@ void LifeMeterBattery::OnSongEnded() Refresh(); } +void LifeMeterBattery::SubtractLives( int iLives ) +{ + if( iLives <= 0 ) + return; + + m_iTrailingLivesLeft = m_iLivesLeft; + m_iLivesLeft -= iLives; + m_soundLoseLife.Play(); + m_textNumLives.PlayCommand("LoseLife"); + + Refresh(); + m_fBatteryBlinkTime = BATTERY_BLINK_TIME; +} + +void LifeMeterBattery::AddLives( int iLives ) +{ + if( iLives <= 0 ) + return; + + m_iTrailingLivesLeft = m_iLivesLeft; + m_iLivesLeft += iLives; + m_soundGainLife.Play(); + m_textNumLives.PlayCommand("GainLife"); + + Refresh(); + m_fBatteryBlinkTime = 0; +} + +void LifeMeterBattery::ChangeLives(int iLifeDiff) +{ + if( iLifeDiff < 0 ) + SubtractLives( abs(iLifeDiff) ); + else if( iLifeDiff > 0 ) + AddLives(iLifeDiff); +} + void LifeMeterBattery::ChangeLife( TapNoteScore score ) { if( m_iLivesLeft == 0 ) return; - // todo: let the themer decide how this is handled. -aj - switch( score ) + // this probably doesn't handle hold checkpoints. -aj + if( score == TNS_HitMine && MINES_SUBTRACT_LIVES > 0 ) + SubtractLives(MINES_SUBTRACT_LIVES); + else { - case TNS_W1: - case TNS_W2: - case TNS_W3: - break; - case TNS_W4: - case TNS_W5: - case TNS_Miss: - case TNS_HitMine: - m_iTrailingLivesLeft = m_iLivesLeft; - m_iLivesLeft--; - m_soundLoseLife.Play(); - - m_textNumLives.PlayCommand("LoseLife"); - /* - m_textNumLives.SetZoom( 1.5f ); - m_textNumLives.BeginTweening( 0.15f ); - m_textNumLives.SetZoom( 1.0f ); - */ - - Refresh(); - m_fBatteryBlinkTime = BATTERY_BLINK_TIME; - break; - default: - break; - /* - // xxx: this doesn't handle hold checkpoints. - ASSERT(0); - */ + if( score < MIN_SCORE_TO_KEEP_LIFE && score > TNS_CheckpointMiss && SUBTRACT_LIVES > 0 ) + SubtractLives(SUBTRACT_LIVES); } Message msg( "LifeChanged" ); @@ -148,16 +168,19 @@ void LifeMeterBattery::ChangeLife( TapNoteScore score ) void LifeMeterBattery::ChangeLife( HoldNoteScore score, TapNoteScore tscore ) { - switch( score ) - { - case HNS_Held: - break; - case HNS_LetGo: - ChangeLife( TNS_Miss ); // LetGo is the same as a miss - break; - default: - ASSERT(0); - } + if( m_iLivesLeft == 0 ) + return; + + if( score == HNS_Held && HELD_ADD_LIVES > 0 ) + AddLives(HELD_ADD_LIVES); + if( score == HNS_LetGo && LET_GO_SUBTRACT_LIVES > 0 ) + SubtractLives(LET_GO_SUBTRACT_LIVES); + + Message msg( "LifeChanged" ); + msg.SetParam( "Player", m_pPlayerState->m_PlayerNumber ); + msg.SetParam( "LifeMeter", LuaReference::CreateFromPush(*this) ); + msg.SetParam( "LivesLeft", GetLivesLeft() ); + MESSAGEMAN->Broadcast( msg ); } void LifeMeterBattery::HandleTapScoreNone() @@ -171,12 +194,12 @@ void LifeMeterBattery::ChangeLife( float fDeltaLifePercent ) bool LifeMeterBattery::IsInDanger() const { - return false; + return m_iLivesLeft < DANGER_THRESHOLD; } bool LifeMeterBattery::IsHot() const { - return false; + return m_iLivesLeft == GAMESTATE->m_SongOptions.GetSong().m_iBatteryLives; } bool LifeMeterBattery::IsFailing() const @@ -208,7 +231,8 @@ void LifeMeterBattery::Refresh() } else { - m_textNumLives.SetText( ssprintf("x%d", m_iLivesLeft-1) ); + //m_textNumLives.SetText( ssprintf("x%d", m_iLivesLeft-1) ); + m_textNumLives.SetText( ssprintf(LIVES_FORMAT.GetValue(), m_iLivesLeft-1) ); m_sprBattery.SetState( 3 ); } } @@ -244,13 +268,14 @@ class LunaLifeMeterBattery: public Luna { public: static int GetLivesLeft( T* p, lua_State *L ) { lua_pushnumber( L, p->GetLivesLeft() ); return 1; } - // is this right? wtf -q2x static int GetTotalLives( T* p, lua_State *L ) { lua_pushnumber( L, GAMESTATE->m_SongOptions.GetSong().m_iBatteryLives ); return 1; } + static int ChangeLives( T* p, lua_State *L ) { p->ChangeLives(IArg(1)); return 0; } LunaLifeMeterBattery() { ADD_METHOD( GetLivesLeft ); ADD_METHOD( GetTotalLives ); + ADD_METHOD( ChangeLives ); } }; diff --git a/src/LifeMeterBattery.h b/src/LifeMeterBattery.h index d7b4a90a1d..648811a9fc 100644 --- a/src/LifeMeterBattery.h +++ b/src/LifeMeterBattery.h @@ -32,18 +32,28 @@ public: void Refresh(); int GetLivesLeft() { return m_iLivesLeft; } + void ChangeLives(int iLifeDiff); // Lua virtual void PushSelf( lua_State *L ); private: + void SubtractLives( int iLives ); + void AddLives( int iLives ); + int m_iLivesLeft; // dead when 0 int m_iTrailingLivesLeft; // lags m_iLivesLeft float m_fBatteryBlinkTime; // if > 0 battery is blinking - // theme metrics added for sm-ssc ThemeMetric BATTERY_BLINK_TIME; + ThemeMetric MIN_SCORE_TO_KEEP_LIFE; + ThemeMetric DANGER_THRESHOLD; + ThemeMetric SUBTRACT_LIVES; + ThemeMetric MINES_SUBTRACT_LIVES; + ThemeMetric HELD_ADD_LIVES; + ThemeMetric LET_GO_SUBTRACT_LIVES; + ThemeMetric LIVES_FORMAT; AutoActor m_sprFrame; Sprite m_sprBattery; diff --git a/src/LuaManager.h b/src/LuaManager.h index 5bcf0233eb..084532800a 100644 --- a/src/LuaManager.h +++ b/src/LuaManager.h @@ -220,9 +220,11 @@ inline bool MyLua_checkintboolean( lua_State *L, int iArg ) #define FArg(n) ((float) luaL_checknumber(L,(n))) #define LuaFunction( func, expr ) \ +int LuaFunc_##func( lua_State *L ); \ int LuaFunc_##func( lua_State *L ) { \ LuaHelpers::Push( L, expr ); return 1; \ } \ +void LuaFunc_Register_##func( lua_State *L ); \ void LuaFunc_Register_##func( lua_State *L ) { lua_register( L, #func, LuaFunc_##func ); } \ REGISTER_WITH_LUA_FUNCTION( LuaFunc_Register_##func ); diff --git a/src/LyricDisplay.cpp b/src/LyricDisplay.cpp index 7284d2dc17..b896814e1d 100644 --- a/src/LyricDisplay.cpp +++ b/src/LyricDisplay.cpp @@ -59,8 +59,8 @@ void LyricDisplay::Update( float fDeltaTime ) if( m_iCurLyricNumber+1 < GAMESTATE->m_pCurSong->m_LyricSegments.size() ) fEndTime = pSong->m_LyricSegments[m_iCurLyricNumber+1].m_fStartTime; else - fEndTime = pSong->m_SongTiming.GetElapsedTimeFromBeat( pSong->m_fLastBeat ); - + fEndTime = pSong->GetLastSecond(); + const float fDistance = fEndTime - pSong->m_LyricSegments[m_iCurLyricNumber].m_fStartTime; const float fTweenBufferTime = IN_LENGTH.GetValue() + OUT_LENGTH.GetValue(); diff --git a/src/Makefile.am b/src/Makefile.am index 2abcf7c4be..34443e1708 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -107,7 +107,7 @@ ScreenSyncOverlay.cpp ScreenSyncOverlay.h \ ScreenSystemLayer.cpp ScreenSystemLayer.h ScreenSetTime.cpp ScreenSetTime.h \ ScreenSongOptions.cpp ScreenSongOptions.h \ ScreenSplash.cpp ScreenSplash.h \ -ScreenTestFonts.cpp ScreenTestFonts.h ScreenTestInput.cpp ScreenTestInput.h \ +ScreenTestInput.cpp ScreenTestInput.h \ ScreenTestLights.cpp ScreenTestLights.h ScreenTestSound.cpp ScreenTestSound.h ScreenTextEntry.cpp ScreenTextEntry.h \ ScreenTitleMenu.cpp ScreenTitleMenu.h \ ScreenUnlockBrowse.cpp ScreenUnlockBrowse.h \ @@ -340,6 +340,7 @@ DualScrollBar.cpp DualScrollBar.h \ EditMenu.cpp EditMenu.h FadingBanner.cpp FadingBanner.h \ GradeDisplay.cpp GradeDisplay.h GraphDisplay.cpp GraphDisplay.h \ GrooveRadar.cpp GrooveRadar.h HelpDisplay.cpp HelpDisplay.h \ +InGameLoadingWindow.cpp InGameLoadingWindow.h \ MemoryCardDisplay.cpp MemoryCardDisplay.h \ MenuTimer.cpp MenuTimer.h \ ModIcon.cpp ModIcon.h ModIconRow.cpp ModIconRow.h \ diff --git a/src/MenuTimer.h b/src/MenuTimer.h index 1756bf715d..cd3a211c54 100644 --- a/src/MenuTimer.h +++ b/src/MenuTimer.h @@ -9,6 +9,8 @@ #include "ThemeMetric.h" #include "AutoActor.h" +RString WARNING_COMMAND_NAME( size_t i ); + class MenuTimer : public ActorFrame { public: diff --git a/src/MeterDisplay.cpp b/src/MeterDisplay.cpp index 641b50d73c..cd8c2faebb 100644 --- a/src/MeterDisplay.cpp +++ b/src/MeterDisplay.cpp @@ -73,8 +73,8 @@ void SongMeterDisplay::Update( float fDeltaTime ) { if( GAMESTATE->m_pCurSong ) { - float fSongStartSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fFirstBeat ); - float fSongEndSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat ); + float fSongStartSeconds = GAMESTATE->m_pCurSong->GetFirstSecond(); + float fSongEndSeconds = GAMESTATE->m_pCurSong->GetLastSecond(); float fPercentPositionSong = SCALE( GAMESTATE->m_Position.m_fMusicSeconds, fSongStartSeconds, fSongEndSeconds, 0.0f, 1.0f ); CLAMP( fPercentPositionSong, 0, 1 ); diff --git a/src/ModIconRow.cpp b/src/ModIconRow.cpp index 362c5a8e4d..7ecf1ce320 100644 --- a/src/ModIconRow.cpp +++ b/src/ModIconRow.cpp @@ -10,6 +10,8 @@ #include "LuaManager.h" #include "Foreach.h" +int OptionToPreferredColumn( RString sOptionText ); + REGISTER_ACTOR_CLASS( ModIconRow ); ModIconRow::ModIconRow() @@ -66,35 +68,12 @@ void ModIconRow::HandleMessage( const Message &msg ) struct OptionColumnEntry { - char *szString; + const char *szString; int iSlotIndex; //void FromStack( lua_State *L, int iPos ); }; -/* -void OptionColumnEntry::FromStack( lua_State *L, int iPos ) -{ - if( lua_type(L, iPos) != LUA_TTABLE ) - return; - - lua_pushvalue( L, iPos ); - const int iTab = lua_gettop( L ); - - // option name - lua_getfield( L, iTab, "Name" ); - RString sName = lua_tostring( L, -1 ); - szString = const_cast(sName.c_str()); - lua_settop( L, iTab ); - - // option icon index - lua_getfield( L, iTab, "IconIndex" ); - iSlotIndex = lua_tointeger( L, -1 ); - lua_settop( L, iTab ); -} -static vector g_OptionColumnEntries; -*/ - // todo: metric these? -aj static const OptionColumnEntry g_OptionColumnEntries[] = { diff --git a/src/MusicWheel.cpp b/src/MusicWheel.cpp index 77303f5286..5c7d9a6b6b 100644 --- a/src/MusicWheel.cpp +++ b/src/MusicWheel.cpp @@ -969,7 +969,7 @@ void MusicWheel::FilterWheelItemDatas(vector &aUnFilteredD } /* If the song has no steps for the current style, remove it. */ - if( !pSong->HasStepsType(GAMESTATE->GetCurrentStyle()->m_StepsType) ) + if( !CommonMetrics::AUTO_SET_STYLE && !pSong->HasStepsType(GAMESTATE->GetCurrentStyle()->m_StepsType) ) { aiRemove[i] = true; continue; @@ -1476,11 +1476,11 @@ RString MusicWheel::JumpToPrevGroup() // in case it wasn't found above: for( unsigned int i = m_CurWheelItemData.size()-1; i > 0; --i ) { - LOG->Trace( ssprintf("JumpToPrevGroup iteration 2 | i = %u",i) ); + LOG->Trace( "JumpToPrevGroup iteration 2 | i = %u",i ); if( m_CurWheelItemData[i]->m_Type == TYPE_SECTION ) { m_iSelection = i; - LOG->Trace( ssprintf("finding it in #2 | i = %u | text = %s",i, m_CurWheelItemData[i]->m_sText.c_str()) ); + LOG->Trace( "finding it in #2 | i = %u | text = %s",i, m_CurWheelItemData[i]->m_sText.c_str() ); return m_CurWheelItemData[i]->m_sText; } } diff --git a/src/MusicWheelItem.cpp b/src/MusicWheelItem.cpp index c7ad0fb3c3..5bde9a78a1 100644 --- a/src/MusicWheelItem.cpp +++ b/src/MusicWheelItem.cpp @@ -170,6 +170,10 @@ MusicWheelItem::MusicWheelItem( const MusicWheelItem &cpy ): MusicWheelItem::~MusicWheelItem() { + FOREACH_ENUM( MusicWheelItemType, i ) + { + SAFE_DELETE(m_pText[i]); + } delete m_pTextSectionCount; } diff --git a/src/NetworkSyncManager.cpp b/src/NetworkSyncManager.cpp index b49720a46a..66a4a1b4de 100644 --- a/src/NetworkSyncManager.cpp +++ b/src/NetworkSyncManager.cpp @@ -237,7 +237,7 @@ void NetworkSyncManager::ReportScore(int playerID, int step, int score, int comb if( !useSMserver ) //Make sure that we are using the network return; - LOG->Trace( ssprintf("Player ID %i combo = %i", playerID, combo) ); + LOG->Trace( "Player ID %i combo = %i", playerID, combo ); m_packet.ClearPacket(); m_packet.Write1( NSCGSU ); diff --git a/src/NoteData.cpp b/src/NoteData.cpp index eac5bc42b4..78880dfbbe 100644 --- a/src/NoteData.cpp +++ b/src/NoteData.cpp @@ -9,6 +9,7 @@ #include "RageUtil.h" #include "RageLog.h" #include "XmlFile.h" +#include "GameState.h" // blame radar calculations. #include "Foreach.h" #include "RageUtil_AutoPtr.h" @@ -458,6 +459,31 @@ int NoteData::GetLastRow() const return iOldestRowFoundSoFar; } +bool NoteData::IsTap(const TapNote &tn, const int row) const +{ + return (tn.type != TapNote::empty && tn.type != TapNote::mine + && tn.type != TapNote::lift && tn.type != TapNote::fake + && GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(row)); +} + +bool NoteData::IsMine(const TapNote &tn, const int row) const +{ + return (tn.type == TapNote::mine + && GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(row)); +} + +bool NoteData::IsLift(const TapNote &tn, const int row) const +{ + return (tn.type == TapNote::lift + && GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(row)); +} + +bool NoteData::IsFake(const TapNote &tn, const int row) const +{ + return (tn.type == TapNote::fake + || !GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(row)); +} + int NoteData::GetNumTapNotes( int iStartIndex, int iEndIndex ) const { int iNumNotes = 0; @@ -465,9 +491,7 @@ int NoteData::GetNumTapNotes( int iStartIndex, int iEndIndex ) const { FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( *this, t, r, iStartIndex, iEndIndex ) { - const TapNote &tn = GetTapNote(t, r); - if( tn.type != TapNote::empty && tn.type != TapNote::mine - && tn.type != TapNote::lift && tn.type != TapNote::fake ) + if (this->IsTap(GetTapNote(t, r), r)) iNumNotes++; } } @@ -485,7 +509,7 @@ int NoteData::GetNumRowsWithTap( int iStartIndex, int iEndIndex ) const { int iNumNotes = 0; FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( *this, r, iStartIndex, iEndIndex ) - if( IsThereATapAtRow(r) ) + if( IsThereATapAtRow(r) && GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r) ) iNumNotes++; return iNumNotes; @@ -498,7 +522,7 @@ int NoteData::GetNumMines( int iStartIndex, int iEndIndex ) const for( int t=0; tIsMine(GetTapNote(t, r), r)) iNumMines++; } @@ -509,7 +533,7 @@ int NoteData::GetNumRowsWithTapOrHoldHead( int iStartIndex, int iEndIndex ) cons { int iNumNotes = 0; FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( *this, r, iStartIndex, iEndIndex ) - if( IsThereATapOrHoldHeadAtRow(r) ) + if( IsThereATapOrHoldHeadAtRow(r) && GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r) ) iNumNotes++; return iNumNotes; @@ -560,7 +584,8 @@ int NoteData::GetNumRowsWithSimultaneousPresses( int iMinSimultaneousPresses, in { if( !RowNeedsAtLeastSimultaneousPresses(iMinSimultaneousPresses,r) ) continue; - + if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r)) + continue; iNum++; } @@ -576,7 +601,10 @@ int NoteData::GetNumRowsWithSimultaneousTaps( int iMinTaps, int iStartIndex, int for( int t=0; tGetProcessedTimingData()->IsJudgableAtRow(r)) iNumNotesThisIndex++; } if( iNumNotesThisIndex >= iMinTaps ) @@ -598,6 +626,8 @@ int NoteData::GetNumHoldNotes( int iStartIndex, int iEndIndex ) const if( lBegin->second.type != TapNote::hold_head || lBegin->second.subType != TapNote::hold_head_hold ) continue; + if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(lBegin->first)) + continue; iNumHolds++; } } @@ -616,6 +646,8 @@ int NoteData::GetNumRolls( int iStartIndex, int iEndIndex ) const if( lBegin->second.type != TapNote::hold_head || lBegin->second.subType != TapNote::hold_head_roll ) continue; + if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(lBegin->first)) + continue; iNumRolls++; } } @@ -629,7 +661,7 @@ int NoteData::GetNumLifts( int iStartIndex, int iEndIndex ) const for( int t=0; tIsLift(GetTapNote(t, r), r)) iNumLifts++; } @@ -643,13 +675,190 @@ int NoteData::GetNumFakes( int iStartIndex, int iEndIndex ) const for( int t=0; tIsFake(GetTapNote(t, r), r)) + iNumFakes++; } return iNumFakes; } +bool NoteData::IsPlayer1(const int track, const TapNote &tn) const +{ + if (this->IsComposite()) + { + return tn.pn == PLAYER_1; + } + return track < (this->GetNumTracks() / 2); +} + +pair NoteData::GetNumTapNotesTwoPlayer( int iStartIndex, int iEndIndex ) const +{ + pair num(0, 0); + for( int t=0; tIsTap(tn, r)) + { + if (this->IsPlayer1(t, tn)) + num.first++; + else + num.second++; + } + } + } + return num; +} + +pair NoteData::GetNumRowsWithSimultaneousTapsTwoPlayer(int minTaps, + int startRow, + int endRow) const +{ + pair num(0, 0); + FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( *this, r, startRow, endRow ) + { + pair found(0, 0); + for( int t=0; tIsTap(tn, r)) + { + if (this->IsPlayer1(t, tn)) + found.first++; + else + found.second++; + } + } + if (found.first >= minTaps) + num.first++; + if (found.second >= minTaps) + num.second++; + } + return num; +} + +pair NoteData::GetNumJumpsTwoPlayer( int iStartIndex, int iEndIndex ) const +{ + return GetNumRowsWithSimultaneousTapsTwoPlayer( 2, iStartIndex, iEndIndex ); +} + +pair NoteData::GetNumHandsTwoPlayer( int iStartIndex, int iEndIndex ) const +{ + return GetNumRowsWithSimultaneousTapsTwoPlayer( 3, iStartIndex, iEndIndex ); +} + +pair NoteData::GetNumQuadsTwoPlayer( int iStartIndex, int iEndIndex ) const +{ + return GetNumRowsWithSimultaneousTapsTwoPlayer( 4, iStartIndex, iEndIndex ); +} + +pair NoteData::GetNumHoldNotesTwoPlayer( int iStartIndex, int iEndIndex ) const +{ + pair num(0, 0); + for( int t=0; tsecond.type != TapNote::hold_head || + lBegin->second.subType != TapNote::hold_head_hold ) + continue; + if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(lBegin->first)) + continue; + if (this->IsPlayer1(t, lBegin->second)) + num.first++; + else + num.second++; + } + } + return num; +} + +pair NoteData::GetNumMinesTwoPlayer( int iStartIndex, int iEndIndex ) const +{ + pair num(0, 0); + for( int t=0; tIsMine(tn, r)) + { + if (this->IsPlayer1(t, tn)) + num.first++; + else + num.second++; + } + } + } + return num; +} + +pair NoteData::GetNumRollsTwoPlayer( int iStartIndex, int iEndIndex ) const +{ + pair num(0, 0); + for( int t=0; tsecond.type != TapNote::hold_head || + lBegin->second.subType != TapNote::hold_head_roll ) + continue; + if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(lBegin->first)) + continue; + if (this->IsPlayer1(t, lBegin->second)) + num.first++; + else + num.second++; + } + } + return num; +} + +pair NoteData::GetNumLiftsTwoPlayer( int iStartIndex, int iEndIndex ) const +{ + pair num(0, 0); + for( int t=0; tIsLift(tn, r)) + { + if (this->IsPlayer1(t, tn)) + num.first++; + else + num.second++; + } + } + } + return num; +} + +pair NoteData::GetNumFakesTwoPlayer( int iStartIndex, int iEndIndex ) const +{ + pair num(0, 0); + for( int t=0; tIsFake(tn, r)) + { + if (this->IsPlayer1(t, tn)) + num.first++; + else + num.second++; + } + } + } + return num; +} + /* int NoteData::GetNumMinefields( int iStartIndex, int iEndIndex ) const { diff --git a/src/NoteData.h b/src/NoteData.h index 5de742eb30..df8d6a5856 100644 --- a/src/NoteData.h +++ b/src/NoteData.h @@ -90,7 +90,46 @@ private: // There's no point in inserting empty notes into the map. // Any blank space in the map is defined to be empty. vector m_TapNotes; + + /** + * @brief Determine whether this note is for Player 1 or Player 2. + * @param track the track/column the note is in. + * @param tn the note in question. Required for routine mode. + * @return true if it's for player 1, false for player 2. */ + bool IsPlayer1(const int track, const TapNote &tn) const; + + /** + * @brief Determine if the note in questino should be counted as a tap. + * @param tn the note in question. + * @param row the row it lives in. + * @return true if it's a tap, false otherwise. */ + bool IsTap(const TapNote &tn, const int row) const; + + /** + * @brief Determine if the note in questino should be counted as a mine. + * @param tn the note in question. + * @param row the row it lives in. + * @return true if it's a mine, false otherwise. */ + bool IsMine(const TapNote &tn, const int row) const; + + /** + * @brief Determine if the note in questino should be counted as a lift. + * @param tn the note in question. + * @param row the row it lives in. + * @return true if it's a lift, false otherwise. */ + bool IsLift(const TapNote &tn, const int row) const; + + /** + * @brief Determine if the note in questino should be counted as a fake. + * @param tn the note in question. + * @param row the row it lives in. + * @return true if it's a fake, false otherwise. */ + bool IsFake(const TapNote &tn, const int row) const; + pair GetNumRowsWithSimultaneousTapsTwoPlayer(int minTaps = 2, + int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + public: void Init(); @@ -130,7 +169,8 @@ public: * @param iEndRow the ending point. * @param begin the eventual beginning point of the range. * @param end the eventual end point of the range. */ - void GetTapNoteRange( int iTrack, int iStartRow, int iEndRow, TrackMap::const_iterator &begin, TrackMap::const_iterator &end ) const; + void GetTapNoteRange(int iTrack, int iStartRow, int iEndRow, + TrackMap::const_iterator &begin, TrackMap::const_iterator &end ) const; /** * @brief Return a constant iterator range for [rowBegin,rowEnd). * @param iTrack the column to use. @@ -158,13 +198,17 @@ public: /* Return an iterator range include iStartRow to iEndRow. Extend the range to include * hold notes overlapping the boundary. */ - void GetTapNoteRangeInclusive( int iTrack, int iStartRow, int iEndRow, TrackMap::const_iterator &begin, TrackMap::const_iterator &end, bool bIncludeAdjacent=false ) const; - void GetTapNoteRangeInclusive( int iTrack, int iStartRow, int iEndRow, TrackMap::iterator &begin, TrackMap::iterator &end, bool bIncludeAdjacent=false ); + void GetTapNoteRangeInclusive(int iTrack, int iStartRow, int iEndRow, + TrackMap::const_iterator &begin, TrackMap::const_iterator &end, bool bIncludeAdjacent=false ) const; + void GetTapNoteRangeInclusive(int iTrack, int iStartRow, int iEndRow, + TrackMap::iterator &begin, TrackMap::iterator &end, bool bIncludeAdjacent=false ); /* Return an iterator range include iStartRow to iEndRow. Shrink the range to exclude * hold notes overlapping the boundary. */ - void GetTapNoteRangeExclusive( int iTrack, int iStartRow, int iEndRow, TrackMap::const_iterator &begin, TrackMap::const_iterator &end ) const; - void GetTapNoteRangeExclusive( int iTrack, int iStartRow, int iEndRow, TrackMap::iterator &begin, TrackMap::iterator &end ); + void GetTapNoteRangeExclusive(int iTrack, int iStartRow, int iEndRow, + TrackMap::const_iterator &begin, TrackMap::const_iterator &end ) const; + void GetTapNoteRangeExclusive(int iTrack, int iStartRow, int iEndRow, + TrackMap::iterator &begin, TrackMap::iterator &end ); /* Returns the row of the first TapNote on the track that has a row greater than rowInOut. */ @@ -175,7 +219,17 @@ public: void MoveTapNoteTrack( int dest, int src ); void SetTapNote( int track, int row, const TapNote& tn ); - void AddHoldNote( int iTrack, int iStartRow, int iEndRow, TapNote tn ); // add note hold note merging overlapping HoldNotes and destroying TapNotes underneath + /** + * @brief Add a hold note, merging other overlapping holds and destroying + * tap notes underneath. + * @param iTrack the column to work with. + * @param iStartRow the starting row. + * @param iEndRow the ending row. + * @param tn the tap note. */ + void AddHoldNote(int iTrack, + int iStartRow, + int iEndRow, + TapNote tn ); void ClearRangeForTrack( int rowBegin, int rowEnd, int iTrack ); void ClearRange( int rowBegin, int rowEnd ); @@ -222,7 +276,12 @@ public: // Count rows that contain iMinTaps or more taps. int GetNumRowsWithSimultaneousTaps( int iMinTaps, int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const; - int GetNumJumps( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const { return GetNumRowsWithSimultaneousTaps( 2, iStartIndex, iEndIndex ); } + int GetNumJumps( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const + { + return GetNumRowsWithSimultaneousTaps( 2, iStartIndex, iEndIndex ); + } + + // This row needs at least iMinSimultaneousPresses either tapped or held. bool RowNeedsAtLeastSimultaneousPresses( int iMinSimultaneousPresses, int row ) const; @@ -230,15 +289,51 @@ public: // Count rows that need iMinSimultaneousPresses either tapped or held. int GetNumRowsWithSimultaneousPresses( int iMinSimultaneousPresses, int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const; - int GetNumHands( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const { return GetNumRowsWithSimultaneousPresses( 3, iStartIndex, iEndIndex ); } - int GetNumQuads( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const { return GetNumRowsWithSimultaneousPresses( 4, iStartIndex, iEndIndex ); } + int GetNumHands( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const + { + return GetNumRowsWithSimultaneousPresses( 3, iStartIndex, iEndIndex ); + } + int GetNumQuads( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const + { + return GetNumRowsWithSimultaneousPresses( 4, iStartIndex, iEndIndex ); + } // and the other notetypes int GetNumLifts( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const; int GetNumFakes( int iStartIndex = 0, int iEndIndex = MAX_NOTE_ROW ) const; + // the couple/routine style variants of the above. + pair GetNumTapNotesTwoPlayer(int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + + pair GetNumJumpsTwoPlayer(int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + + pair GetNumHandsTwoPlayer(int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + + pair GetNumQuadsTwoPlayer(int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + + pair GetNumHoldNotesTwoPlayer(int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + + pair GetNumMinesTwoPlayer(int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + + pair GetNumRollsTwoPlayer(int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + + pair GetNumLiftsTwoPlayer(int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + + pair GetNumFakesTwoPlayer(int startRow = 0, + int endRow = MAX_NOTE_ROW) const; + // Transformations - void LoadTransformed( const NoteData& original, int iNewNumTracks, const int iOriginalTrackToTakeFrom[] ); // -1 for iOriginalTracksToTakeFrom means no track + void LoadTransformed(const NoteData& original, + int iNewNumTracks, + const int iOriginalTrackToTakeFrom[] ); // -1 for iOriginalTracksToTakeFrom means no track // XML XNode* CreateNode() const; diff --git a/src/NoteDataUtil.cpp b/src/NoteDataUtil.cpp index 022691c700..eff74fb0ae 100644 --- a/src/NoteDataUtil.cpp +++ b/src/NoteDataUtil.cpp @@ -778,13 +778,6 @@ void NoteDataUtil::LoadTransformedLightsFromTwo( const NoteData &marquee, const NoteDataUtil::RemoveMines( out ); } -struct RadarStats { - int taps; - int jumps; - int hands; - int quads; -}; - RadarStats CalculateRadarStatsFast( const NoteData &in, RadarStats &out ) { out.taps = 0; @@ -799,12 +792,18 @@ RadarStats CalculateRadarStatsFast( const NoteData &in, RadarStats &out ) { FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE( in, t, r, 0, MAX_NOTE_ROW ) { + /* This function deals strictly with taps, jumps, hands, and quads. + * As such, all rows in here have to be judgable. */ + if (!GAMESTATE->GetProcessedTimingData()->IsJudgableAtRow(r)) + continue; + const TapNote &tn = in.GetTapNote(t, r); switch( tn.type ) { case TapNote::mine: case TapNote::empty: case TapNote::fake: + case TapNote::autoKeysound: continue; // skip these types - they don't count } @@ -886,7 +885,7 @@ void NoteDataUtil::CalculateRadarValues( const NoteData &in, float fSongSeconds, case RadarCategory_Jumps: out[rc] = (float) stats.jumps; break; case RadarCategory_Holds: out[rc] = (float) in.GetNumHoldNotes(); break; case RadarCategory_Mines: out[rc] = (float) in.GetNumMines(); break; - case RadarCategory_Hands: out[rc] = (float) stats.hands; break; + case RadarCategory_Hands: out[rc] = (float) in.GetNumHands(); break; case RadarCategory_Rolls: out[rc] = (float) in.GetNumRolls(); break; case RadarCategory_Lifts: out[rc] = (float) in.GetNumLifts(); break; case RadarCategory_Fakes: out[rc] = (float) in.GetNumFakes(); break; diff --git a/src/NoteDataUtil.h b/src/NoteDataUtil.h index f92043c9ff..167d2955f7 100644 --- a/src/NoteDataUtil.h +++ b/src/NoteDataUtil.h @@ -10,6 +10,24 @@ class NoteData; class Song; struct AttackArray; +/** @brief A limited selection of the RadarValues. */ +struct RadarStats +{ + /** @brief The number of tap notes in the song. */ + int taps; + /** @brief The number of jumps in the song. */ + int jumps; + /** @brief The number of 3 panel hits in the song. */ + int hands; + /** @brief The number of 4 panel hits in the song. */ + int quads; +}; + +void PlaceAutoKeysound( NoteData &out, int row, TapNote akTap ); +int FindLongestOverlappingHoldNoteForAnyTrack( const NoteData &in, int iRow ); +void LightTransformHelper( const NoteData &in, NoteData &out, const vector &aiTracks ); +RadarStats CalculateRadarStatsFast( const NoteData &in, RadarStats &out ); + /** * @brief Utility functions that deal with NoteData. * diff --git a/src/NoteDataWithScoring.cpp b/src/NoteDataWithScoring.cpp index 06d1ebc88f..7a4113b213 100644 --- a/src/NoteDataWithScoring.cpp +++ b/src/NoteDataWithScoring.cpp @@ -349,7 +349,7 @@ void NoteDataWithScoring::GetActualRadarValues( const NoteData &in, const Player case RadarCategory_Hands: out[rc] = (float) GetSuccessfulHands( in ); break; case RadarCategory_Rolls: out[rc] = (float) GetNumHoldNotesWithScore( in, TapNote::hold_head_roll, HNS_Held ); break; case RadarCategory_Lifts: out[rc] = (float) GetSuccessfulLifts( in, TNS_W4 ); break; - case RadarCategory_Fakes: out[rc] = (float) in.GetNumLifts(); break; + case RadarCategory_Fakes: out[rc] = (float) in.GetNumFakes(); break; //case RadarCategory_Minefields: out[rc] = (float) GetNumMinefieldsWithScore( in, TapNote::hold_head_mine, HNS_Held ); break; DEFAULT_FAIL( rc ); } diff --git a/src/NoteDisplay.cpp b/src/NoteDisplay.cpp index a5c530bd73..d71b845198 100644 --- a/src/NoteDisplay.cpp +++ b/src/NoteDisplay.cpp @@ -46,6 +46,8 @@ static const NoteType MAX_DISPLAY_NOTE_TYPE = (NoteType)7; struct NoteMetricCache_t { bool m_bDrawHoldHeadForTapsOnSameRow; + bool m_bDrawRollHeadForTapsOnSameRow; + bool m_bTapHoldRollOnRowMeansHold; float m_fAnimationLength[NUM_NotePart]; bool m_bAnimationIsVivid[NUM_NotePart]; RageVector2 m_fAdditionTextureCoordOffset[NUM_NotePart]; @@ -69,6 +71,8 @@ struct NoteMetricCache_t void NoteMetricCache_t::Load( const RString &sButton ) { m_bDrawHoldHeadForTapsOnSameRow = NOTESKIN->GetMetricB(sButton,"DrawHoldHeadForTapsOnSameRow"); + m_bDrawRollHeadForTapsOnSameRow = NOTESKIN->GetMetricB(sButton,"DrawRollHeadForTapsOnSameRow"); + m_bTapHoldRollOnRowMeansHold = NOTESKIN->GetMetricB(sButton,"TapHoldRollOnRowMeansHold"); FOREACH_NotePart( p ) { const RString &s = NotePartToString(p); @@ -271,6 +275,11 @@ bool NoteDisplay::DrawHoldHeadForTapsOnSameRow() const return cache->m_bDrawHoldHeadForTapsOnSameRow; } +bool NoteDisplay::DrawRollHeadForTapsOnSameRow() const +{ + return cache->m_bDrawRollHeadForTapsOnSameRow; +} + void NoteDisplay::Update( float fDeltaTime ) { /* This function is static: it's called once per game loop, not once per @@ -683,11 +692,18 @@ void NoteDisplay::DrawActor( const TapNote& tn, Actor* pActor, NotePart part, in const float fGlow = ArrowEffects::GetGlow( m_pPlayerState, iCol, fYOffset, fPercentFadeToFail, m_fYReverseOffsetPixels, fDrawDistanceBeforeTargetsPixels, fFadeInPercentOfDrawFar ); const RageColor diffuse = RageColor(fColorScale,fColorScale,fColorScale,fAlpha); const RageColor glow = RageColor(1,1,1,fGlow); - float fRotationX = 0, fRotationY = 0, fRotationZ = 0; + float fRotationX = 0, fRotationZ = 0; + const float fRotationY = ArrowEffects::GetRotationY( m_pPlayerState, fYOffset ); + + bool bIsHoldHead = tn.type == tn.hold_head; + bool bIsHoldCap = bIsHoldHead || tn.type == tn.hold_tail; + + fRotationZ = ArrowEffects::GetRotationZ( m_pPlayerState, fBeat, bIsHoldHead ); + if( !bIsHoldCap ) + { + fRotationX = ArrowEffects::GetRotationX( m_pPlayerState, fYOffset ); + } - fRotationX = ArrowEffects::GetRotationX( m_pPlayerState, fYOffset ); - fRotationY = ArrowEffects::GetRotationY( m_pPlayerState, fYOffset ); - fRotationZ = ArrowEffects::GetRotationZ( m_pPlayerState, fBeat, tn.type == tn.hold_head ); if( tn.type != tn.hold_head ) fColorScale *= ArrowEffects::GetBrightness( m_pPlayerState, fBeat ); @@ -718,7 +734,13 @@ void NoteDisplay::DrawActor( const TapNote& tn, Actor* pActor, NotePart part, in } } -void NoteDisplay::DrawTap( const TapNote& tn, int iCol, float fBeat, bool bOnSameRowAsHoldStart, bool bIsAddition, float fPercentFadeToFail, float fReverseOffsetPixels, float fDrawDistanceAfterTargetsPixels, float fDrawDistanceBeforeTargetsPixels, float fFadeInPercentOfDrawFar ) +void NoteDisplay::DrawTap(const TapNote& tn, int iCol, float fBeat, + bool bOnSameRowAsHoldStart, bool bOnSameRowAsRollStart, + bool bIsAddition, float fPercentFadeToFail, + float fReverseOffsetPixels, + float fDrawDistanceAfterTargetsPixels, + float fDrawDistanceBeforeTargetsPixels, + float fFadeInPercentOfDrawFar) { Actor* pActor = NULL; NotePart part = NotePart_Tap; @@ -738,10 +760,40 @@ void NoteDisplay::DrawTap( const TapNote& tn, int iCol, float fBeat, bool bOnSam pActor = GetTapActor( m_TapFake, NotePart_Fake, fBeat ); part = NotePart_Fake; } + // TODO: Simplify all of the below. + else if (bOnSameRowAsHoldStart && bOnSameRowAsRollStart) + { + if (cache->m_bDrawHoldHeadForTapsOnSameRow && cache->m_bDrawRollHeadForTapsOnSameRow) + { + if (cache->m_bTapHoldRollOnRowMeansHold) // another new metric? + { + pActor = GetHoldActor( m_HoldHead, NotePart_HoldHead, fBeat, false, false ); + } + else + { + pActor = GetHoldActor( m_HoldHead, NotePart_HoldHead, fBeat, true, false ); + } + } + else if (cache->m_bDrawHoldHeadForTapsOnSameRow) + { + pActor = GetHoldActor( m_HoldHead, NotePart_HoldHead, fBeat, false, false ); + } + else if (cache->m_bDrawRollHeadForTapsOnSameRow) + { + pActor = GetHoldActor( m_HoldHead, NotePart_HoldHead, fBeat, true, false ); + } + } + else if( bOnSameRowAsHoldStart && cache->m_bDrawHoldHeadForTapsOnSameRow ) { pActor = GetHoldActor( m_HoldHead, NotePart_HoldHead, fBeat, false, false ); } + + else if( bOnSameRowAsRollStart && cache->m_bDrawRollHeadForTapsOnSameRow ) + { + pActor = GetHoldActor( m_HoldHead, NotePart_HoldHead, fBeat, true, false ); + } + else { pActor = GetTapActor( m_TapNote, NotePart_Tap, fBeat ); diff --git a/src/NoteDisplay.h b/src/NoteDisplay.h index 8f79041e17..a7e45f3f62 100644 --- a/src/NoteDisplay.h +++ b/src/NoteDisplay.h @@ -80,13 +80,33 @@ public: static void Update( float fDeltaTime ); - void DrawTap( const TapNote& tn, int iCol, float fBeat, bool bOnSameRowAsHoldStart, bool bIsAddition, - float fPercentFadeToFail, float fReverseOffsetPixels, float fDrawDistanceAfterTargetsPixels, float fDrawDistanceBeforeTargetsPixels, float fFadeInPercentOfDrawFar ); + /** + * @brief Draw the TapNote onto the NoteField. + * @param tn the TapNote in question. + * @param iCol the column. + * @param float fBeat the beat to draw them on. + * @param bOnSameRowAsHoldStart a flag to see if a hold is on the same beat. + * @param bOnSameRowAsRollStart a flag to see if a roll is on the same beat. + * @param bIsAddition a flag to see if this note was added via mods. + * @param fPercentFadeToFail at what point do the notes fade on failure? + * @param fReverseOffsetPixels How are the notes adjusted on Reverse? + * @param fDrawDistanceAfterTargetsPixels how much to draw after the receptors. + * @param fDrawDistanceBeforeTargetsPixels how much ot draw before the receptors. + * @param fFadeInPercentOfDrawFar when to start fading in. */ + void DrawTap(const TapNote& tn, int iCol, float fBeat, + bool bOnSameRowAsHoldStart, bool bOnSameRowAsRollBeat, + bool bIsAddition, float fPercentFadeToFail, + float fReverseOffsetPixels, + float fDrawDistanceAfterTargetsPixels, + float fDrawDistanceBeforeTargetsPixels, + float fFadeInPercentOfDrawFar ); void DrawHold( const TapNote& tn, int iCol, int iRow, bool bIsBeingHeld, const HoldNoteResult &Result, bool bIsAddition, float fPercentFadeToFail, float fReverseOffsetPixels, float fDrawDistanceAfterTargetsPixels, float fDrawDistanceBeforeTargetsPixels, float fDrawDistanceBeforeTargetsPixels2, float fFadeInPercentOfDrawFar ); bool DrawHoldHeadForTapsOnSameRow() const; + + bool DrawRollHeadForTapsOnSameRow() const; private: void SetActiveFrame( float fNoteBeat, Actor &actorToSet, float fAnimationLength, bool bVivid ); diff --git a/src/NoteField.cpp b/src/NoteField.cpp index 60b0d9b6be..e45ab8325a 100644 --- a/src/NoteField.cpp +++ b/src/NoteField.cpp @@ -20,6 +20,9 @@ #include "Course.h" #include "NoteData.h" +float FindFirstDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistanceAfterTargetsPixels ); +float FindLastDisplayedBeat( const PlayerState* pPlayerState, int iDrawDistanceBeforeTargetsPixels ); + static ThemeMetric SHOW_BOARD( "NoteField", "ShowBoard" ); static ThemeMetric SHOW_BEAT_BARS( "NoteField", "ShowBeatBars" ); static ThemeMetric FADE_BEFORE_TARGETS_PERCENT( "NoteField", "FadeBeforeTargetsPercent" ); @@ -208,10 +211,10 @@ void NoteField::Load( //int i1 = m_pNoteData->GetNumTracks(); //int i2 = GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer; - - ASSERT_M( m_pNoteData->GetNumTracks() == GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer, - ssprintf("NumTracks %d = ColsPerPlayer %d",m_pNoteData->GetNumTracks(), GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer) ); - + ASSERT_M(m_pNoteData->GetNumTracks() == GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer, + ssprintf("NumTracks %d = ColsPerPlayer %d",m_pNoteData->GetNumTracks(), + GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer)); + // The NoteSkin may have changed at the beginning of a new course song. RString sNoteSkinLower = m_pPlayerState->m_PlayerOptions.GetCurrent().m_sNoteSkin; @@ -303,7 +306,7 @@ void NoteField::Update( float fDeltaTime ) // TODO: Remove use of PlayerNumber. PlayerNumber pn = m_pPlayerState->m_PlayerNumber; - if( pn == GAMESTATE->m_MasterPlayerNumber ) + if( pn == GAMESTATE->GetMasterPlayerNumber() ) NoteDisplay::Update( fDeltaTime ); } @@ -574,7 +577,7 @@ void NoteField::DrawTickcountText( const float fBeat, int iTicks ) m_textMeasureNumber.Draw(); } -void NoteField::DrawComboText( const float fBeat, int iCombo ) +void NoteField::DrawComboText( const float fBeat, int iCombo, int iMiss ) { const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat ); const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels ); @@ -586,7 +589,7 @@ void NoteField::DrawComboText( const float fBeat, int iCombo ) m_textMeasureNumber.SetHorizAlign( COMBO_IS_LEFT_SIDE ? align_right : align_left ); m_textMeasureNumber.SetDiffuse( COMBO_COLOR ); m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) ); - m_textMeasureNumber.SetText( ssprintf("%d", iCombo) ); + m_textMeasureNumber.SetText( ssprintf("%d/%d", iCombo, iMiss) ); m_textMeasureNumber.SetXY( (COMBO_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos ); m_textMeasureNumber.Draw(); } @@ -814,7 +817,7 @@ void NoteField::DrawPrimitives() float fDrawScale = 1; fDrawScale *= 1 + 0.5f * fabsf( current_po.m_fPerspectiveTilt ); - fDrawScale *= 1 + fabsf( current_po.m_fEffects[PlayerOptions::EFFECT_TINY] ); + fDrawScale *= 1 + fabsf( current_po.m_fEffects[PlayerOptions::EFFECT_MINI] ); iDrawDistanceAfterTargetsPixels = (int)(iDrawDistanceAfterTargetsPixels * fDrawScale); iDrawDistanceBeforeTargetsPixels = (int)(iDrawDistanceBeforeTargetsPixels * fDrawScale); @@ -846,27 +849,26 @@ void NoteField::DrawPrimitives() } const TimingData *pTiming = GetDisplayedTiming(m_pPlayerState); - + const vector *segs = pTiming->allTimingSegments; + unsigned i = 0; // Draw beat bars if( ( GAMESTATE->IsEditing() || SHOW_BEAT_BARS ) && pTiming != NULL ) { - const TimingData &timing = *pTiming; - const vector &vTimeSignatureSegments = timing.m_vTimeSignatureSegments; + const vector &tSigs = segs[SEGMENT_TIME_SIG]; int iMeasureIndex = 0; - FOREACH_CONST( TimeSignatureSegment, vTimeSignatureSegments, iter ) + for (i = 0; i < tSigs.size(); i++) { - vector::const_iterator next = iter; - next++; - int iSegmentEndRow = (next == vTimeSignatureSegments.end()) ? iLastRowToDraw : next->GetRow(); - + TimeSignatureSegment *ts = static_cast(tSigs[i]); + int iSegmentEndRow = (i + 1 == tSigs.size()) ? iLastRowToDraw : tSigs[i+1]->GetRow(); + // beat bars every 16th note - int iDrawBeatBarsEveryRows = BeatToNoteRow( ((float)iter->GetDen()) / 4 ) / 4; + int iDrawBeatBarsEveryRows = BeatToNoteRow( ((float)ts->GetDen()) / 4 ) / 4; // In 4/4, every 16th beat bar is a measure - int iMeasureBarFrequency = iter->GetNum() * 4; + int iMeasureBarFrequency = ts->GetNum() * 4; int iBeatBarsDrawn = 0; - for( int i=iter->GetRow(); i < iSegmentEndRow; i += iDrawBeatBarsEveryRows ) + for( int j=ts->GetRow(); j < iSegmentEndRow; j += iDrawBeatBarsEveryRows ) { bool bMeasureBar = iBeatBarsDrawn % iMeasureBarFrequency == 0; BeatBarType type = quarter_beat; @@ -876,7 +878,7 @@ void NoteField::DrawPrimitives() type = beat; else if( iBeatBarsDrawn % 2 == 0 ) type = half_beat; - float fBeat = NoteRowToBeat(i); + float fBeat = NoteRowToBeat(j); if( IS_ON_SCREEN(fBeat) ) { @@ -899,8 +901,9 @@ void NoteField::DrawPrimitives() // Scroll text if( GAMESTATE->m_bIsUsingStepTiming ) { - FOREACH_CONST( ScrollSegment, timing.m_ScrollSegments, seg ) + for (i = 0; i < segs[SEGMENT_SCROLL].size(); i++) { + ScrollSegment *seg = static_cast(segs[SEGMENT_SCROLL][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); @@ -911,8 +914,9 @@ void NoteField::DrawPrimitives() } // BPM text - FOREACH_CONST( BPMSegment, timing.m_BPMSegments, seg ) + for (i = 0; i < segs[SEGMENT_BPM].size(); i++) { + BPMSegment *seg = static_cast(segs[SEGMENT_BPM][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); @@ -922,8 +926,9 @@ void NoteField::DrawPrimitives() } // Freeze text - FOREACH_CONST( StopSegment, timing.m_StopSegments, seg ) + for (i = 0; i < segs[SEGMENT_STOP_DELAY].size(); i++) { + StopSegment *seg = static_cast(segs[SEGMENT_STOP_DELAY][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); @@ -933,8 +938,9 @@ void NoteField::DrawPrimitives() } // Warp text - FOREACH_CONST( WarpSegment, timing.m_WarpSegments, seg ) + for (i = 0; i < segs[SEGMENT_WARP].size(); i++) { + WarpSegment *seg = static_cast(segs[SEGMENT_WARP][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); @@ -945,8 +951,9 @@ void NoteField::DrawPrimitives() // Time Signature text - FOREACH_CONST( TimeSignatureSegment, timing.m_vTimeSignatureSegments, seg ) + for (i = 0; i < segs[SEGMENT_TIME_SIG].size(); i++) { + TimeSignatureSegment *seg = static_cast(segs[SEGMENT_TIME_SIG][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); @@ -958,8 +965,9 @@ void NoteField::DrawPrimitives() if( GAMESTATE->m_bIsUsingStepTiming ) { // Tickcount text - FOREACH_CONST( TickcountSegment, timing.m_TickcountSegments, seg ) + for (i = 0; i < segs[SEGMENT_TICKCOUNT].size(); i++) { + TickcountSegment *seg = static_cast(segs[SEGMENT_TICKCOUNT][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); @@ -972,20 +980,22 @@ void NoteField::DrawPrimitives() if( GAMESTATE->m_bIsUsingStepTiming ) { // Combo text - FOREACH_CONST( ComboSegment, timing.m_ComboSegments, seg ) + for (i = 0; i < segs[SEGMENT_COMBO].size(); i++) { + ComboSegment *seg = static_cast(segs[SEGMENT_COMBO][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); if( IS_ON_SCREEN(fBeat) ) - DrawComboText( fBeat, seg->GetCombo() ); + DrawComboText( fBeat, seg->GetCombo(), seg->GetMissCombo() ); } } } // Label text - FOREACH_CONST( LabelSegment, timing.m_LabelSegments, seg ) + for (i = 0; i < segs[SEGMENT_LABEL].size(); i++) { + LabelSegment *seg = static_cast(segs[SEGMENT_LABEL][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); @@ -996,8 +1006,10 @@ void NoteField::DrawPrimitives() if( GAMESTATE->m_bIsUsingStepTiming ) { - FOREACH_CONST( SpeedSegment, timing.m_SpeedSegments, seg ) + // Speed text + for (i = 0; i < segs[SEGMENT_SPEED].size(); i++) { + SpeedSegment *seg = static_cast(segs[SEGMENT_SPEED][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); @@ -1008,11 +1020,12 @@ void NoteField::DrawPrimitives() } } - // Speed text + // Fake text if( GAMESTATE->m_bIsUsingStepTiming ) { - FOREACH_CONST( FakeSegment, timing.m_FakeSegments, seg ) + for (i = 0; i < segs[SEGMENT_FAKE].size(); i++) { + FakeSegment *seg = static_cast(segs[SEGMENT_FAKE][i]); if( seg->GetRow() >= iFirstRowToDraw && seg->GetRow() <= iLastRowToDraw ) { float fBeat = seg->GetBeat(); @@ -1042,6 +1055,22 @@ void NoteField::DrawPrimitives() } } } + else + { + AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ? + GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks : + GAMESTATE->m_pCurSong->m_Attacks; + FOREACH_CONST(Attack, attacks, a) + { + float fBeat = timing.GetBeatFromElapsedTime(a->fStartSecond); + if (BeatToNoteRow(fBeat) >= iFirstRowToDraw && + BeatToNoteRow(fBeat) <= iLastRowToDraw && + IS_ON_SCREEN(fBeat)) + { + this->DrawAttackText(fBeat, *a); + } + } + } if( !GAMESTATE->m_bIsUsingStepTiming ) { @@ -1055,55 +1084,55 @@ void NoteField::DrawPrimitives() case EditMode_Full: { vector::iterator iter[NUM_BackgroundLayer]; - FOREACH_BackgroundLayer( i ) - iter[i] = GAMESTATE->m_pCurSong->GetBackgroundChanges(i).begin(); + FOREACH_BackgroundLayer( j ) + iter[j] = GAMESTATE->m_pCurSong->GetBackgroundChanges(j).begin(); while( 1 ) { float fLowestBeat = FLT_MAX; vector viLowestIndex; - FOREACH_BackgroundLayer( i ) + FOREACH_BackgroundLayer( j ) { - if( iter[i] == GAMESTATE->m_pCurSong->GetBackgroundChanges(i).end() ) + if( iter[j] == GAMESTATE->m_pCurSong->GetBackgroundChanges(j).end() ) continue; - float fBeat = iter[i]->m_fStartBeat; + float fBeat = iter[j]->m_fStartBeat; if( fBeat < fLowestBeat ) { fLowestBeat = fBeat; viLowestIndex.clear(); - viLowestIndex.push_back( i ); + viLowestIndex.push_back( j ); } else if( fBeat == fLowestBeat ) { - viLowestIndex.push_back( i ); + viLowestIndex.push_back( j ); } } if( viLowestIndex.empty() ) { - FOREACH_BackgroundLayer( i ) - ASSERT( iter[i] == GAMESTATE->m_pCurSong->GetBackgroundChanges(i).end() ); + FOREACH_BackgroundLayer( j ) + ASSERT( iter[j] == GAMESTATE->m_pCurSong->GetBackgroundChanges(j).end() ); break; } if( IS_ON_SCREEN(fLowestBeat) ) { vector vsBGChanges; - FOREACH_CONST( BackgroundLayer, viLowestIndex, i ) + FOREACH_CONST( BackgroundLayer, viLowestIndex, bl ) { - ASSERT( iter[*i] != GAMESTATE->m_pCurSong->GetBackgroundChanges(*i).end() ); - const BackgroundChange& change = *iter[*i]; + ASSERT( iter[*bl] != GAMESTATE->m_pCurSong->GetBackgroundChanges(*bl).end() ); + const BackgroundChange& change = *iter[*bl]; RString s = change.GetTextDescription(); - if( *i!=0 ) - s = ssprintf("%d: ",*i) + s; + if( *bl!=0 ) + s = ssprintf("%d: ",*bl) + s; vsBGChanges.push_back( s ); } DrawBGChangeText( fLowestBeat, join("\n",vsBGChanges) ); } - FOREACH_CONST( BackgroundLayer, viLowestIndex, i ) - iter[*i]++; + FOREACH_CONST( BackgroundLayer, viLowestIndex, bl ) + iter[*bl]++; } } break; @@ -1143,11 +1172,13 @@ void NoteField::DrawPrimitives() float fSelectedRangeGlow = SCALE( RageFastCos(RageTimer::GetTimeSinceStartFast()*2), -1, 1, 0.1f, 0.3f ); const Style* pStyle = GAMESTATE->GetCurrentStyle(); - ASSERT( GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer == m_pNoteData->GetNumTracks() ); + ASSERT_M(m_pNoteData->GetNumTracks() == GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer, + ssprintf("NumTracks %d = ColsPerPlayer %d",m_pNoteData->GetNumTracks(), + GAMESTATE->GetCurrentStyle()->m_iColsPerPlayer)); - for( int i=0; iGetNumTracks(); i++ ) // for each arrow column + for( int j=0; jGetNumTracks(); j++ ) // for each arrow column { - const int c = pStyle->m_iColumnDrawOrder[i]; + const int c = pStyle->m_iColumnDrawOrder[j]; bool bAnyUpcomingInThisCol = false; @@ -1158,7 +1189,7 @@ void NoteField::DrawPrimitives() for( ; begin != end; ++begin ) { - const TapNote &tn = begin->second; //m_pNoteData->GetTapNote(c, i); + const TapNote &tn = begin->second; //m_pNoteData->GetTapNote(c, j); if( tn.type != TapNote::hold_head ) continue; // skip @@ -1257,13 +1288,31 @@ void NoteField::DrawPrimitives() { for( int c2=0; c2GetNumTracks(); c2++ ) { - if( m_pNoteData->GetTapNote(c2, q).type == TapNote::hold_head) + const TapNote &tmp = m_pNoteData->GetTapNote(c2, q); + if(tmp.type == TapNote::hold_head && + tmp.subType == TapNote::hold_head_hold) { bHoldNoteBeginsOnThisBeat = true; break; } } } + + // do the same for a roll. + bool bRollNoteBeginsOnThisBeat = false; + if (m_pCurDisplay->display[c].DrawRollHeadForTapsOnSameRow() ) + { + for( int c2=0; c2GetNumTracks(); c2++ ) + { + const TapNote &tmp = m_pNoteData->GetTapNote(c2, q); + if(tmp.type == TapNote::hold_head && + tmp.subType == TapNote::hold_head_roll) + { + bRollNoteBeginsOnThisBeat = true; + break; + } + } + } bool bIsInSelectionRange = false; if( m_iBeginMarker!=-1 && m_iEndMarker!=-1 ) @@ -1273,7 +1322,8 @@ void NoteField::DrawPrimitives() bool bIsHopoPossible = (tn.bHopoPossible); bool bUseAdditionColoring = bIsAddition || bIsHopoPossible; NoteDisplayCols *displayCols = tn.pn == PLAYER_INVALID ? m_pCurDisplay : m_pDisplays[tn.pn]; - displayCols->display[c].DrawTap( tn, c, NoteRowToVisibleBeat(m_pPlayerState, q), bHoldNoteBeginsOnThisBeat, + displayCols->display[c].DrawTap(tn, c, NoteRowToVisibleBeat(m_pPlayerState, q), + bHoldNoteBeginsOnThisBeat, bRollNoteBeginsOnThisBeat, bUseAdditionColoring, bIsInSelectionRange ? fSelectedRangeGlow : m_fPercentFadeToFail, m_fYReverseOffsetPixels, iDrawDistanceAfterTargetsPixels, iDrawDistanceBeforeTargetsPixels, FADE_BEFORE_TARGETS_PERCENT ); diff --git a/src/NoteField.h b/src/NoteField.h index 3357eff284..2deb044350 100644 --- a/src/NoteField.h +++ b/src/NoteField.h @@ -62,7 +62,7 @@ protected: void DrawWarpText( const float fBeat, const float fNewBeat ); void DrawTimeSignatureText( const float fBeat, int iNumerator, int iDenominator ); void DrawTickcountText( const float fBeat, int iTicks ); - void DrawComboText( const float fBeat, int iCombo ); + void DrawComboText( const float fBeat, int iCombo, int iMiss ); void DrawLabelText( const float fBeat, RString sLabel ); void DrawSpeedText( const float fBeat, float fPercent, float fWait, unsigned short usMode ); void DrawScrollText( const float fBeat, float fPercent ); diff --git a/src/NoteSkinManager.cpp b/src/NoteSkinManager.cpp index d56062e0df..562629346f 100644 --- a/src/NoteSkinManager.cpp +++ b/src/NoteSkinManager.cpp @@ -200,7 +200,7 @@ bool NoteSkinManager::DoesNoteSkinExist( const RString &sSkinName ) vector asSkinNames; GetAllNoteSkinNamesForGame( GAMESTATE->m_pCurGame, asSkinNames ); for( unsigned i=0; i TapNote::fake ) { - LOG->Trace(ssprintf("Invalid tap note type %d (most likely) due to random vanish issues. Assume it doesn't need judging.", type_ ) ); + LOG->Trace("Invalid tap note type %d (most likely) due to random vanish issues. Assume it doesn't need judging.", (int)type_ ); type = TapNote::empty; } } @@ -334,7 +334,23 @@ static inline float ToBeat(int row) { return NoteRowToBeat(row); } */ static inline float ToBeat(float beat) { return beat; } - +/** + * @brief Scales the position. + * @param T start - the starting row of the scaling region + * @param T length - the length of the scaling region + * @param T newLength - the new length of the scaling region + * @param T position - the position to scale + * @return T the scaled position + */ +template +inline T ScalePosition( T start, T length, T newLength, T position ) +{ + if( position < start ) + return position; + if( position >= start + length ) + return position - length + newLength; + return start + (position - start) * newLength / length; +} #endif diff --git a/src/NotesLoader.cpp b/src/NotesLoader.cpp index 88f68787aa..983f35cedb 100644 --- a/src/NotesLoader.cpp +++ b/src/NotesLoader.cpp @@ -32,20 +32,23 @@ bool NotesLoader::LoadFromDir( const RString &sPath, Song &out, set &Bl vector list; BlacklistedImages.clear(); - SSCLoader::GetApplicableFiles( sPath, list ); + SSCLoader loaderSSC; + loaderSSC.GetApplicableFiles( sPath, list ); if( !list.empty() ) { - if( !SSCLoader::LoadFromDir( sPath, out ) ) + if( !loaderSSC.LoadFromDir( sPath, out ) ) return false; - SSCLoader::TidyUpData( out, false ); + loaderSSC.TidyUpData( out, false ); return true; } - SMALoader::GetApplicableFiles( sPath, list ); + SMALoader loaderSMA; + loaderSMA.GetApplicableFiles( sPath, list ); if (!list.empty() ) - return SMALoader::LoadFromDir( sPath, out ); - SMLoader::GetApplicableFiles( sPath, list ); + return loaderSMA.LoadFromDir( sPath, out ); + SMLoader loaderSM; + loaderSM.GetApplicableFiles( sPath, list ); if (!list.empty() ) - return SMLoader::LoadFromDir( sPath, out ); + return loaderSM.LoadFromDir( sPath, out ); DWILoader::GetApplicableFiles( sPath, list ); if( !list.empty() ) return DWILoader::LoadFromDir( sPath, out, BlacklistedImages ); diff --git a/src/NotesLoaderBMS.cpp b/src/NotesLoaderBMS.cpp index e7adf6d5a2..fdaf8ea92c 100644 --- a/src/NotesLoaderBMS.cpp +++ b/src/NotesLoaderBMS.cpp @@ -459,13 +459,16 @@ static bool SearchForKeysound( const RString &sPath, RString nDataOriginal, map< * Do a search. Don't do a wildcard search; if sData is "song.wav", * we might also have "song.png", which we shouldn't match. */ RString nData = nDataOriginal; - if( !IsAFile(out.GetSongDir()+nData) ) + RString dir = out.GetSongDir(); + if (dir.empty()) + dir = Dirname(sPath); + if( !IsAFile(dir+nData) ) { const char *exts[] = { "oga", "ogg", "wav", "mp3", NULL }; // XXX: stop duplicating these everywhere for( unsigned i = 0; exts[i] != NULL; ++i ) { RString fn = SetExtension( nData, exts[i] ); - if( IsAFile(out.GetSongDir()+fn) ) + if( IsAFile(dir+fn) ) { nData = fn; break; @@ -473,9 +476,9 @@ static bool SearchForKeysound( const RString &sPath, RString nDataOriginal, map< } } - if( !IsAFile(out.GetSongDir()+nData) ) + if( !IsAFile(dir+nData) ) { - LOG->UserLog( "Song file", out.GetSongDir(), "references key \"%s\" that can't be found", nData.c_str() ); + LOG->UserLog( "Song file", dir, "references key \"%s\" that can't be found", nData.c_str() ); return false; } @@ -548,6 +551,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo { map mapIdToKeysoundIndex; + map mapNoteRowToBPM; MeasureToTimeSig_t sigAdjustments; LOG->Trace( "Steps::LoadFromBMSFile( '%s' )", sPath.c_str() ); @@ -572,8 +576,8 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo if( fBPM > 0.0f ) { - BPMSegment newSeg( 0, fBPM ); - out.m_Timing.AddBPMSegment( newSeg ); + BPMSegment * newSeg = new BPMSegment( 0, fBPM ); + out.m_Timing.AddSegment(SEGMENT_BPM, newSeg ); LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM ); } else @@ -622,7 +626,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo case BMS_TRACK_BPM: if( iVal > 0 ) { - out.m_Timing.SetBPMAtBeat( fBeat, (float) iVal ); + mapNoteRowToBPM[ BeatToNoteRow(fBeat) ] = iVal; LOG->Trace( "Inserting new BPM change at beat %f, BPM %i", fBeat, iVal ); } else @@ -639,7 +643,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo if( GetTagFromMap( mapNameToData, sTagToLookFor, sBPM ) ) { float fBPM = StringToFloat( sBPM ); - out.m_Timing.SetBPMAtBeat( fBeat, fBPM ); + mapNoteRowToBPM[ BeatToNoteRow(fBeat) ] = fBPM; } else { @@ -662,9 +666,9 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo float fBeats = StringToFloat( sBeats ) / 48.0f; float fFreezeSecs = fBeats / fBPS; - StopSegment newSeg( BeatToNoteRow(fBeat), fFreezeSecs ); - out.m_Timing.AddStopSegment( newSeg ); - LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg.GetPause() ); + StopSegment * newSeg = new StopSegment( fBeat, fFreezeSecs ); + out.m_Timing.AddSegment( SEGMENT_STOP_DELAY, newSeg ); + LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg->GetPause() ); } else { @@ -676,6 +680,11 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo } } + + for( map::iterator it = mapNoteRowToBPM.begin(); it != mapNoteRowToBPM.end(); it ++ ) + { + out.m_Timing.SetBPMAtRow( it->first, it->second ); + } // Now that we're done reading BPMs, factor out weird time signatures. SetTimeSigAdjustments( mapMeasureToTimeSig, outSong, sigAdjustments ); @@ -690,6 +699,8 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo } NameToData_t::const_iterator it; + + bool hasBGM = false; for( it = mapNameToData.lower_bound("#00000"); it != mapNameToData.end(); ++it ) { const RString &sName = it->first; @@ -739,6 +750,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo { if( bmsTrack == BMS_AUTO_KEYSOUND_1 ) { + hasBGM = true; // shift the auto keysound as far right as possible int iLastEmptyTrack = -1; if( ndNotes.GetTapLastEmptyTrack(row, iLastEmptyTrack) && @@ -766,6 +778,12 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo } } + if (!hasBGM) + { + LOG->Warn("The song at %s is missing a #XXX01 tag! We're unable to load.", sPath.c_str()); + return false; + } + /* Handles hold notes like uBMPlay. * Different BMS simulators support hold notes differently. * See http://nvyu.net/rdm/ex.php for more info. @@ -958,7 +976,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo iTransformNewToOld[15] = BMS_P2_TURN; break; default: - ASSERT(0); + ASSERT_M(0, ssprintf("Invalid StepsType when parsing BMS file %s!", sPath.c_str())); } // shift all of the autokeysound tracks onto the main tracks @@ -984,7 +1002,7 @@ static bool LoadFromBMSFile( const RString &sPath, const NameToData_t &mapNameTo } else { - LOG->UserLog( "Song file", sPath, "has too much simultenous autokeysound tracks." ); + LOG->UserLog( "Song file", sPath, "has too much simultaneous autokeysound tracks." ); } } } @@ -1052,6 +1070,75 @@ void BMSLoader::GetApplicableFiles( const RString &sPath, vector &out ) GetDirListing( sPath + RString("*.bml"), out ); } +bool BMSLoader::LoadNoteDataFromSimfile( const RString & cachePath, Steps & out ) +{ + Song dummy; + // TODO: Simplify this copy/paste from LoadFromDir. + + vector BMSData; + BMSData.push_back(NameToData_t()); + ReadBMSFile(cachePath, BMSData.back()); + + RString commonSubstring; + GetCommonTagFromMapList( BMSData, "#title", commonSubstring ); + + Steps *copy = dummy.CreateSteps(); + + copy->SetDifficulty( Difficulty_Medium ); + RString sTag; + if( GetTagFromMap( BMSData[0], "#title", sTag ) && sTag.size() != commonSubstring.size() ) + { + sTag = sTag.substr( commonSubstring.size(), sTag.size() - commonSubstring.size() ); + sTag.MakeLower(); + + if( sTag.find('l') != sTag.npos ) + { + unsigned lPos = sTag.find('l'); + if( lPos > 2 && sTag.substr(lPos-2,4) == "solo" ) + { + copy->SetDifficulty( Difficulty_Edit ); + } + else + { + copy->SetDifficulty( Difficulty_Easy ); + } + } + else if( sTag.find('a') != sTag.npos ) + copy->SetDifficulty( Difficulty_Hard ); + else if( sTag.find('b') != sTag.npos ) + copy->SetDifficulty( Difficulty_Beginner ); + } + if( commonSubstring == "" ) + { + copy->SetDifficulty(Difficulty_Medium); + RString sTag; + if (GetTagFromMap(BMSData[0], "#title#", sTag)) + SearchForDifficulty(sTag, copy); + } + ReadGlobalTags( BMSData[0], dummy ); + if( commonSubstring.size() > 2 && commonSubstring[commonSubstring.size() - 2] == ' ' ) + { + switch( commonSubstring[commonSubstring.size() - 1] ) + { + case '[': + case '(': + case '<': + commonSubstring = commonSubstring.substr(0, commonSubstring.size() - 2); + default: + break; + } + } + map mapFilenameToKeysoundIndex; + + + const bool ok = LoadFromBMSFile( cachePath, BMSData[0], *copy, dummy, mapFilenameToKeysoundIndex ); + if( ok ) + { + out.SetNoteData(copy->GetNoteData()); + } + return ok; +} + bool BMSLoader::LoadFromDir( const RString &sDir, Song &out ) { LOG->Trace( "Song::LoadFromBMSDir(%s)", sDir.c_str() ); @@ -1156,6 +1243,7 @@ bool BMSLoader::LoadFromDir( const RString &sDir, Song &out ) iMainDataIndex = i; ReadGlobalTags( aBMSData[iMainDataIndex], out ); + out.m_sSongFileName = out.GetSongDir() + arrayBMSFileNames[iMainDataIndex]; // The brackets before the difficulty are in common substring, so remove them if it's found. if( commonSubstring.size() > 2 && commonSubstring[commonSubstring.size() - 2] == ' ' ) @@ -1188,6 +1276,7 @@ bool BMSLoader::LoadFromDir( const RString &sDir, Song &out ) if( i == static_cast(iMainDataIndex) ) out.m_SongTiming = pNewNotes->m_Timing; + pNewNotes->SetFilename(out.GetSongDir() + arrayBMSFileNames[i]); out.AddSteps( pNewNotes ); } else diff --git a/src/NotesLoaderBMS.h b/src/NotesLoaderBMS.h index caf8372d64..caf124f07b 100644 --- a/src/NotesLoaderBMS.h +++ b/src/NotesLoaderBMS.h @@ -2,11 +2,13 @@ #define NOTES_LOADER_BMS_H class Song; +class Steps; /** @brief Reads a Song from a set of .BMS files. */ namespace BMSLoader { void GetApplicableFiles( const RString &sPath, vector &out ); bool LoadFromDir( const RString &sDir, Song &out ); + bool LoadNoteDataFromSimfile( const RString & cachePath, Steps &out ); } #endif diff --git a/src/NotesLoaderDWI.cpp b/src/NotesLoaderDWI.cpp index 9277a7a464..242108bbe3 100644 --- a/src/NotesLoaderDWI.cpp +++ b/src/NotesLoaderDWI.cpp @@ -14,6 +14,8 @@ #include +Difficulty DwiCompatibleStringToDifficulty( const RString& sDC ); + static std::map g_mapDanceNoteToNoteDataColumn; /** @brief The different types of core DWI arrows and pads. */ @@ -168,6 +170,238 @@ Difficulty DwiCompatibleStringToDifficulty( const RString& sDC ) else return Difficulty_Invalid; } +static StepsType GetTypeFromMode(const RString &mode) +{ + if( mode == "SINGLE" ) + return StepsType_dance_single; + else if( mode == "DOUBLE" ) + return StepsType_dance_double; + else if( mode == "COUPLE" ) + return StepsType_dance_couple; + else if( mode == "SOLO" ) + return StepsType_dance_solo; + ASSERT_M(0, "Unrecognized DWI notes format " + mode + "!"); + return StepsType_Invalid; // just in case. +} + +static NoteData ParseNoteData(RString &step1, RString &step2, + Steps &out, const RString &path) +{ + g_mapDanceNoteToNoteDataColumn.clear(); + switch( out.m_StepsType ) + { + case StepsType_dance_single: + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3; + break; + case StepsType_dance_double: + case StepsType_dance_couple: + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_LEFT] = 4; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_DOWN] = 5; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_UP] = 6; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_RIGHT] = 7; + break; + case StepsType_dance_solo: + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPLEFT] = 1; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 2; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 3; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPRIGHT] = 4; + g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 5; + break; + DEFAULT_FAIL( out.m_StepsType ); + } + + NoteData newNoteData; + newNoteData.SetNumTracks( g_mapDanceNoteToNoteDataColumn.size() ); + + for( int pad=0; pad<2; pad++ ) // foreach pad + { + RString sStepData; + switch( pad ) + { + case 0: + sStepData = step1; + break; + case 1: + if( step2 == "" ) // no data + continue; // skip + sStepData = step2; + break; + DEFAULT_FAIL( pad ); + } + + sStepData.Replace("\n", ""); + sStepData.Replace("\r", ""); + sStepData.Replace("\t", ""); + sStepData.Replace(" ", ""); + + double fCurrentBeat = 0; + double fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE; + + for( size_t i=0; i': + fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE; + break; + + default: // this is a note character + { + if( c == '!' ) + { + LOG->UserLog( + "Song file", + path, + "has an unexpected character: '!'." ); + continue; + } + + bool jump = false; + if( c == '<' ) + { + /* Arr. Is this a jump or a 1/192 marker? */ + if( Is192( sStepData, i ) ) + { + fCurrentIncrementer = 1.0/192 * BEATS_PER_MEASURE; + break; + } + + /* It's a jump. + * We need to keep reading notes until we hit a >. */ + jump = true; + i++; + } + + const int iIndex = BeatToNoteRow( (float)fCurrentBeat ); + i--; + do { + c = sStepData[i++]; + + if( jump && c == '>' ) + break; + + int iCol1, iCol2; + DWIcharToNoteCol( + c, + (GameController)pad, + iCol1, + iCol2, + path ); + + if( iCol1 != -1 ) + newNoteData.SetTapNote(iCol1, + iIndex, + TAP_ORIGINAL_TAP); + if( iCol2 != -1 ) + newNoteData.SetTapNote(iCol2, + iIndex, + TAP_ORIGINAL_TAP); + + if(i>=sStepData.length()) + { + break; + //we ran out of data + //while looking for the ending > mark + } + + if( sStepData[i] == '!' ) + { + i++; + const char holdChar = sStepData[i++]; + + DWIcharToNoteCol(holdChar, + (GameController)pad, + iCol1, + iCol2, + path ); + + if( iCol1 != -1 ) + newNoteData.SetTapNote(iCol1, + iIndex, + TAP_ORIGINAL_HOLD_HEAD); + if( iCol2 != -1 ) + newNoteData.SetTapNote(iCol2, + iIndex, + TAP_ORIGINAL_HOLD_HEAD); + } + } + while( jump ); + fCurrentBeat += fCurrentIncrementer; + } + break; + } + } + } + + /* Fill in iDuration. */ + for( int t=0; tUserLog("Song file", + path, + "failed to close a hold note in \"%s\" on track %i", + DifficultyToString(out.GetDifficulty()).c_str(), + t); + + newNoteData.SetTapNote( t, iHeadRow, TAP_EMPTY ); + } + } + } + + ASSERT( newNoteData.GetNumTracks() > 0 ); + return newNoteData; +} + /** * @brief Look through the notes tag to extract the data. * @param sMode the steps type. @@ -190,216 +424,17 @@ static bool LoadFromDWITokens( { CHECKPOINT_M( "DWILoader::LoadFromDWITokens()" ); - out.m_StepsType = StepsType_Invalid; + out.m_StepsType = GetTypeFromMode(sMode); - if( sMode == "SINGLE" ) out.m_StepsType = StepsType_dance_single; - else if( sMode == "DOUBLE" ) out.m_StepsType = StepsType_dance_double; - else if( sMode == "COUPLE" ) out.m_StepsType = StepsType_dance_couple; - else if( sMode == "SOLO" ) out.m_StepsType = StepsType_dance_solo; - else - { - ASSERT_M(0, "Unrecognized DWI notes format " + sMode + "!"); - out.m_StepsType = StepsType_dance_single; - } + out.SetMeter(StringToInt(sNumFeet)); - - g_mapDanceNoteToNoteDataColumn.clear(); - switch( out.m_StepsType ) - { - case StepsType_dance_single: - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3; - break; - case StepsType_dance_double: - case StepsType_dance_couple: - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_LEFT] = 4; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_DOWN] = 5; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_UP] = 6; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_RIGHT] = 7; - break; - case StepsType_dance_solo: - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPLEFT] = 1; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 2; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 3; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPRIGHT] = 4; - g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 5; - break; - DEFAULT_FAIL( out.m_StepsType ); - } - - int iNumFeet = StringToInt(sNumFeet); - // out.SetDescription(sDescription); // Don't put garbage in the description. - out.SetMeter(iNumFeet); out.SetDifficulty( DwiCompatibleStringToDifficulty(sDescription) ); - - NoteData newNoteData; - newNoteData.SetNumTracks( g_mapDanceNoteToNoteDataColumn.size() ); - - for( int pad=0; pad<2; pad++ ) // foreach pad - { - RString sStepData; - switch( pad ) - { - case 0: - sStepData = sStepData1; - break; - case 1: - if( sStepData2 == "" ) // no data - continue; // skip - sStepData = sStepData2; - break; - DEFAULT_FAIL( pad ); - } - - sStepData.Replace("\n", ""); - sStepData.Replace("\r", ""); - sStepData.Replace("\t", ""); - sStepData.Replace(" ", ""); - - double fCurrentBeat = 0; - double fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE; - - for( size_t i=0; i': - fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE; - break; - - default: // this is a note character - { - if( c == '!' ) - { - LOG->UserLog( "Song file", sPath, "has an unexpected character: '!'." ); - continue; - } - - bool jump = false; - if( c == '<' ) - { - /* Arr. Is this a jump or a 1/192 marker? */ - if( Is192( sStepData, i ) ) - { - fCurrentIncrementer = 1.0/192 * BEATS_PER_MEASURE; - break; - } - - /* It's a jump. We need to keep reading notes until we hit a >. */ - jump = true; - i++; - } - - const int iIndex = BeatToNoteRow( (float)fCurrentBeat ); - i--; - do { - c = sStepData[i++]; - - if( jump && c == '>' ) - break; - - int iCol1, iCol2; - DWIcharToNoteCol( c, (GameController)pad, iCol1, iCol2, sPath ); - - if( iCol1 != -1 ) - newNoteData.SetTapNote(iCol1, iIndex, TAP_ORIGINAL_TAP); - if( iCol2 != -1 ) - newNoteData.SetTapNote(iCol2, iIndex, TAP_ORIGINAL_TAP); - - if(i>=sStepData.length()) { - break;//we ran out of data while looking for the ending > mark - } - - if( sStepData[i] == '!' ) - { - i++; - const char holdChar = sStepData[i++]; - - DWIcharToNoteCol( holdChar, (GameController)pad, iCol1, iCol2, sPath ); - - if( iCol1 != -1 ) - newNoteData.SetTapNote(iCol1, iIndex, TAP_ORIGINAL_HOLD_HEAD); - if( iCol2 != -1 ) - newNoteData.SetTapNote(iCol2, iIndex, TAP_ORIGINAL_HOLD_HEAD); - } - } - while( jump ); - fCurrentBeat += fCurrentIncrementer; - } - break; - } - } - } - - /* Fill in iDuration. */ - for( int t=0; tUserLog( "Song file", sPath, "failed to close a hold note in \"%s\" on track %i", - sDescription.c_str(), t ); - - newNoteData.SetTapNote( t, iHeadRow, TAP_EMPTY ); - } - } - } - - ASSERT( newNoteData.GetNumTracks() > 0 ); - - out.SetNoteData( newNoteData ); + + out.SetNoteData( ParseNoteData(sStepData1, sStepData2, out, sPath) ); out.TidyUpData(); out.SetSavedToDisk( true ); // we're loading from disk, so this is by definintion already saved - return true; } @@ -442,17 +477,55 @@ void DWILoader::GetApplicableFiles( const RString &sPath, vector &out ) GetDirListing( sPath + RString("*.dwi"), out ); } +bool DWILoader::LoadNoteDataFromSimfile( const RString &path, Steps &out ) +{ + MsdFile msd; + if( !msd.ReadFile( path, false ) ) // don't unescape + { + LOG->UserLog("Song file", + path, + "couldn't be opened: %s", + msd.GetError().c_str() ); + return false; + } + + for( unsigned i=0; i &BlacklistedImages ) { vector aFileNames; GetApplicableFiles( sPath_, aFileNames ); - + if( aFileNames.size() > 1 ) { LOG->UserLog( "Song", sPath_, "has more than one DWI file. There should be only one!" ); return false; } - + /* We should have exactly one; if we had none, we shouldn't have been called to begin with. */ ASSERT( aFileNames.size() == 1 ); const RString sPath = sPath_ + aFileNames[0]; @@ -466,6 +539,8 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set &Bla return false; } + out.m_sSongFileName = sPath; + for( unsigned i=0; i &Bla if( PREFSMAN->m_bQuirksMode ) { - out.m_SongTiming.AddBPMSegment( BPMSegment(0, fBPM) ); + out.m_SongTiming.AddSegment( SEGMENT_BPM, new BPMSegment(0, fBPM) ); } else{ if( fBPM > 0.0f ) - out.m_SongTiming.AddBPMSegment( BPMSegment(0, fBPM) ); + out.m_SongTiming.AddSegment( SEGMENT_BPM, new BPMSegment(0, fBPM) ); else - LOG->UserLog( "Song file", sPath, "has an invalid BPM change at beat %f, BPM %f.", - NoteRowToBeat(0), fBPM ); + LOG->UserLog("Song file", + sPath, + "has an invalid BPM change at beat %f, BPM %f.", + 0.0f, fBPM ); } } else if( sValueName.EqualsNoCase("DISPLAYBPM") ) @@ -574,7 +651,7 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set &Bla int iFreezeRow = BeatToNoteRow( StringToFloat(arrayFreezeValues[0]) / 4.0f ); float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ) / 1000.0f; - out.m_SongTiming.AddStopSegment( StopSegment(iFreezeRow, fFreezeSeconds) ); + out.m_SongTiming.AddSegment( SEGMENT_STOP_DELAY, new StopSegment(iFreezeRow, fFreezeSeconds) ); // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", fFreezeBeat, fFreezeSeconds ); } } @@ -598,8 +675,8 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set &Bla float fBPM = StringToFloat( arrayBPMChangeValues[1] ); if( fBPM > 0.0f ) { - BPMSegment bs( iStartIndex, fBPM ); - out.m_SongTiming.AddBPMSegment( bs ); + BPMSegment * bs = new BPMSegment( iStartIndex, fBPM ); + out.m_SongTiming.AddSegment( SEGMENT_BPM, bs ); } else { @@ -625,7 +702,10 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set &Bla sPath ); if( pNewNotes->m_StepsType != StepsType_Invalid ) + { + pNewNotes->SetFilename( sPath ); out.AddSteps( pNewNotes ); + } else delete pNewNotes; } @@ -660,7 +740,6 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set &Bla // do nothing. We don't care about this value name } } - out.TidyUpData(); return true; } diff --git a/src/NotesLoaderDWI.h b/src/NotesLoaderDWI.h index 1aa9e729c4..c121d0dc28 100644 --- a/src/NotesLoaderDWI.h +++ b/src/NotesLoaderDWI.h @@ -6,6 +6,7 @@ #include class Song; +class Steps; /** @brief The DWILoader handles parsing the .dwi file. */ namespace DWILoader @@ -24,6 +25,8 @@ namespace DWILoader * @return its success or failure. */ bool LoadFromDir( const RString &sPath, Song &out, set &BlacklistedImages ); + + bool LoadNoteDataFromSimfile( const RString &path, Steps &out ); } #endif diff --git a/src/NotesLoaderJson.cpp b/src/NotesLoaderJson.cpp index e0f79204d8..6865120fbc 100644 --- a/src/NotesLoaderJson.cpp +++ b/src/NotesLoaderJson.cpp @@ -15,22 +15,33 @@ void NotesLoaderJson::GetApplicableFiles( const RString &sPath, vector GetDirListing( sPath + RString("*.json"), out ); } -void Deserialize(BPMSegment &seg, const Json::Value &root) +static void Deserialize(TimingSegment &seg_, const Json::Value &root) { - seg.SetBeat((float)(root["Beat"].asDouble())); - seg.SetBPM((float)(root["BPM"].asDouble())); -} - -static void Deserialize(StopSegment &seg, const Json::Value &root) -{ - seg.SetBeat((float)(root["Beat"].asDouble())); - seg.SetPause((float)(root["Seconds"].asDouble())); + TimingSegment *seg = &seg_; + + float fBeat = root["Beat"].asDouble(); + seg->SetBeat(fBeat); + switch (seg->GetType()) + { + case SEGMENT_BPM: + { + float fBPM = root["BPM"].asDouble(); + static_cast(seg)->SetBPM(fBPM); + break; + } + case SEGMENT_STOP_DELAY: + { + float fStop = root["Seconds"].asDouble(); + static_cast(seg)->SetPause(fStop); + break; + } + } } static void Deserialize(TimingData &td, const Json::Value &root) { - JsonUtil::DeserializeVectorObjects( td.m_BPMSegments, Deserialize, root["BpmSegments"] ); - JsonUtil::DeserializeVectorObjects( td.m_StopSegments, Deserialize, root["StopSegments"] ); + JsonUtil::DeserializeVectorPointers( td.allTimingSegments[SEGMENT_BPM], Deserialize, root["BpmSegments"] ); + JsonUtil::DeserializeVectorPointers( td.allTimingSegments[SEGMENT_STOP_DELAY], Deserialize, root["StopSegments"] ); } static void Deserialize(LyricSegment &o, const Json::Value &root) @@ -148,8 +159,6 @@ static void Deserialize( Song &out, const Json::Value &root ) else if( sSelectable.EqualsNoCase("NO") ) out.m_SelectionDisplay = out.SHOW_NEVER; - out.m_fFirstBeat = (float)root["FirstBeat"].asDouble(); - out.m_fLastBeat = (float)root["LastBeat"].asDouble(); out.m_sSongFileName = root["SongFileName"].asString(); out.m_bHasMusic = root["HasMusic"].asBool(); out.m_bHasBanner = root["HasBanner"].asBool(); diff --git a/src/NotesLoaderKSF.cpp b/src/NotesLoaderKSF.cpp index 604c049ea1..1d2735c8ad 100644 --- a/src/NotesLoaderKSF.cpp +++ b/src/NotesLoaderKSF.cpp @@ -17,44 +17,10 @@ static void HandleBunki( TimingData &timing, const float fEarlyBPM, const float beat = (fPos + fGap) * BeatsPerSecond; LOG->Trace( "BPM %f, BPS %f, BPMPos %f, beat %f", fEarlyBPM, BeatsPerSecond, fPos, beat ); - timing.AddBPMSegment( BPMSegment(BeatToNoteRow(beat), fCurBPM) ); + timing.AddSegment( SEGMENT_BPM, new BPMSegment(beat, fCurBPM) ); } -static bool HandlePipeChars( TimingData &timing, const RString sNoteRow, - const float fCurBeat, int &iTickCount ) -{ - RString temp = sNoteRow.substr(2,sNoteRow.size()-3); - float numTemp = StringToFloat(temp); - if (BeginsWith(sNoteRow, "|T")) - { - iTickCount = static_cast(numTemp); - timing.SetTickcountAtBeat( fCurBeat, clamp(iTickCount, 0, ROWS_PER_BEAT) ); - return true; - } - else if (BeginsWith(sNoteRow, "|B")) - { - timing.SetBPMAtBeat( fCurBeat, numTemp ); - return true; - } - else if (BeginsWith(sNoteRow, "|E")) - { - // Finally! the |E| tag is working as it should. I can die happy now -DaisuMaster - float fCurDelay = 60 / timing.GetBPMAtBeat(fCurBeat) * numTemp / iTickCount; - fCurDelay += timing.GetDelayAtRow(BeatToNoteRow(fCurBeat) ); - timing.SetStopAtBeat( fCurBeat, fCurDelay, true ); - return true; - } - else if (BeginsWith(sNoteRow, "|D")) - { - float fCurDelay = timing.GetStopAtRow(BeatToNoteRow(fCurBeat) ); - fCurDelay += numTemp / 1000; - timing.SetStopAtBeat( fCurBeat, fCurDelay, true ); - return true; - } - return false; -} - -static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, bool bKIUCompliant ) +static bool LoadFromKSFFile( const RString &sPath, Steps &out, Song &song, bool bKIUCompliant ) { LOG->Trace( "Steps::LoadFromKSFFile( '%s' )", sPath.c_str() ); @@ -65,7 +31,10 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, return false; } - int iTickCount = -1; // this is the value we read for TICKCOUNT + // this is the value we read for TICKCOUNT + int iTickCount = -1; + // used to adapt weird tickcounts + //float fScrollRatio = 1.0f; -- uncomment when ready to use. vector vNoteRows; // According to Aldo_MX, there is a default BPM and it's 60. -aj @@ -85,13 +54,12 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, if (sValueName=="TITLE" || EndsWith(sValueName, "INTRO") || EndsWith(sValueName, "FILE") ) { - ; + } - else if( sValueName=="BPM" ) { BPM1 = StringToFloat(sParams[1]); - stepsTiming.AddBPMSegment( BPMSegment(0, BPM1) ); + stepsTiming.AddSegment( SEGMENT_BPM, new BPMSegment(0, BPM1) ); } else if( sValueName=="BPM2" ) { @@ -168,7 +136,7 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, LOG->UserLog( "Song file", sPath, "has an invalid tick count: %d.", iTickCount ); return false; } - stepsTiming.AddTickcountSegment(TickcountSegment(0, iTickCount)); + stepsTiming.AddSegment( SEGMENT_TICKCOUNT, new TickcountSegment(0, iTickCount)); } else if( sValueName=="DIFFICULTY" ) @@ -226,28 +194,43 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, out.SetDifficulty( Difficulty_Edit ); if( !out.GetMeter() ) out.SetMeter( 25 ); } - else if( sFName.find("wild") != string::npos || sFName.find("wd") != string::npos || sFName.find("crazy+") != string::npos || sFName.find("cz+") != string::npos || sFName.find("hardcore") != string::npos ) + else if(sFName.find("wild") != string::npos || + sFName.find("wd") != string::npos || + sFName.find("crazy+") != string::npos || + sFName.find("cz+") != string::npos || + sFName.find("hardcore") != string::npos ) { out.SetDifficulty( Difficulty_Challenge ); if( !out.GetMeter() ) out.SetMeter( 20 ); } - else if( sFName.find("crazy") != string::npos || sFName.find("cz") != string::npos || sFName.find("nightmare") != string::npos || sFName.find("nm") != string::npos || sFName.find("crazydouble") != string::npos ) + else if(sFName.find("crazy") != string::npos || + sFName.find("cz") != string::npos || + sFName.find("nightmare") != string::npos || + sFName.find("nm") != string::npos || + sFName.find("crazydouble") != string::npos ) { out.SetDifficulty( Difficulty_Hard ); if( !out.GetMeter() ) out.SetMeter( 14 ); // Set the meters to the Pump scale, not DDR. } - else if( sFName.find("hard") != string::npos || sFName.find("hd") != string::npos || sFName.find("freestyle") != string::npos || sFName.find("fs") != string::npos || sFName.find("double") != string::npos ) + else if(sFName.find("hard") != string::npos || + sFName.find("hd") != string::npos || + sFName.find("freestyle") != string::npos || + sFName.find("fs") != string::npos || + sFName.find("double") != string::npos ) { out.SetDifficulty( Difficulty_Medium ); if( !out.GetMeter() ) out.SetMeter( 8 ); } - else if( sFName.find("easy") != string::npos || sFName.find("ez") != string::npos || sFName.find("normal") != string::npos ) + else if(sFName.find("easy") != string::npos || + sFName.find("ez") != string::npos || + sFName.find("normal") != string::npos ) { // I wonder if I should leave easy fall into the Beginner difficulty... -DaisuMaster out.SetDifficulty( Difficulty_Easy ); if( !out.GetMeter() ) out.SetMeter( 4 ); } - else if( sFName.find("beginner") != string::npos || sFName.find("practice") != string::npos || sFName.find("pr") != string::npos ) + else if(sFName.find("beginner") != string::npos || + sFName.find("practice") != string::npos || sFName.find("pr") != string::npos ) { out.SetDifficulty( Difficulty_Beginner ); if( !out.GetMeter() ) out.SetMeter( 4 ); @@ -261,10 +244,18 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, out.m_StepsType = StepsType_pump_single; // Check for "halfdouble" before "double". - if( sFName.find("halfdouble") != string::npos || sFName.find("half-double") != string::npos || sFName.find("h_double") != string::npos || sFName.find("hdb") != string::npos ) + if(sFName.find("halfdouble") != string::npos || + sFName.find("half-double") != string::npos || + sFName.find("h_double") != string::npos || + sFName.find("hdb") != string::npos ) out.m_StepsType = StepsType_pump_halfdouble; // Handle bDoublesChart from above as well. -aj - else if( sFName.find("double") != string::npos || sFName.find("nightmare") != string::npos || sFName.find("freestyle") != string::npos || sFName.find("db") != string::npos || sFName.find("nm") != string::npos || sFName.find("fs") != string::npos || bDoublesChart ) + else if(sFName.find("double") != string::npos || + sFName.find("nightmare") != string::npos || + sFName.find("freestyle") != string::npos || + sFName.find("db") != string::npos || + sFName.find("nm") != string::npos || + sFName.find("fs") != string::npos || bDoublesChart ) out.m_StepsType = StepsType_pump_double; else if( sFName.find("_1") != string::npos ) out.m_StepsType = StepsType_pump_single; @@ -311,34 +302,89 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, if( iHoldStartRow[t] == BeatToNoteRow(prevBeat) ) notedata.SetTapNote( t, iHoldStartRow[t], TAP_ORIGINAL_TAP ); else - notedata.AddHoldNote( t, iHoldStartRow[t], BeatToNoteRow(prevBeat) , TAP_ORIGINAL_HOLD_HEAD ); + notedata.AddHoldNote(t, + iHoldStartRow[t], + BeatToNoteRow(prevBeat), + TAP_ORIGINAL_HOLD_HEAD ); } } + /* have this row be the last moment in the song, unless + * a future step ends later. */ + float curTime = stepsTiming.GetElapsedTimeFromBeat(fCurBeat); + if (curTime > song.GetSpecifiedLastSecond()) + { + song.SetSpecifiedLastSecond(curTime); + } break; } else if( BeginsWith(sRowString, "|") ) { + /* if (bKIUCompliant) { // Log an error, ignore the line. continue; } - if ( !HandlePipeChars( stepsTiming, sRowString, fCurBeat, iTickCount ) ) - { - // LOG it first. - } - continue; + */ + // gotta do something tricky here: if the bpm is below one then a couple of calculations + // for scrollsegments will be made, example, bpm 0.2, tick 4000, the scrollsegment will + // be 0. if the tickcount is non a stepmania standard then it will be adapted, a scroll + // segment will then be added based on approximations. -DaisuMaster + // eh better do it considering the tickcount (high tickcounts) - } - - else - { - // Is this why improper ksf or some kiucompilant ksf mixed with dm05 ksf are ignored?? -DaisuMaster - //LOG->UserLog( "Song file", sPath, "has a RowString with an improper length \"%s\"; corrupt notes ignored.", - // sRowString.c_str() ); - //return false; + // I'm making some experiments, please spare me... //continue; + + RString temp = sRowString.substr(2,sRowString.size()-3); + float numTemp = StringToFloat(temp); + if (BeginsWith(sRowString, "|T")) + { + // duh + iTickCount = static_cast(numTemp); + // I have been owned by the man -DaisuMaster + stepsTiming.SetTickcountAtBeat( fCurBeat, clamp(iTickCount, 0, ROWS_PER_BEAT) ); + } + else if (BeginsWith(sRowString, "|B")) + { + // BPM + stepsTiming.SetBPMAtBeat( fCurBeat, numTemp ); + } + else if (BeginsWith(sRowString, "|E")) + { + // DelayBeat + float fCurDelay = 60 / stepsTiming.GetBPMAtBeat(fCurBeat) * numTemp / iTickCount; + fCurDelay += stepsTiming.GetDelayAtRow(BeatToNoteRow(fCurBeat) ); + stepsTiming.SetStopAtBeat( fCurBeat, fCurDelay, true ); + } + else if (BeginsWith(sRowString, "|D")) + { + // Delays + float fCurDelay = stepsTiming.GetStopAtRow(BeatToNoteRow(fCurBeat) ); + fCurDelay += numTemp / 1000; + stepsTiming.SetStopAtBeat( fCurBeat, fCurDelay, true ); + } + else if (BeginsWith(sRowString, "|M") || BeginsWith(sRowString, "|C")) + { + // multipliers/combo + stepsTiming.SetHitComboAtBeat( fCurBeat, static_cast(numTemp) ); + } + else if (BeginsWith(sRowString, "|S")) + { + // speed segments + } + else if (BeginsWith(sRowString, "|F")) + { + // fakes + } + else if (BeginsWith(sRowString, "|X")) + { + // scroll segments + stepsTiming.SetScrollAtBeat( fCurBeat, numTemp ); + //return true; + } + + continue; } // Half-doubles is offset; "0011111100000". @@ -459,6 +505,20 @@ static void LoadTags( const RString &str, Song &out ) out.m_sArtist = artist; } +static void ProcessTickcounts( const RString & value, int & ticks, TimingData & timing ) +{ + /* TICKCOUNT will be used below if there are DM compliant BPM changes + * and stops. It will be called again in LoadFromKSFFile for the + * actual steps. */ + ticks = StringToInt( value ); + ticks = ticks > 0 ? ticks : 4; + // add a tickcount for those using the [Player] + // CheckpointsUseTimeSignatures metric. -aj + // It's not with timesigs now -DaisuMaster + TickcountSegment * tcs = new TickcountSegment(0, ticks > ROWS_PER_BEAT ? ROWS_PER_BEAT : ticks); + timing.AddSegment( SEGMENT_TICKCOUNT, tcs ); +} + static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant ) { MsdFile msd; @@ -497,7 +557,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant else if( sValueName=="BPM" ) { BPM1 = StringToFloat(sParams[1]); - out.m_SongTiming.AddBPMSegment( BPMSegment(0, BPM1) ); + out.m_SongTiming.AddSegment( SEGMENT_BPM, new BPMSegment(0, BPM1) ); } else if( sValueName=="BPM2" ) { @@ -533,21 +593,11 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant else if ( sValueName=="STARTTIME3" ) { // STARTTIME3 only ensures this is a KIU compliant simfile. - bKIUCompliant = true; + //bKIUCompliant = true; } else if ( sValueName=="TICKCOUNT" ) { - /* TICKCOUNT will be used below if there are DM compliant BPM changes - * and stops. It will be called again in LoadFromKSFFile for the - * actual steps. */ - iTickCount = StringToInt( sParams[1] ); - iTickCount = iTickCount > 0 ? iTickCount : 4; - // add a tickcount for those using the [Player] - // CheckpointsUseTimeSignatures metric. -aj - // It's not with timesigs now -DaisuMaster - TickcountSegment tcs(0); - tcs.SetTicks(iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount); - out.m_SongTiming.AddTickcountSegment( tcs ); + ProcessTickcounts(sParams[1], iTickCount, out.m_SongTiming); } else if ( sValueName=="STEP" ) { @@ -557,10 +607,10 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant TrimLeft( theSteps ); split( theSteps, "\n", vNoteRows, true ); } - - else if( sValueName=="DIFFICULTY" ) + else if( sValueName=="DIFFICULTY" || sValueName=="PLAYER" ) { - /* DIFFICULTY is handled only in LoadFromKSFFile. Ignore it here. */ + /* DIFFICULTY and PLAYER are handled only in LoadFromKSFFile. + Ignore those here. */ continue; } // New cases noted in Aldo_MX's code: @@ -632,14 +682,10 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant } // This is where the DMRequired test will take place. - if (BeginsWith(NoteRowString, "|T") || BeginsWith(NoteRowString, "|B") || - BeginsWith(NoteRowString, "|D") || BeginsWith(NoteRowString, "|E") ) + if ( BeginsWith( NoteRowString, "|" ) ) { + // have a static timing for everything bDMRequired = true; - if ( !HandlePipeChars( out.m_SongTiming, NoteRowString, fCurBeat, iTickCount ) ) - { - // LOG it first. - } continue; } else @@ -669,6 +715,22 @@ void KSFLoader::GetApplicableFiles( const RString &sPath, vector &out ) GetDirListing( sPath + RString("*.ksf"), out ); } +bool KSFLoader::LoadNoteDataFromSimfile( const RString & cachePath, Steps &out ) +{ + bool KIUCompliant = false; + Song dummy; + if (!LoadGlobalData(cachePath, dummy, KIUCompliant)) + return false; + Steps *notes = dummy.CreateSteps(); + if (LoadFromKSFFile(cachePath, *notes, dummy, KIUCompliant)) + { + KIUCompliant = true; // yeah, reusing a variable. + out.SetNoteData(notes->GetNoteData()); + } + delete notes; + return KIUCompliant; +} + bool KSFLoader::LoadFromDir( const RString &sDir, Song &out ) { LOG->Trace( "KSFLoader::LoadFromDir(%s)", sDir.c_str() ); @@ -685,23 +747,36 @@ bool KSFLoader::LoadFromDir( const RString &sDir, Song &out ) * order (hopefully), it is best to use the LAST file for timing * purposes, for that is the "normal", or easiest difficulty. * Usually. */ + // Nevermind, kiu compilancy is screwing things up: + // IE, I have two simfiles, oh wich each have four ksf files, the first one has + // the first ksf with directmove timing changes, and the rest are not, everything + // goes fine. In the other hand I have my second simfile with the first ksf file + // without directmove timing changes and the rest have changes, changes are not + // loaded due to kiucompilancy in the first ksf file. + // About the "normal" thing, my simfiles' ksfs uses non-standard naming so + // the last chart is usually nightmare or normal, I use easy and normal + // indistinctly for SM so it shouldn't matter, I use piu fiesta/ex naming + // for directmove though, and we're just gathering basic info anyway, and + // most of the time all the KSF files have the same info in the #TITLE:; section unsigned files = arrayKSFFileNames.size(); - if( !LoadGlobalData(out.GetSongDir() + arrayKSFFileNames[files - 1], out, bKIUCompliant) ) + RString dir = out.GetSongDir(); + if( !LoadGlobalData(dir + arrayKSFFileNames[files - 1], out, bKIUCompliant) ) return false; + out.m_sSongFileName = dir + arrayKSFFileNames[files - 1]; // load the Steps from the rest of the KSF files for( unsigned i=0; iSetFilename(dir + arrayKSFFileNames[i]); out.AddSteps( pNewNotes ); } - out.TidyUpData(); + out.TidyUpData(false, true); return true; } diff --git a/src/NotesLoaderKSF.h b/src/NotesLoaderKSF.h index b18e94a1e9..650f7aa44f 100644 --- a/src/NotesLoaderKSF.h +++ b/src/NotesLoaderKSF.h @@ -2,11 +2,13 @@ #define NOTES_LOADER_KSF_H class Song; +class Steps; /** @brief Reads a Song from a set of .KSF files. */ namespace KSFLoader { void GetApplicableFiles( const RString &sPath, vector &out ); bool LoadFromDir( const RString &sDir, Song &out ); + bool LoadNoteDataFromSimfile( const RString & cachePath, Steps &out ); } #endif diff --git a/src/NotesLoaderMidi.cpp b/src/NotesLoaderMidi.cpp index 8a3377b527..f356cdb3d6 100644 --- a/src/NotesLoaderMidi.cpp +++ b/src/NotesLoaderMidi.cpp @@ -677,21 +677,22 @@ static bool LoadFromMidi( const RString &sPath, Song &songOut ) FOREACH_CONST( MidiFileIn::TempoChange, midi.tempoEvents_, iter ) { - BPMSegment bpmSeg; - bpmSeg.SetRow( MidiCountToNoteRow( iter->count ) ); + BPMSegment * bpmSeg = NULL; + bpmSeg->SetRow( MidiCountToNoteRow( iter->count ) ); double fSecondsPerBeat = (iter->tickSeconds * GUITAR_MIDI_COUNTS_PER_BEAT); - bpmSeg.SetBPS( float( 1. / fSecondsPerBeat ) ); + bpmSeg->SetBPS( float( 1. / fSecondsPerBeat ) ); - songOut.m_SongTiming.AddBPMSegment( bpmSeg ); + songOut.m_SongTiming.AddSegment( SEGMENT_BPM, bpmSeg ); } FOREACH_CONST( MidiFileIn::TimeSignatureChange, midi.timeSignatureEvents_, iter ) { - TimeSignatureSegment seg(MidiCountToNoteRow( iter->count ), - iter->numerator, - iter->denominator); + TimeSignatureSegment * seg = + new TimeSignatureSegment(MidiCountToNoteRow( iter->count ), + iter->numerator, + iter->denominator); - songOut.m_SongTiming.AddTimeSignatureSegment( seg ); + songOut.m_SongTiming.AddSegment( SEGMENT_TIME_SIG, seg ); } @@ -955,7 +956,7 @@ bool MidiLoader::LoadFromDir( const RString &sDir, Song &out ) if( !LoadFromMidi(sDir+vsFiles[0], out) ) return false; - out.TidyUpData(); + out.TidyUpData(false, true); return true; } diff --git a/src/NotesLoaderPMS.cpp b/src/NotesLoaderPMS.cpp index f0d742973c..ca4c672091 100644 --- a/src/NotesLoaderPMS.cpp +++ b/src/NotesLoaderPMS.cpp @@ -573,7 +573,7 @@ static bool LoadFromPMSFile( const RString &sPath, const NameToData_t &mapNameTo return true; } -static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, MeasureToTimeSig_t &sigAdjustmentsOut, map &idToKeySoundIndexOut ) +static void ReadGlobalTags( const RString &sPath, const NameToData_t &mapNameToData, Song &out, MeasureToTimeSig_t &sigAdjustmentsOut, map &idToKeySoundIndexOut ) { RString sData; if( GetTagFromMap(mapNameToData, "#title", sData) ) @@ -590,8 +590,7 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( fBPM > 0.0f ) { - BPMSegment newSeg( 0, fBPM ); - out.m_SongTiming.AddBPMSegment( newSeg ); + out.m_SongTiming.AddSegment( SEGMENT_BPM, new BPMSegment(0, fBPM) ); LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", NoteRowToBeat(0), fBPM ); } else @@ -612,26 +611,29 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur // this is keysound file name. Looks like "#WAV1A" RString nData = it->second; RString sWavID = sName.Right(2); + RString dir = out.GetSongDir(); + if (dir.empty()) + dir = Dirname(sPath); /* Due to bugs in some programs, many PMS files have a "WAV" extension * on files in the PMS for files that actually have some other extension. * Do a search. Don't do a wildcard search; if sData is "song.wav", * we might also have "song.png", which we shouldn't match. */ - if( !IsAFile(out.GetSongDir()+nData) ) + if( !IsAFile(dir+nData) ) { const char *exts[] = { "oga", "ogg", "wav", "mp3", NULL }; // XXX: stop duplicating these everywhere for( unsigned i = 0; exts[i] != NULL; ++i ) { RString fn = SetExtension( nData, exts[i] ); - if( IsAFile(out.GetSongDir()+fn) ) + if( IsAFile(dir+fn) ) { nData = fn; break; } } } - if( !IsAFile(out.GetSongDir()+nData) ) - LOG->UserLog( "Song file", out.GetSongDir(), "references key \"%s\" that can't be found", nData.c_str() ); + if( !IsAFile(dir+nData) ) + LOG->UserLog( "Song file", dir, "references key \"%s\" that can't be found", nData.c_str() ); sWavID.MakeUpper(); // HACK: undo the MakeLower() out.m_vsKeysoundFile.push_back( nData ); @@ -693,9 +695,9 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( fBPM > 0.0f ) { - BPMSegment newSeg( BeatToNoteRow(fBeat), fBPM ); - out.m_SongTiming.AddBPMSegment( newSeg ); - LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", fBeat, newSeg.GetBPM() ); + BPMSegment * newSeg = new BPMSegment( fBeat, fBPM ); + out.m_SongTiming.AddSegment( SEGMENT_BPM, newSeg ); + LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", fBeat, newSeg->GetBPM() ); } else { @@ -720,9 +722,9 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur float fBeats = StringToFloat( sBeats ) / 48.0f; float fFreezeSecs = fBeats / fBPS; - StopSegment newSeg( BeatToNoteRow(fBeat), fFreezeSecs ); - out.m_SongTiming.AddStopSegment( newSeg ); - LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg.GetPause() ); + StopSegment * newSeg = new StopSegment( fBeat, fFreezeSecs ); + out.m_SongTiming.AddSegment( SEGMENT_STOP_DELAY, newSeg ); + LOG->Trace( "Inserting new Freeze at beat %f, secs %f", fBeat, newSeg->GetPause() ); } else { @@ -749,9 +751,11 @@ static void ReadGlobalTags( const NameToData_t &mapNameToData, Song &out, Measur if( fBPM > 0.0f ) { - BPMSegment newSeg( iStepIndex, fBPM ); - out.m_SongTiming.AddBPMSegment( newSeg ); - LOG->Trace( "Inserting new BPM change at beat %f, BPM %f", newSeg.GetBeat(), newSeg.GetBPM() ); + BPMSegment * newSeg = new BPMSegment( iStepIndex, fBPM ); + out.m_SongTiming.AddSegment( SEGMENT_BPM, newSeg ); + LOG->Trace("Inserting new BPM change at beat %f, BPM %f", + newSeg->GetBeat(), + newSeg->GetBPM() ); } else @@ -809,6 +813,64 @@ void PMSLoader::GetApplicableFiles( const RString &sPath, vector &out ) GetDirListing( sPath + RString("*.pms"), out ); } +bool PMSLoader::LoadNoteDataFromSimfile(const RString &cachePath, Steps &out) +{ + Song dummy; + // TODO: Simplify this copy/paste from LoadFromDir. + + vector BMSData; + BMSData.push_back(NameToData_t()); + ReadPMSFile(cachePath, BMSData.back()); + + RString commonSubstring; + GetCommonTagFromMapList( BMSData, "#title", commonSubstring ); + + Steps *copy = dummy.CreateSteps(); + + copy->SetDifficulty( Difficulty_Medium ); + RString sTag; + if( GetTagFromMap( BMSData[0], "#title", sTag ) && sTag.size() != commonSubstring.size() ) + { + sTag = sTag.substr( commonSubstring.size(), sTag.size() - commonSubstring.size() ); + sTag.MakeLower(); + + if( sTag.find('l') != sTag.npos ) + { + unsigned lPos = sTag.find('l'); + if( lPos > 2 && sTag.substr(lPos-2,4) == "solo" ) + { + copy->SetDifficulty( Difficulty_Edit ); + } + else + { + copy->SetDifficulty( Difficulty_Easy ); + } + } + else if( sTag.find('a') != sTag.npos ) + copy->SetDifficulty( Difficulty_Hard ); + else if( sTag.find('b') != sTag.npos ) + copy->SetDifficulty( Difficulty_Beginner ); + } + if( commonSubstring == "" ) + { + copy->SetDifficulty(Difficulty_Medium); + RString unused; + if (GetTagFromMap(BMSData[0], "#title#", sTag)) + SearchForDifficulty(unused, copy); + } + MeasureToTimeSig_t sigAdjustments; + map idToKeysoundIndex; + ReadGlobalTags( cachePath, BMSData[0], dummy, sigAdjustments, idToKeysoundIndex ); + + const bool ok = LoadFromPMSFile( cachePath, BMSData[0], *copy, sigAdjustments, idToKeysoundIndex ); + if( ok ) + { + out.SetNoteData(copy->GetNoteData()); + } + return ok; + +} + bool PMSLoader::LoadFromDir( const RString &sDir, Song &out ) { LOG->Trace( "Song::LoadFromPMSDir(%s)", sDir.c_str() ); @@ -914,7 +976,8 @@ bool PMSLoader::LoadFromDir( const RString &sDir, Song &out ) MeasureToTimeSig_t sigAdjustments; map idToKeysoundIndex; - ReadGlobalTags( aPMSData[iMainDataIndex], out, sigAdjustments, idToKeysoundIndex ); + ReadGlobalTags( sDir, aPMSData[iMainDataIndex], out, sigAdjustments, idToKeysoundIndex ); + out.m_sSongFileName = out.GetSongDir() + arrayPMSFileNames[iMainDataIndex]; // Override what that global tag said about the title if we have a good substring. // Prevents clobbering and catches "MySong (7keys)" / "MySong (Another) (7keys)" @@ -929,7 +992,10 @@ bool PMSLoader::LoadFromDir( const RString &sDir, Song &out ) Steps* pNewNotes = apSteps[i]; const bool ok = LoadFromPMSFile( out.GetSongDir() + arrayPMSFileNames[i], aPMSData[i], *pNewNotes, sigAdjustments, idToKeysoundIndex ); if( ok ) + { + pNewNotes->SetFilename(out.GetSongDir() + arrayPMSFileNames[i]); out.AddSteps( pNewNotes ); + } else delete pNewNotes; } @@ -940,7 +1006,7 @@ bool PMSLoader::LoadFromDir( const RString &sDir, Song &out ) ConvertString( out.m_sArtist, "utf-8,japanese" ); ConvertString( out.m_sGenre, "utf-8,japanese" ); - out.TidyUpData(); + out.TidyUpData(false, true); return true; } diff --git a/src/NotesLoaderPMS.h b/src/NotesLoaderPMS.h index 0cdc0d398d..65ec7f4ecb 100644 --- a/src/NotesLoaderPMS.h +++ b/src/NotesLoaderPMS.h @@ -2,11 +2,13 @@ #define NOTES_LOADER_PMS_H class Song; +class Steps; /** @brief Reads a Song from a set of .PMS files. */ namespace PMSLoader { void GetApplicableFiles( const RString &sPath, vector &out ); bool LoadFromDir( const RString &sDir, Song &out ); + bool LoadNoteDataFromSimfile(const RString & cachePath, Steps & out); } #endif diff --git a/src/NotesLoaderSM.cpp b/src/NotesLoaderSM.cpp index f18c556056..c74e867a18 100644 --- a/src/NotesLoaderSM.cpp +++ b/src/NotesLoaderSM.cpp @@ -13,10 +13,49 @@ #include "Attack.h" #include "PrefsManager.h" -/** @brief The maximum file size for edits. */ -const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB +void SMLoader::SetSongTitle(const RString & title) +{ + this->songTitle = title; +} -void SMLoader::LoadFromSMTokens( +RString SMLoader::GetSongTitle() const +{ + return this->songTitle; +} + +bool SMLoader::LoadFromDir( const RString &sPath, Song &out ) +{ + vector aFileNames; + GetApplicableFiles( sPath, aFileNames ); + + if( aFileNames.size() > 1 ) + { + // Need to break this up first. + RString tmp = "Song " + sPath + " has more than one"; + LOG->UserLog(tmp, this->GetFileExtension(), "file. There can only be one!"); + return false; + } + + ASSERT( aFileNames.size() == 1 ); + return LoadFromSimfile( sPath + aFileNames[0], out ); +} + +float SMLoader::RowToBeat( RString line, const int rowsPerBeat ) +{ + RString backup = line; + Trim(line, "r"); + Trim(line, "R"); + if( backup != line ) + { + return StringToFloat( line ) / rowsPerBeat; + } + else + { + return StringToFloat( line ); + } +} + +void SMLoader::LoadFromTokens( RString sStepsType, RString sDescription, RString sDifficulty, @@ -34,12 +73,13 @@ void SMLoader::LoadFromSMTokens( Trim( sDifficulty ); Trim( sNoteData ); - // LOG->Trace( "Steps::LoadFromSMTokens()" ); + // LOG->Trace( "Steps::LoadFromTokens()" ); // insert stepstype hacks from GameManager.cpp here? -aj out.m_StepsType = GAMEMAN->StringToStepsType( sStepsType ); out.SetDescription( sDescription ); out.SetCredit( sDescription ); // this is often used for both. + out.SetChartName(sDescription); // yeah, one more for good measure. out.SetDifficulty( StringToDifficulty(sDifficulty) ); // Handle hacks that originated back when StepMania didn't have @@ -56,34 +96,12 @@ void SMLoader::LoadFromSMTokens( } out.SetMeter( StringToInt(sMeter) ); - vector saValues; - split( sRadarValues, ",", saValues, true ); - int categories = NUM_RadarCategory - 1; // Fakes aren't counted in the radar values. - if( saValues.size() == (unsigned)categories * NUM_PLAYERS ) - { - RadarValues v[NUM_PLAYERS]; - FOREACH_PlayerNumber( pn ) - { - // Can't use the foreach anymore due to flexible radar lines. - for( RadarCategory rc = (RadarCategory)0; rc < categories; - enum_add( rc, 1 ) ) - { - v[pn][rc] = StringToFloat( saValues[pn*categories + rc] ); - } - } - out.SetCachedRadarValues( v ); - } out.SetSMNoteData( sNoteData ); out.TidyUpData(); } -void SMLoader::GetApplicableFiles( const RString &sPath, vector &out ) -{ - GetDirListing( sPath + RString("*.sm"), out ); -} - void SMLoader::ProcessBGChanges( Song &out, const RString &sValueName, const RString &sPath, const RString &sParam ) { BackgroundLayer iLayer = BACKGROUND_LAYER_1; @@ -109,26 +127,32 @@ void SMLoader::ProcessBGChanges( Song &out, const RString &sValueName, const RSt } } -void SMLoader::ProcessAttacks( Song &out, MsdFile::value_t sParams ) +void SMLoader::ProcessAttackString( vector & attacks, MsdFile::value_t params ) +{ + for( unsigned s=1; s < params.params.size(); ++s ) + { + RString tmp = params[s]; + Trim(tmp); + if (tmp.size() > 0) + attacks.push_back( tmp ); + } +} + +void SMLoader::ProcessAttacks( AttackArray &attacks, MsdFile::value_t params ) { - // Build the RString vector here so we can write it to file again later - for( unsigned s=1; s < sParams.params.size(); ++s ) - out.m_sAttackString.push_back( sParams[s] ); - Attack attack; float end = -9999; - for( unsigned j=1; j < sParams.params.size(); ++j ) + for( unsigned j=1; j < params.params.size(); ++j ) { vector sBits; - split( sParams[j], "=", sBits, false ); + split( params[j], "=", sBits, false ); // Need an identifer and a value for this to work if( sBits.size() < 2 ) continue; - TrimLeft( sBits[0] ); - TrimRight( sBits[0] ); + Trim( sBits[0] ); if( !sBits[0].CompareNoCase("TIME") ) attack.fStartSecond = strtof( sBits[1], NULL ); @@ -138,6 +162,7 @@ void SMLoader::ProcessAttacks( Song &out, MsdFile::value_t sParams ) end = strtof( sBits[1], NULL ); else if( !sBits[0].CompareNoCase("MODS") ) { + Trim(sBits[1]); attack.sModifiers = sBits[1]; if( end != -9999 ) @@ -149,7 +174,7 @@ void SMLoader::ProcessAttacks( Song &out, MsdFile::value_t sParams ) if( attack.fSecsRemaining < 0.0f ) attack.fSecsRemaining = 0.0f; - out.m_Attacks.push_back( attack ); + attacks.push_back( attack ); } } } @@ -171,10 +196,10 @@ void SMLoader::ProcessInstrumentTracks( Song &out, const RString &sParam ) } } -bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam ) +bool SMLoader::ProcessBPMs( TimingData &out, const RString line, const int rowsPerBeat ) { vector arrayBPMChangeExpressions; - split( sParam, ",", arrayBPMChangeExpressions ); + split( line, ",", arrayBPMChangeExpressions ); // prepare storage variables for negative BPMs -> Warps. float negBeat = -1; @@ -186,22 +211,22 @@ bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam ) { vector arrayBPMChangeValues; split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); - // XXX: Hard to tell which file caused this. if( arrayBPMChangeValues.size() != 2 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #BPMs value \"%s\" (must have exactly one '='), ignored.", + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid #BPMs value \"%s\" (must have exactly one '='), ignored.", arrayBPMChangeExpressions[b].c_str() ); continue; } bNotEmpty = true; - const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); + const float fBeat = RowToBeat( arrayBPMChangeValues[0], rowsPerBeat ); const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); if( fNewBPM < 0.0f ) { - out.m_bHasNegativeBpms = true; negBeat = fBeat; negBPM = fNewBPM; } @@ -211,8 +236,8 @@ bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam ) if( negBPM < 0 ) { float endBeat = fBeat + (fNewBPM / -negBPM) * (fBeat - negBeat); - WarpSegment new_seg(negBeat, endBeat - negBeat); - out.AddWarpSegment( new_seg ); + out.AddSegment(SEGMENT_WARP, + new WarpSegment(negBeat, endBeat - negBeat)); negBeat = -1; negBPM = 1; @@ -227,13 +252,13 @@ bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam ) // add in a warp. if( highspeedBeat > 0 ) { - WarpSegment new_seg(highspeedBeat, fBeat - highspeedBeat); - out.AddWarpSegment( new_seg ); + out.AddSegment(SEGMENT_WARP, + new WarpSegment(highspeedBeat, fBeat - highspeedBeat) ); highspeedBeat = -1; } { - BPMSegment new_seg( BeatToNoteRow( fBeat ), fNewBPM ); - out.AddBPMSegment( new_seg ); + out.AddSegment(SEGMENT_BPM, + new BPMSegment(fBeat, fNewBPM)); } } } @@ -242,10 +267,10 @@ bool SMLoader::ProcessBPMs( TimingData &out, const RString sParam ) return bNotEmpty; } -void SMLoader::ProcessStops( TimingData &out, const RString sParam ) +void SMLoader::ProcessStops( TimingData &out, const RString line, const int rowsPerBeat ) { vector arrayFreezeExpressions; - split( sParam, ",", arrayFreezeExpressions ); + split( line, ",", arrayFreezeExpressions ); // Prepare variables for negative stop conversion. float negBeat = -1; @@ -257,27 +282,27 @@ void SMLoader::ProcessStops( TimingData &out, const RString sParam ) split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); if( arrayFreezeValues.size() != 2 ) { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #STOPS value \"%s\" (must have exactly one '='), ignored.", + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid #STOPS value \"%s\" (must have exactly one '='), ignored.", arrayFreezeExpressions[f].c_str() ); continue; } - const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); + const float fFreezeBeat = RowToBeat( arrayFreezeValues[0], rowsPerBeat ); const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); // Process the prior stop. if( negPause > 0 ) { - BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat)); - float fSecondsPerBeat = 60 / oldBPM.GetBPM(); + BPMSegment * oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat)); + float fSecondsPerBeat = 60 / oldBPM->GetBPM(); float fSkipBeats = negPause / fSecondsPerBeat; if( negBeat + fSkipBeats > fFreezeBeat ) fSkipBeats = fFreezeBeat - negBeat; - WarpSegment ws( negBeat, fSkipBeats); - out.AddWarpSegment( ws ); + out.AddSegment(SEGMENT_WARP, new WarpSegment(negBeat, fSkipBeats)); negBeat = -1; negPause = 0; @@ -290,8 +315,8 @@ void SMLoader::ProcessStops( TimingData &out, const RString sParam ) } else if( fFreezeSeconds > 0.0f ) { - StopSegment ss( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); - out.AddStopSegment( ss ); + out.AddSegment(SEGMENT_STOP_DELAY, + new StopSegment(fFreezeBeat, fFreezeSeconds)); } } @@ -299,19 +324,18 @@ void SMLoader::ProcessStops( TimingData &out, const RString sParam ) // Process the prior stop if there was one. if( negPause > 0 ) { - BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat)); - float fSecondsPerBeat = 60 / oldBPM.GetBPM(); + BPMSegment * oldBPM = out.GetBPMSegmentAtBeat(negBeat); + float fSecondsPerBeat = 60 / oldBPM->GetBPM(); float fSkipBeats = negPause / fSecondsPerBeat; - WarpSegment ws( negBeat, fSkipBeats); - out.AddWarpSegment( ws ); + out.AddSegment(SEGMENT_WARP, new WarpSegment(negBeat, fSkipBeats)); } } -void SMLoader::ProcessDelays( TimingData &out, const RString sParam ) +void SMLoader::ProcessDelays( TimingData &out, const RString line, const int rowsPerBeat ) { vector arrayDelayExpressions; - split( sParam, ",", arrayDelayExpressions ); + split( line, ",", arrayDelayExpressions ); for( unsigned f=0; fTrace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); if(fFreezeSeconds > 0.0f) - out.AddStopSegment( new_seg ); + out.AddSegment( SEGMENT_STOP_DELAY, new_seg ); else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + LOG->UserLog( + "Song file", + this->GetSongTitle(), + "has an invalid delay at beat %f, length %f.", + fFreezeBeat, fFreezeSeconds ); } } -void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam ) +void SMLoader::ProcessTimeSignatures( TimingData &out, const RString line, const int rowsPerBeat ) { vector vs1; - split( sParam, ",", vs1 ); + split( line, ",", vs1 ); FOREACH_CONST( RString, vs1, s1 ) { @@ -354,40 +382,55 @@ void SMLoader::ProcessTimeSignatures( TimingData &out, const RString sParam ) if( vs2.size() < 3 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid time signature change with %i values.", + static_cast(vs2.size()) ); continue; } - const float fBeat = StringToFloat( vs2[0] ); + const float fBeat = RowToBeat( vs2[0], rowsPerBeat ); - TimeSignatureSegment seg( BeatToNoteRow( fBeat ), StringToInt( vs2[1] ), StringToInt( vs2[2] )); + TimeSignatureSegment * seg = + new TimeSignatureSegment(fBeat, + StringToInt( vs2[1] ), + StringToInt( vs2[2] )); if( fBeat < 0 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid time signature change with beat %f.", + fBeat ); continue; } - if( seg.GetNum() < 1 ) + if( seg->GetNum() < 1 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.GetNum() ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid time signature change with beat %f, iNumerator %i.", + fBeat, seg->GetNum() ); continue; } - if( seg.GetDen() < 1 ) + if( seg->GetDen() < 1 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.GetDen() ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid time signature change with beat %f, iDenominator %i.", + fBeat, seg->GetDen() ); continue; } - out.AddTimeSignatureSegment( seg ); + out.AddSegment( SEGMENT_TIME_SIG, seg ); } } -void SMLoader::ProcessTickcounts( TimingData &out, const RString sParam ) +void SMLoader::ProcessTickcounts( TimingData &out, const RString line, const int rowsPerBeat ) { vector arrayTickcountExpressions; - split( sParam, ",", arrayTickcountExpressions ); + split( line, ",", arrayTickcountExpressions ); for( unsigned f=0; f vs1; + split( line, ",", vs1 ); + + FOREACH_CONST( RString, vs1, s1 ) + { + vector vs2; + split( *s1, "=", vs2 ); + + if( vs2[0] == 0 && vs2.size() == 2 ) // First one always seems to have 2. + { + vs2.push_back("0"); + } + + if( vs2.size() == 3 ) // use beats by default. + { + vs2.push_back("0"); + } + + if( vs2.size() < 4 ) + { + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an speed change with %i values.", + static_cast(vs2.size()) ); + continue; + } + + const float fBeat = RowToBeat( vs2[0], rowsPerBeat ); + + SpeedSegment * seg = new SpeedSegment(fBeat, + StringToFloat( vs2[1] ), + StringToFloat( vs2[2] )); + seg->SetUnit(StringToInt(vs2[3])); + + if( fBeat < 0 ) + { + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an speed change with beat %f.", + fBeat ); + continue; + } + + if( seg->GetLength() < 0 ) + { + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an speed change with beat %f, length %f.", + fBeat, seg->GetLength() ); + continue; + } + + out.AddSegment( SEGMENT_SPEED, seg ); + } +} + +void SMLoader::ProcessFakes( TimingData &out, const RString line, const int rowsPerBeat ) +{ + vector arrayFakeExpressions; + split( line, ",", arrayFakeExpressions ); + + for( unsigned b=0; b arrayFakeValues; + split( arrayFakeExpressions[b], "=", arrayFakeValues ); + if( arrayFakeValues.size() != 2 ) + { + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.", + arrayFakeExpressions[b].c_str() ); + continue; + } + + const float fBeat = RowToBeat( arrayFakeValues[0], rowsPerBeat ); + const float fNewBeat = StringToFloat( arrayFakeValues[1] ); + + if(fNewBeat > 0) + out.AddSegment( SEGMENT_FAKE, new FakeSegment(fBeat, fNewBeat) ); + else + { + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid Fake at beat %f, BPM %f.", + fBeat, fNewBeat ); + } } } @@ -495,7 +630,66 @@ bool SMLoader::LoadFromBGChangesString( BackgroundChange &change, const RString return aBGChangeValues.size() >= 2; } -bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache ) +bool SMLoader::LoadNoteDataFromSimfile( const RString &path, Steps &out ) +{ + MsdFile msd; + if( !msd.ReadFile( path, true ) ) // unescape + { + LOG->UserLog("Song file", + path, + "couldn't be opened: %s", + msd.GetError().c_str() ); + return false; + } + for (unsigned i = 0; iUserLog("Song file", + path, + "has %d fields in a #NOTES tag, but should have at least 7.", + iNumParams ); + continue; + } + + RString stepsType = sParams[1]; + RString description = sParams[2]; + RString difficulty = sParams[3]; + Trim(stepsType); + Trim(description); + Trim(difficulty); + // Remember our old versions. + if (difficulty.CompareNoCase("smaniac") == 0) + { + difficulty = "Challenge"; + } + + if(!(out.m_StepsType == GAMEMAN->StringToStepsType( stepsType ) && + out.GetDescription() == description && + out.GetDifficulty() == StringToDifficulty(difficulty))) + { + continue; + } + + RString noteData = sParams[6]; + Trim( noteData ); + out.SetSMNoteData( noteData ); + out.TidyUpData(); + return true; + } + } + return false; +} + +bool SMLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache ) { LOG->Trace( "Song::LoadFromSMFile(%s)", sPath.c_str() ); @@ -507,6 +701,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache } out.m_SongTiming.m_sFile = sPath; + out.m_sSongFileName = sPath; for( unsigned i=0; iSetSongTitle(sParams[1]); + } else if( sValueName=="SUBTITLE" ) out.m_sSubTitle = sParams[1]; @@ -601,37 +799,19 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache } else if( sValueName=="LASTBEATHINT" ) - out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] ); + { + // unable to identify at this point: ignore + } else if( sValueName=="MUSICBYTES" ) ; /* ignore */ - /* We calculate these. Some SMs in circulation have bogus values for - * these, so make sure we always calculate it ourself. */ - else if( sValueName=="FIRSTBEAT" ) + // cache tags from older SM files: ignore. + else if(sValueName=="FIRSTBEAT" || sValueName=="LASTBEAT" || + sValueName=="SONGFILENAME" || sValueName=="HASMUSIC" || + sValueName=="HASBANNER") { - if( bFromCache ) - out.m_fFirstBeat = StringToFloat( sParams[1] ); - } - else if( sValueName=="LASTBEAT" ) - { - if( bFromCache ) - out.m_fLastBeat = StringToFloat( sParams[1] ); - } - else if( sValueName=="SONGFILENAME" ) - { - if( bFromCache ) - out.m_sSongFileName = sParams[1]; - } - else if( sValueName=="HASMUSIC" ) - { - if( bFromCache ) - out.m_bHasMusic = StringToInt( sParams[1] ) != 0; - } - else if( sValueName=="HASBANNER" ) - { - if( bFromCache ) - out.m_bHasBanner = StringToInt( sParams[1] ) != 0; + ; } else if( sValueName=="SAMPLESTART" ) @@ -707,7 +887,8 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache // Attacks loaded from file else if( sValueName=="ATTACKS" ) { - ProcessAttacks( out, sParams ); + ProcessAttackString(out.m_sAttackString, sParams); + ProcessAttacks(out.m_Attacks, sParams); } else if( sValueName=="NOTES" || sValueName=="NOTES2" ) @@ -719,7 +900,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache } Steps* pNewNotes = out.CreateSteps(); - LoadFromSMTokens( + LoadFromTokens( sParams[1], sParams[2], sParams[3], @@ -728,6 +909,7 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache sParams[6], *pNewNotes ); + pNewNotes->SetFilename(sPath); out.AddSteps( pNewNotes ); } // XXX: Does anyone know what LEADTRACK is for? -Wolfman2000 @@ -738,38 +920,12 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache } // Ensure all warps from negative time changes are in order. - sort(out.m_SongTiming.m_WarpSegments.begin(), out.m_SongTiming.m_WarpSegments.end()); + vector &warps = out.m_SongTiming.allTimingSegments[SEGMENT_WARP]; + sort(warps.begin(), warps.end()); TidyUpData( out, bFromCache ); return true; } -bool SMLoader::LoadFromDir( const RString &sPath, Song &out ) -{ - vector aFileNames; - GetApplicableFiles( sPath, aFileNames ); - - if( aFileNames.size() > 1 ) - { - LOG->UserLog( "Song", sPath, "has more than one SM file. There can be only one (unless you are using TougaKiryuu's AnimeMix files somehow, which assume a different version of StepMania)!" ); - return false; - /* - for( unsigned i=0; i= 1 ); - - return LoadFromSMFile( sPath + aFileNames[0], out ); -} - bool SMLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) { LOG->Trace( "SMLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() ); @@ -819,6 +975,7 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath } RString sSongFullTitle = sParams[1]; + this->SetSongTitle(sParams[1]); sSongFullTitle.Replace( '\\', '/' ); pSong = SONGMAN->FindSong( sSongFullTitle ); @@ -853,7 +1010,7 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath return true; Steps* pNewNotes = pSong->CreateSteps(); - LoadFromSMTokens( + LoadFromTokens( sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], *pNewNotes); @@ -881,6 +1038,11 @@ bool SMLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath } +void SMLoader::GetApplicableFiles( const RString &sPath, vector &out ) +{ + GetDirListing( sPath + RString("*" + this->GetFileExtension() ), out ); +} + void SMLoader::TidyUpData( Song &song, bool bFromCache ) { /* @@ -917,9 +1079,10 @@ void SMLoader::TidyUpData( Song &song, bool bFromCache ) if( bFromCache ) break; + float lastBeat = song.GetLastBeat(); /* If BGChanges already exist after the last beat, don't add the * background in the middle. */ - if( !bg.empty() && bg.back().m_fStartBeat-0.0001f >= song.m_fLastBeat ) + if( !bg.empty() && bg.back().m_fStartBeat-0.0001f >= lastBeat ) break; // If the last BGA is already the song BGA, don't add a duplicate. @@ -929,10 +1092,14 @@ void SMLoader::TidyUpData( Song &song, bool bFromCache ) if( !IsAFile( song.GetBackgroundPath() ) ) break; - bg.push_back( BackgroundChange(song.m_fLastBeat,song.m_sBackgroundFile) ); + + bg.push_back( BackgroundChange(lastBeat,song.m_sBackgroundFile) ); } while(0); } - song.TidyUpData( bFromCache ); + if (bFromCache) + { + song.TidyUpData( bFromCache, true ); + } } /* diff --git a/src/NotesLoaderSM.h b/src/NotesLoaderSM.h index 94dfdd2dfe..6ba22589d6 100644 --- a/src/NotesLoaderSM.h +++ b/src/NotesLoaderSM.h @@ -3,6 +3,7 @@ #include "GameConstantsAndTypes.h" #include "BackgroundUtil.h" +#include "Attack.h" #include "MsdFile.h" // we require the struct from here. class Song; @@ -15,33 +16,186 @@ class TimingData; * This was brought in from StepMania 4's recent betas. */ const float FAST_BPM_WARP = 9999999.f; -/** @brief Reads a Song from an .SM file. */ -namespace SMLoader -{ - void LoadFromSMTokens( RString sStepsType, RString sDescription, RString sDifficulty, - RString sMeter, RString sRadarValues, RString sNoteData, Steps &out ); - - bool LoadFromDir( const RString &sPath, Song &out ); - void TidyUpData( Song &song, bool bFromCache ); +/** @brief The maximum file size for edits. */ +const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB - bool LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache = false ); - void GetApplicableFiles( const RString &sPath, vector &out ); - bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); - bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot ); - bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); - bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression ); +/** @brief Reads a Song from an .SM file. */ +struct SMLoader +{ + SMLoader() : fileExt(".sm"), songTitle() {} + SMLoader(RString ext) : fileExt(ext), songTitle() {} - bool ProcessBPMs( TimingData &, const RString ); - void ProcessStops( TimingData &, const RString ); - void ProcessDelays( TimingData &, const RString ); - void ProcessTimeSignatures( TimingData &, const RString ); - void ProcessTickcounts( TimingData &, const RString ); - void ProcessBGChanges( Song &out, const RString &sValueName, + virtual ~SMLoader() {} + + /** + * @brief Attempt to load a song from a specified path. + * @param sPath a const reference to the path on the hard drive to check. + * @param out a reference to the Song that will retrieve the song information. + * @return its success or failure. + */ + virtual bool LoadFromDir( const RString &sPath, Song &out ); + /** + * @brief Perform some cleanup on the loaded song. + * @param song a reference to the song that may need cleaning up. + * @param bFromCache a flag to determine if this song is loaded from a cache file. + */ + virtual void TidyUpData( Song &song, bool bFromCache ); + + /** + * @brief Retrieve the relevant notedata from the simfile. + * @param path the path where the simfile lives. + * @param out the Steps we are loading the data into. */ + virtual bool LoadNoteDataFromSimfile(const RString &path, Steps &out ); + + /** + * @brief Attempt to load the specified sm file. + * @param sPath a const reference to the path on the hard drive to check. + * @param out a reference to the Song that will retrieve the song information. + * @param bFromCache a check to see if we are getting certain information from the cache file. + * @return its success or failure. + */ + virtual bool LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache = false ); + /** + * @brief Retrieve the list of .sm files. + * @param sPath a const reference to the path on the hard drive to check. + * @param out a vector of files found in the path. + */ + virtual void GetApplicableFiles( const RString &sPath, vector &out ); + virtual bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); + virtual bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot ); + virtual bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); + virtual bool LoadFromBGChangesString(BackgroundChange &change, + const RString &sBGChangeExpression ); + + /** + * @brief Process the BPM Segments from the string. + * @param out the TimingData being modified. + * @param line the string in question. + * @param rowsPerBeat the number of rows per beat for this purpose. + * @return true if there was at least one segment found, false otherwise. */ + bool ProcessBPMs(TimingData & out, + const RString line, + const int rowsPerBeat = -1); + /** + * @brief Process the Stop Segments from the string. + * @param out the TimingData being modified. + * @param line the string in question. + * @param rowsPerBeat the number of rows per beat for this purpose. */ + void ProcessStops(TimingData & out, + const RString line, + const int rowsPerBeat = -1); + /** + * @brief Process the Delay Segments from the string. + * @param out the TimingData being modified. + * @param line the string in question. + * @param rowsPerBeat the number of rows per beat for this purpose. */ + void ProcessDelays(TimingData & out, + const RString line, + const int rowsPerBeat = -1); + /** + * @brief Process the Time Signature Segments from the string. + * @param out the TimingData being modified. + * @param line the string in question. + * @param rowsPerBeat the number of rows per beat for this purpose. */ + void ProcessTimeSignatures(TimingData & out, + const RString line, + const int rowsPerBeat = -1); + /** + * @brief Process the Tickcount Segments from the string. + * @param out the TimingData being modified. + * @param line the string in question. + * @param rowsPerBeat the number of rows per beat for this purpose. */ + void ProcessTickcounts(TimingData & out, + const RString line, + const int rowsPerBeat = -1); + + /** + * @brief Process the Speed Segments from the string. + * @param out the TimingData being modified. + * @param line the string in question. + * @param rowsPerBeat the number of rows per beat for this purpose. */ + virtual void ProcessSpeeds(TimingData & out, + const RString line, + const int rowsPerBeat = -1); + + virtual void ProcessCombos(TimingData & out, + const RString line, + const int rowsPerBeat = -1) {} + + /** + * @brief Process the Fake Segments from the string. + * @param out the TimingData being modified. + * @param line the string in question. + * @param rowsPerBeat the number of rows per beat for this purpose. */ + virtual void ProcessFakes(TimingData & out, + const RString line, + const int rowsPerBeat = -1); + + virtual void ProcessBGChanges( Song &out, const RString &sValueName, const RString &sPath, const RString &sParam ); - void ProcessAttacks( Song &out, MsdFile::value_t sParams ); + + /** + * @brief Put the attacks in the attacks string. + * @param attacks the attack string. + * @param params the params from the simfile. */ + virtual void ProcessAttackString(vector &attacks, MsdFile::value_t params); + + /** + * @brief Put the attacks in the attacks array. + * @param attacks the attacks array. + * @param params the params from the simfile. */ + void ProcessAttacks( AttackArray &attacks, MsdFile::value_t params ); void ProcessInstrumentTracks( Song &out, const RString &sParam ); -} + + /** + * @brief Convert a row value to the proper beat value. + * + * This is primarily used for assistance with converting SMA files. + * @param line The line that contains the value. + * @param rowsPerBeat the number of rows per beat according to the original file. + * @return the converted beat value. */ + float RowToBeat(RString line, const int rowsPerBeat); + +protected: + /** + * @brief Process the different tokens we have available to get NoteData. + * @param stepsType The current StepsType. + * @param description The description of the chart. + * @param difficulty The difficulty (in words) of the chart. + * @param meter the difficulty (in numbers) of the chart. + * @param radarValues the calculated radar values. + * @param noteData the note data itself. + * @param out the Steps getting the data. */ + virtual void LoadFromTokens(RString sStepsType, + RString sDescription, + RString sDifficulty, + RString sMeter, + RString sRadarValues, + RString sNoteData, + Steps &out); + + /** + * @brief Retrieve the file extension associated with this loader. + * @return the file extension. */ + RString GetFileExtension() const { return fileExt; } + + /** + * @brief Set the song title. + * @param t the song title. */ + virtual void SetSongTitle(const RString & title); + + /** + * @brief Get the song title. + * @return the song title. */ + virtual RString GetSongTitle() const; + +private: + /** @brief The file extension in use. */ + const RString fileExt; + /** @brief The song title that is being processed. */ + RString songTitle; +}; #endif diff --git a/src/NotesLoaderSMA.cpp b/src/NotesLoaderSMA.cpp index c902b1f103..1a3cf4ef00 100644 --- a/src/NotesLoaderSMA.cpp +++ b/src/NotesLoaderSMA.cpp @@ -14,240 +14,6 @@ #include "Steps.h" #include "Attack.h" -/** - * @brief A custom .edit file can only be so big before we have to reject it. - */ -const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB - -bool SMALoader::LoadFromBGChangesString( BackgroundChange &change, - const RString &sBGChangeExpression ) -{ - return SMLoader::LoadFromBGChangesString(change, sBGChangeExpression); -} - -bool SMALoader::LoadFromDir( const RString &sPath, Song &out ) -{ - vector aFileNames; - GetApplicableFiles( sPath, aFileNames ); - - if( aFileNames.size() > 1 ) - { - LOG->UserLog( "Song", sPath, "has more than one SMA file. Only one SMA file is allowed per song." ); - return false; - } - ASSERT( aFileNames.size() == 1 ); - return LoadFromSMAFile( sPath + aFileNames[0], out ); -} - -float SMALoader::RowToBeat( RString sLine, const int iRowsPerBeat ) -{ - if( sLine.find("R") || sLine.find("r") ) - { - sLine = sLine.Left(sLine.size()-1); - return StringToFloat( sLine ) / iRowsPerBeat; - } - else - { - return StringToFloat( sLine ); - } -} - -bool SMALoader::ProcessBPMs( TimingData &out, const int iRowsPerBeat, const RString sParam ) -{ - vector arrayBPMChangeExpressions; - split( sParam, ",", arrayBPMChangeExpressions ); - - // prepare storage variables for negative BPMs -> Warps. - float negBeat = -1; - float negBPM = 1; - float highspeedBeat = -1; - bool bNotEmpty = false; - - for( unsigned b=0; b arrayBPMChangeValues; - split( arrayBPMChangeExpressions[b], "=", arrayBPMChangeValues ); - // XXX: Hard to tell which file caused this. - if( arrayBPMChangeValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #BPMs value \"%s\" (must have exactly one '='), ignored.", - arrayBPMChangeExpressions[b].c_str() ); - continue; - } - - bNotEmpty = true; - - const float fBeat = RowToBeat( arrayBPMChangeValues[0], iRowsPerBeat ); - const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); - - if( fNewBPM < 0.0f ) - { - out.m_bHasNegativeBpms = true; - negBeat = fBeat; - negBPM = fNewBPM; - } - else if( fNewBPM > 0.0f ) - { - // add in a warp. - if( negBPM < 0 ) - { - float endBeat = fBeat + (fNewBPM / -negBPM) * (fBeat - negBeat); - WarpSegment new_seg(negBeat, endBeat - negBeat); - out.AddWarpSegment( new_seg ); - - negBeat = -1; - negBPM = 1; - } - // too fast. make it a warp. - if( fNewBPM > FAST_BPM_WARP ) - { - highspeedBeat = fBeat; - } - else - { - // add in a warp. - if( highspeedBeat > 0 ) - { - WarpSegment new_seg(highspeedBeat, fBeat - highspeedBeat); - out.AddWarpSegment( new_seg ); - highspeedBeat = -1; - } - { - BPMSegment new_seg( BeatToNoteRow( fBeat ), fNewBPM ); - out.AddBPMSegment( new_seg ); - } - } - } - } - - return bNotEmpty; -} - -void SMALoader::ProcessStops( TimingData &out, const int iRowsPerBeat, const RString sParam ) -{ - vector arrayFreezeExpressions; - split( sParam, ",", arrayFreezeExpressions ); - - // Prepare variables for negative stop conversion. - float negBeat = -1; - float negPause = 0; - - for( unsigned f=0; f arrayFreezeValues; - split( arrayFreezeExpressions[f], "=", arrayFreezeValues ); - if( arrayFreezeValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #STOPS value \"%s\" (must have exactly one '='), ignored.", - arrayFreezeExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = RowToBeat( arrayFreezeValues[0], iRowsPerBeat ); - const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); - - // Process the prior stop. - if( negPause > 0 ) - { - BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat)); - float fSecondsPerBeat = 60 / oldBPM.GetBPM(); - float fSkipBeats = negPause / fSecondsPerBeat; - - if( negBeat + fSkipBeats > fFreezeBeat ) - fSkipBeats = fFreezeBeat - negBeat; - - WarpSegment ws( negBeat, fSkipBeats); - out.AddWarpSegment( ws ); - - negBeat = -1; - negPause = 0; - } - - if( fFreezeSeconds < 0.0f ) - { - negBeat = fFreezeBeat; - negPause = -fFreezeSeconds; - } - else if( fFreezeSeconds > 0.0f ) - { - StopSegment ss( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); - out.AddStopSegment( ss ); - } - - } - - // Process the prior stop if there was one. - if( negPause > 0 ) - { - BPMSegment oldBPM = out.GetBPMSegmentAtRow(BeatToNoteRow(negBeat)); - float fSecondsPerBeat = 60 / oldBPM.GetBPM(); - float fSkipBeats = negPause / fSecondsPerBeat; - - WarpSegment ws( negBeat, fSkipBeats); - out.AddWarpSegment( ws ); - } -} - -void SMALoader::ProcessDelays( TimingData &out, const int iRowsPerBeat, const RString sParam ) -{ - vector arrayDelayExpressions; - split( sParam, ",", arrayDelayExpressions ); - - for( unsigned f=0; f arrayDelayValues; - split( arrayDelayExpressions[f], "=", arrayDelayValues ); - if( arrayDelayValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #DELAYS value \"%s\" (must have exactly one '='), ignored.", - arrayDelayExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = RowToBeat( arrayDelayValues[0], iRowsPerBeat ); - const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); - - StopSegment new_seg( fFreezeBeat, fFreezeSeconds, true ); - // XXX: Remove Negatives Bug? - new_seg.SetBeat(fFreezeBeat); - new_seg.SetPause(fFreezeSeconds); - - // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - - if(fFreezeSeconds > 0.0f) - out.AddStopSegment( new_seg ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); - } -} - -void SMALoader::ProcessTickcounts( TimingData &out, const int iRowsPerBeat, const RString sParam ) -{ - vector arrayTickcountExpressions; - split( sParam, ",", arrayTickcountExpressions ); - - for( unsigned f=0; f arrayTickcountValues; - split( arrayTickcountExpressions[f], "=", arrayTickcountValues ); - if( arrayTickcountValues.size() != 2 ) - { - // XXX: Hard to tell which file caused this. - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #TICKCOUNTS value \"%s\" (must have exactly one '='), ignored.", - arrayTickcountExpressions[f].c_str() ); - continue; - } - - const float fTickcountBeat = RowToBeat( arrayTickcountValues[0], iRowsPerBeat ); - int iTicks = clamp(atoi( arrayTickcountValues[1] ), 0, ROWS_PER_BEAT); - - TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); - out.AddTickcountSegment( new_seg ); - } -} - void SMALoader::ProcessMultipliers( TimingData &out, const int iRowsPerBeat, const RString sParam ) { vector arrayMultiplierExpressions; @@ -257,16 +23,23 @@ void SMALoader::ProcessMultipliers( TimingData &out, const int iRowsPerBeat, con { vector arrayMultiplierValues; split( arrayMultiplierExpressions[f], "=", arrayMultiplierValues ); - if( arrayMultiplierValues.size() != 2 ) + unsigned size = arrayMultiplierValues.size(); + if( size < 2 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #MULTIPLIER value \"%s\" (must have exactly one '='), ignored.", + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid #MULTIPLIER value \"%s\" (must have at least one '='), ignored.", arrayMultiplierExpressions[f].c_str() ); continue; } const float fComboBeat = RowToBeat( arrayMultiplierValues[0], iRowsPerBeat ); - const int iCombos = StringToInt( arrayMultiplierValues[1] ); - ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); - out.AddComboSegment( new_seg ); + const int iCombos = StringToInt( arrayMultiplierValues[1] ); // always true. + // hoping I'm right here: SMA files can use 6 values after the row/beat. + const int iMisses = (size == 2 || size == 4 ? + iCombos : + StringToInt(arrayMultiplierValues[2])); + out.AddSegment(SEGMENT_COMBO, + new ComboSegment( fComboBeat, iCombos, iMisses )); } } @@ -282,39 +55,45 @@ void SMALoader::ProcessBeatsPerMeasure( TimingData &out, const RString sParam ) if( vs2.size() < 2 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid beats per measure change with %i values.", (int)vs2.size() ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid beats per measure change with %i values.", + static_cast(vs2.size()) ); continue; } const float fBeat = StringToFloat( vs2[0] ); - TimeSignatureSegment seg( BeatToNoteRow( fBeat ), StringToInt( vs2[1] ), 4 ); + TimeSignatureSegment * seg = new TimeSignatureSegment(fBeat, + StringToInt(vs2[1]), + 4 ); if( fBeat < 0 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid time signature change with beat %f.", + fBeat ); continue; } - if( seg.GetNum() < 1 ) + if( seg->GetNum() < 1 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.GetNum() ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid time signature change with beat %f, iNumerator %i.", + fBeat, seg->GetNum() ); continue; } - out.AddTimeSignatureSegment( seg ); + out.AddSegment( SEGMENT_TIME_SIG, seg ); } } -float BeatToSeconds(float fromBeat, RString toSomething) -{ - return 0; -} - -void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RString sParam ) +void SMALoader::ProcessSpeeds( TimingData &out, const RString line, const int rowsPerBeat ) { vector vs1; - split( sParam, ",", vs1 ); + split( line, ",", vs1 ); FOREACH_CONST( RString, vs1, s1 ) { @@ -331,11 +110,14 @@ void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RS if( vs2.size() < 3 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with %i values.", (int)vs2.size() ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an speed change with %i values.", + static_cast(vs2.size()) ); continue; } - const float fBeat = RowToBeat( vs2[0], iRowsPerBeat ); + const float fBeat = RowToBeat( vs2[0], rowsPerBeat ); RString backup = vs2[2]; Trim(vs2[2], "s"); @@ -343,76 +125,34 @@ void SMALoader::ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RS unsigned short tmp = ((backup != vs2[2]) ? 1 : 0); - SpeedSegment seg(fBeat, StringToFloat( vs2[1] ), StringToFloat(vs2[2]), tmp); - //seg.SetUnit(tmp); + SpeedSegment * seg = new SpeedSegment(fBeat, + StringToFloat( vs2[1] ), + StringToFloat(vs2[2]), + tmp); if( fBeat < 0 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f.", fBeat ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an speed change with beat %f.", + fBeat ); continue; } - if( seg.GetLength() < 0 ) + if( seg->GetLength() < 0 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f, length %f.", fBeat, seg.GetLength() ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an speed change with beat %f, length %f.", + fBeat, seg->GetLength() ); continue; } - out.AddSpeedSegment( seg ); + out.AddSegment( SEGMENT_SPEED, seg ); } } -void SMALoader::ProcessFakes( TimingData &out, const int iRowsPerBeat, const RString sParam ) -{ - vector arrayFakeExpressions; - split( sParam, ",", arrayFakeExpressions ); - - for( unsigned b=0; b arrayFakeValues; - split( arrayFakeExpressions[b], "=", arrayFakeValues ); - // XXX: Hard to tell which file caused this. - if( arrayFakeValues.size() != 2 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.", - arrayFakeExpressions[b].c_str() ); - continue; - } - - const float fBeat = RowToBeat( arrayFakeValues[0], iRowsPerBeat ); - const float fNewBeat = StringToFloat( arrayFakeValues[1] ); - - if(fNewBeat > 0) - out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) ); - else - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat ); - } - } -} - - -void SMALoader::LoadFromSMATokens( - RString sStepsType, - RString sDescription, - RString sDifficulty, - RString sMeter, - RString sRadarValues, - RString sNoteData, - Steps &out -) -{ - SMLoader::LoadFromSMTokens( sStepsType, sDescription, - sDifficulty, sMeter, sRadarValues, - sNoteData, out ); -} - -void SMALoader::TidyUpData( Song &song, bool bFromCache ) -{ - SMLoader::TidyUpData( song, bFromCache ); -} - -bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) +bool SMALoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache ) { LOG->Trace( "Song::LoadFromSMAFile(%s)", sPath.c_str() ); @@ -424,6 +164,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) } out.m_SongTiming.m_sFile = sPath; // songs still have their fallback timing. + out.m_sSongFileName = sPath; int state = SMA_GETTING_SONG_INFO; Steps* pNewNotes = NULL; @@ -441,7 +182,10 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) /* Don't use GetMainAndSubTitlesFromFullTitle; that's only for heuristically * splitting other formats that *don't* natively support #SUBTITLE. */ if( sValueName=="TITLE" ) + { out.m_sMainTitle = sParams[1]; + this->SetSongTitle(sParams[1]); + } else if( sValueName=="SUBTITLE" ) out.m_sSubTitle = sParams[1]; @@ -491,30 +235,16 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) } else if( sValueName=="LASTBEATHINT" ) - out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] ); - + { + // can't identify at this position: ignore. + } else if( sValueName=="MUSICBYTES" ) ; /* ignore */ - /* We calculate these. Some SMs in circulation have bogus values for - * these, so make sure we always calculate it ourself. */ - else if( sValueName=="FIRSTBEAT" ) - { - ; - } - else if( sValueName=="LASTBEAT" ) - { - ; - } - else if( sValueName=="SONGFILENAME" ) - { - ; - } - else if( sValueName=="HASMUSIC" ) - { - ; - } - else if( sValueName=="HASBANNER" ) + // Cache tags: ignore. + else if (sValueName=="FIRSTBEAT" || sValueName=="LASTBEAT" || + sValueName=="SONGFILENAME" || sValueName=="HASMUSIC" || + sValueName=="HASBANNER" ) { ; } @@ -603,7 +333,10 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) else if( StringToInt(sParams[1]) > 0 ) out.m_SelectionDisplay = out.SHOW_ALWAYS; else - LOG->UserLog( "Song file", sPath, "has an unknown #SELECTABLE value, \"%s\"; ignored.", sParams[1].c_str() ); + LOG->UserLog("Song file", + sPath, + "has an unknown #SELECTABLE value, \"%s\"; ignored.", + sParams[1].c_str() ); } else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" ) @@ -635,28 +368,28 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) { TimingData &timing = (state == SMA_GETTING_STEP_INFO ? pNewNotes->m_Timing : out.m_SongTiming); - ProcessBPMs( timing, iRowsPerBeat, sParams[1] ); + ProcessBPMs( timing, sParams[1], iRowsPerBeat ); } else if( sValueName=="STOPS" || sValueName=="FREEZES" ) { TimingData &timing = (state == SMA_GETTING_STEP_INFO ? pNewNotes->m_Timing : out.m_SongTiming); - ProcessStops( timing, iRowsPerBeat, sParams[1] ); + ProcessStops( timing, sParams[1], iRowsPerBeat ); } else if( sValueName=="DELAYS" ) { TimingData &timing = (state == SMA_GETTING_STEP_INFO ? pNewNotes->m_Timing : out.m_SongTiming); - ProcessDelays( timing, iRowsPerBeat, sParams[1] ); + ProcessDelays( timing, sParams[1], iRowsPerBeat ); } else if( sValueName=="TICKCOUNT" ) { TimingData &timing = (state == SMA_GETTING_STEP_INFO ? pNewNotes->m_Timing : out.m_SongTiming); - ProcessTickcounts( timing, iRowsPerBeat, sParams[1] ); + ProcessTickcounts( timing, sParams[1], iRowsPerBeat ); } else if( sValueName=="SPEED" ) @@ -665,7 +398,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) ? pNewNotes->m_Timing : out.m_SongTiming); RString tmp = sParams[1]; Trim( tmp ); - ProcessSpeeds( timing, iRowsPerBeat, tmp ); + ProcessSpeeds( timing, tmp, iRowsPerBeat ); } else if( sValueName=="MULTIPLIER" ) @@ -679,7 +412,7 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) { TimingData &timing = (state == SMA_GETTING_STEP_INFO ? pNewNotes->m_Timing : out.m_SongTiming); - ProcessFakes( timing, iRowsPerBeat, sParams[1] ); + ProcessFakes( timing, sParams[1], iRowsPerBeat ); } else if( sValueName=="METERTYPE" ) @@ -695,18 +428,22 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) // Attacks loaded from file else if( sValueName=="ATTACKS" ) { - SMLoader::ProcessAttacks( out, sParams ); + ProcessAttackString(out.m_sAttackString, sParams); + ProcessAttacks(out.m_Attacks, sParams); } else if( sValueName=="NOTES" || sValueName=="NOTES2" ) { if( iNumParams < 7 ) { - LOG->UserLog( "Song file", sPath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); + LOG->UserLog("Song file", + sPath, + "has %d fields in a #NOTES tag, but should have at least 7.", + iNumParams ); continue; } - LoadFromSMATokens( + LoadFromTokens( sParams[1], sParams[2], sParams[3], @@ -714,131 +451,19 @@ bool SMALoader::LoadFromSMAFile( const RString &sPath, Song &out ) sParams[5], sParams[6], *pNewNotes ); - + pNewNotes->SetFilename(sPath); out.AddSteps( pNewNotes ); } else if( sValueName=="TIMESIGNATURES" || sValueName=="LEADTRACK" ) ; else - LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() ); + LOG->UserLog("Song file", + sPath, + "has an unexpected value named \"%s\".", + sValueName.c_str() ); } TidyUpData(out, false); - out.TidyUpData(); - return true; -} - -void SMALoader::GetApplicableFiles( const RString &sPath, vector &out ) -{ - GetDirListing( sPath + RString("*.sma"), out ); -} - -bool SMALoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) -{ - LOG->Trace( "SMALoader::LoadEditFromFile(%s)", sEditFilePath.c_str() ); - - int iBytes = FILEMAN->GetFileSizeInBytes( sEditFilePath ); - if( iBytes > MAX_EDIT_STEPS_SIZE_BYTES ) - { - LOG->UserLog( "Edit file", sEditFilePath, "is unreasonably large. It won't be loaded." ); - return false; - } - - MsdFile msd; - if( !msd.ReadFile( sEditFilePath, true ) ) // unescape - { - LOG->UserLog( "Edit file", sEditFilePath, "couldn't be opened: %s", msd.GetError().c_str() ); - return false; - } - - return LoadEditFromMsd( msd, sEditFilePath, slot, bAddStepsToSong ); -} - -bool SMALoader::LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot ) -{ - MsdFile msd; - msd.ReadFromString( sBuffer, true ); // unescape - return LoadEditFromMsd( msd, sEditFilePath, slot, true ); -} - -bool SMALoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) -{ - Song* pSong = NULL; - - for( unsigned i=0; iUserLog( "Edit file", sEditFilePath, "has more than one #SONG tag." ); - return false; - } - - RString sSongFullTitle = sParams[1]; - sSongFullTitle.Replace( '\\', '/' ); - - pSong = SONGMAN->FindSong( sSongFullTitle ); - if( pSong == NULL ) - { - LOG->UserLog( "Edit file", sEditFilePath, "requires a song \"%s\" that isn't present.", sSongFullTitle.c_str() ); - return false; - } - - if( pSong->GetNumStepsLoadedFromProfile(slot) >= MAX_EDITS_PER_SONG_PER_PROFILE ) - { - LOG->UserLog( "Song file", sSongFullTitle, "already has the maximum number of edits allowed for ProfileSlotP%d.", slot+1 ); - return false; - } - } - - else if( sValueName=="NOTES" ) - { - if( pSong == NULL ) - { - LOG->UserLog( "Edit file", sEditFilePath, "doesn't have a #SONG tag preceeding the first #NOTES tag." ); - return false; - } - - if( iNumParams < 7 ) - { - LOG->UserLog( "Edit file", sEditFilePath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); - continue; - } - - if( !bAddStepsToSong ) - return true; - - Steps* pNewNotes = pSong->CreateSteps(); - LoadFromSMATokens( - sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], - *pNewNotes); - - pNewNotes->SetLoadedFromProfile( slot ); - pNewNotes->SetDifficulty( Difficulty_Edit ); - pNewNotes->SetFilename( sEditFilePath ); - - if( pSong->IsEditAlreadyLoaded(pNewNotes) ) - { - LOG->UserLog( "Edit file", sEditFilePath, "is a duplicate of another edit that was already loaded." ); - SAFE_DELETE( pNewNotes ); - return false; - } - - pSong->AddSteps( pNewNotes ); - return true; // Only allow one Steps per edit file! - } - else - { - LOG->UserLog( "Edit file", sEditFilePath, "has an unexpected value \"%s\".", sValueName.c_str() ); - } - } - + out.TidyUpData(false, true); return true; } diff --git a/src/NotesLoaderSMA.h b/src/NotesLoaderSMA.h index c9e3dfa811..f38acac470 100644 --- a/src/NotesLoaderSMA.h +++ b/src/NotesLoaderSMA.h @@ -2,6 +2,7 @@ #define NOTES_LOADER_SMA_H #include "GameConstantsAndTypes.h" +#include "NotesLoaderSM.h" #include "BackgroundUtil.h" class MsdFile; @@ -20,37 +21,21 @@ enum SMALoadingStates }; /** @brief Reads a Song from a .SMA file. */ -namespace SMALoader -{ - void LoadFromSMATokens( RString sStepsType, - RString sDescription, - RString sDifficulty, - RString sMeter, - RString sRadarValues, - RString sNoteData, - Steps &out ); +struct SMALoader : public SMLoader +{ + SMALoader() : SMLoader(".sma") {} - bool LoadFromDir( const RString &sPath, Song &out ); - void TidyUpData( Song &song, bool bFromCache ); - - bool LoadFromSMAFile( const RString &sPath, Song &out ); - void GetApplicableFiles( const RString &sPath, vector &out ); - - bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); - bool LoadEditFromBuffer( const RString &sBuffer, const RString &sEditFilePath, ProfileSlot slot ); - bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); - bool LoadFromBGChangesString( BackgroundChange &change, const RString &sBGChangeExpression ); + virtual bool LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache = false ); + void ProcessBeatsPerMeasure( TimingData &out, const RString sParam ); - bool ProcessBPMs( TimingData &out, const int iRowsPerBeat, const RString sParam ); - void ProcessStops( TimingData &out, const int iRowsPerBeat, const RString sParam ); - void ProcessDelays( TimingData &out, const int iRowsPerBeat, const RString sParam ); - void ProcessTickcounts( TimingData &out, const int iRowsPerBeat, const RString sParam ); void ProcessMultipliers( TimingData &out, const int iRowsPerBeat, const RString sParam ); - void ProcessSpeeds( TimingData &out, const int iRowsPerBeat, const RString sParam ); - void ProcessFakes( TimingData &out, const int iRowsPerBeat, const RString sParam ); - - float RowToBeat( RString sLine, const int iRowsPerBeat ); + /** + * @brief Process the Speed Segments from the string. + * @param out the TimingData being modified. + * @param line the string in question. + * @param rowsPerBeat the number of rows per beat for this purpose. */ + virtual void ProcessSpeeds( TimingData &out, const RString line, const int rowsPerBeat ); }; #endif diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 04a4fdc167..bcefb97fad 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -14,38 +14,6 @@ #include "Attack.h" #include "PrefsManager.h" -/** - * @brief A custom .edit file can only be so big before we have to reject it. - */ -const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60 KB - -/** - * @brief Attempt to load any background changes in use by this song. - * @param change a reference to the background change. - * @param sBGChangeExpression a reference to the list of changes to be made. - * @return its success or failure. - */ -bool LoadFromBGSSCChangesString( BackgroundChange &change, const RString &sBGChangeExpression ) -{ - return SMLoader::LoadFromBGChangesString( change, sBGChangeExpression ); -} - -bool SSCLoader::LoadFromDir( const RString &sPath, Song &out ) -{ - vector aFileNames; - GetApplicableFiles( sPath, aFileNames ); - - if( aFileNames.size() > 1 ) - { - LOG->UserLog( "Song", sPath, "has more than one SSC file. Only one SSC file is allowed per song." ); - return false; - } - - ASSERT( aFileNames.size() == 1 ); // Ensure one was found entirely. - - return LoadFromSSCFile( sPath + aFileNames[0], out ); -} - void SSCLoader::ProcessWarps( TimingData &out, const RString sParam, const float fVersion ) { vector arrayWarpExpressions; @@ -55,10 +23,11 @@ void SSCLoader::ProcessWarps( TimingData &out, const RString sParam, const float { vector arrayWarpValues; split( arrayWarpExpressions[b], "=", arrayWarpValues ); - // XXX: Hard to tell which file caused this. if( arrayWarpValues.size() != 2 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #WARPS value \"%s\" (must have exactly one '='), ignored.", + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid #WARPS value \"%s\" (must have exactly one '='), ignored.", arrayWarpExpressions[b].c_str() ); continue; } @@ -68,13 +37,16 @@ void SSCLoader::ProcessWarps( TimingData &out, const RString sParam, const float // Early versions were absolute in beats. They should be relative. if( ( fVersion < VERSION_SPLIT_TIMING && fNewBeat > fBeat ) ) { - out.AddWarpSegment( WarpSegment(fBeat, fNewBeat - fBeat) ); + out.AddSegment( SEGMENT_WARP, new WarpSegment(fBeat, fNewBeat - fBeat) ); } else if( fNewBeat > 0 ) - out.AddWarpSegment( WarpSegment(fBeat, fNewBeat) ); + out.AddSegment( SEGMENT_WARP, new WarpSegment(fBeat, fNewBeat) ); else { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Warp at beat %f, BPM %f.", fBeat, fNewBeat ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid Warp at beat %f, BPM %f.", + fBeat, fNewBeat ); } } } @@ -90,7 +62,9 @@ void SSCLoader::ProcessLabels( TimingData &out, const RString sParam ) split( arrayLabelExpressions[b], "=", arrayLabelValues ); if( arrayLabelValues.size() != 2 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #LABELS value \"%s\" (must have exactly one '='), ignored.", + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid #LABELS value \"%s\" (must have exactly one '='), ignored.", arrayLabelExpressions[b].c_str() ); continue; } @@ -99,81 +73,40 @@ void SSCLoader::ProcessLabels( TimingData &out, const RString sParam ) RString sLabel = arrayLabelValues[1]; TrimRight(sLabel); if( fBeat >= 0.0f ) - out.AddLabelSegment( LabelSegment(fBeat, sLabel) ); + out.AddSegment( SEGMENT_LABEL, new LabelSegment(fBeat, sLabel) ); else { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Label at beat %f called %s.", fBeat, sLabel.c_str() ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid Label at beat %f called %s.", + fBeat, sLabel.c_str() ); } } } -void SSCLoader::ProcessCombos( TimingData &out, const RString sParam ) +void SSCLoader::ProcessCombos( TimingData &out, const RString line, const int rowsPerBeat ) { vector arrayComboExpressions; - split( sParam, ",", arrayComboExpressions ); + split( line, ",", arrayComboExpressions ); for( unsigned f=0; f arrayComboValues; split( arrayComboExpressions[f], "=", arrayComboValues ); - if( arrayComboValues.size() != 2 ) + unsigned size = arrayComboValues.size(); + if( size < 2 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #COMBOS value \"%s\" (must have exactly one '='), ignored.", + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an invalid #COMBOS value \"%s\" (must have at least one '='), ignored.", arrayComboExpressions[f].c_str() ); continue; } const float fComboBeat = StringToFloat( arrayComboValues[0] ); const int iCombos = StringToInt( arrayComboValues[1] ); - ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); - out.AddComboSegment( new_seg ); - } -} - -void SSCLoader::ProcessSpeeds( TimingData &out, const RString sParam ) -{ - vector vs1; - split( sParam, ",", vs1 ); - - FOREACH_CONST( RString, vs1, s1 ) - { - vector vs2; - split( *s1, "=", vs2 ); - - if( vs2[0] == 0 && vs2.size() == 2 ) // First one always seems to have 2. - { - vs2.push_back("0"); - } - - if( vs2.size() == 3 ) // use beats by default. - { - vs2.push_back("0"); - } - - if( vs2.size() < 4 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with %i values.", (int)vs2.size() ); - continue; - } - - const float fBeat = StringToFloat( vs2[0] ); - - SpeedSegment seg( fBeat, StringToFloat( vs2[1] ), StringToFloat( vs2[2] )); - seg.SetUnit(StringToInt(vs2[3])); - - if( fBeat < 0 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f.", fBeat ); - continue; - } - - if( seg.GetLength() < 0 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an speed change with beat %f, length %f.", fBeat, seg.GetLength() ); - continue; - } - - out.AddSpeedSegment( seg ); + const int iMisses = (size == 2 ? iCombos : StringToInt(arrayComboValues[2])); + out.AddSegment( SEGMENT_COMBO, new ComboSegment( fComboBeat, iCombos, iMisses ) ); } } @@ -189,55 +122,120 @@ void SSCLoader::ProcessScrolls( TimingData &out, const RString sParam ) if( vs2.size() < 2 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an scroll change with %i values.", (int)vs2.size() ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an scroll change with %i values.", + static_cast(vs2.size()) ); continue; } const float fBeat = StringToFloat( vs2[0] ); - ScrollSegment seg( fBeat, StringToFloat( vs2[1] ) ); + ScrollSegment * seg = new ScrollSegment(fBeat, StringToFloat( vs2[1] ) ); if( fBeat < 0 ) { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an scroll change with beat %f.", fBeat ); + LOG->UserLog("Song file", + this->GetSongTitle(), + "has an scroll change with beat %f.", + fBeat ); continue; } - out.AddScrollSegment( seg ); + out.AddSegment( SEGMENT_SCROLL, seg ); } } -void SSCLoader::ProcessFakes( TimingData &out, const RString sParam ) +bool SSCLoader::LoadNoteDataFromSimfile( const RString & cachePath, Steps &out ) { - vector arrayFakeExpressions; - split( sParam, ",", arrayFakeExpressions ); + LOG->Trace( "Loading notes from %s", cachePath.c_str() ); - for( unsigned b=0; b arrayFakeValues; - split( arrayFakeExpressions[b], "=", arrayFakeValues ); - // XXX: Hard to tell which file caused this. - if( arrayFakeValues.size() != 2 ) + LOG->UserLog("Unable to load any notes from", + cachePath, + "for this reason: %s", + msd.GetError().c_str()); + return false; + } + + bool tryingSteps = false; + float storedVersion = 0; + const unsigned values = msd.GetNumValues(); + + for (unsigned i = 0; i < values; i++) + { + const MsdFile::value_t ¶ms = msd.GetValue(i); + RString valueName = params[0]; + valueName.MakeUpper(); + RString matcher = params[1]; // mainly for debugging. + Trim(matcher); + + if (valueName=="VERSION") { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #FAKES value \"%s\" (must have exactly one '='), ignored.", - arrayFakeExpressions[b].c_str() ); - continue; + storedVersion = StringToFloat(matcher); + } + if (tryingSteps) + { + if( valueName=="STEPSTYPE" ) + { + if (out.m_StepsType != GAMEMAN->StringToStepsType(matcher)) + tryingSteps = false; + } + else if( valueName=="CHARTNAME") + { + if (storedVersion >= VERSION_CHART_NAME_TAG && out.GetChartName() != matcher) + tryingSteps = false; + } + else if( valueName=="DESCRIPTION" ) + { + if (storedVersion < VERSION_CHART_NAME_TAG) + { + if (out.GetChartName() != matcher) + tryingSteps = false; + } + else if (out.GetDescription() != matcher) + tryingSteps = false; + } + + else if( valueName=="DIFFICULTY" ) + { + if (out.GetDifficulty() != StringToDifficulty(matcher)) + tryingSteps = false; + } + + else if( valueName=="METER" ) + { + if (out.GetMeter() != StringToInt(matcher)) + tryingSteps = false; + } + + else if( valueName=="CREDIT" ) + { + if (out.GetCredit() != matcher) + tryingSteps = false; + } + + else if( valueName=="NOTES" || valueName=="NOTES2" ) + { + out.SetSMNoteData(matcher); + out.TidyUpData(); + return true; + } } - - const float fBeat = StringToFloat( arrayFakeValues[0] ); - const float fNewBeat = StringToFloat( arrayFakeValues[1] ); - - if(fNewBeat > 0) - out.AddFakeSegment( FakeSegment(fBeat, fNewBeat) ); else { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid Fake at beat %f, BPM %f.", fBeat, fNewBeat ); + if(valueName == "NOTEDATA") + { + tryingSteps = true; + } } } + return false; } - -bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache ) +bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache ) { LOG->Trace( "Song::LoadFromSSCFile(%s)", sPath.c_str() ); @@ -249,6 +247,7 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach } out.m_SongTiming.m_sFile = sPath; // songs still have their fallback timing. + out.m_sSongFileName = sPath; int state = GETTING_SONG_INFO; const unsigned values = msd.GetNumValues(); @@ -274,6 +273,7 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach else if( sValueName=="TITLE" ) { out.m_sMainTitle = sParams[1]; + this->SetSongTitle(sParams[1]); } else if( sValueName=="SUBTITLE" ) @@ -355,7 +355,12 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach else if( sValueName=="LASTBEATHINT" ) { - out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] ); + // unable to parse due to tag position. Ignore. + } + + else if (sValueName == "LASTSECONDHINT") + { + out.SetSpecifiedLastSecond(StringToFloat(sParams[1])); } else if( sValueName=="MUSICBYTES" ) @@ -421,7 +426,7 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach for( unsigned b=0; bSetChartName(sParams[1]); + } if( sValueName=="STEPSTYPE" ) { pNewNotes->m_StepsType = GAMEMAN->StringToStepsType( sParams[1] ); @@ -538,7 +552,14 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach else if( sValueName=="DESCRIPTION" ) { - pNewNotes->SetDescription( sParams[1] ); + if (out.m_fVersion < VERSION_CHART_NAME_TAG) + { + pNewNotes->SetChartName(sParams[1]); + } + else + { + pNewNotes->SetDescription(sParams[1]); + } } else if( sValueName=="DIFFICULTY" ) @@ -553,27 +574,35 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach else if( sValueName=="RADARVALUES" ) { - vector saValues; - split( sParams[1], ",", saValues, true ); - - int categories = NUM_RadarCategory; - if( out.m_fVersion < VERSION_RADAR_FAKE ) - categories -= 1; - - if( saValues.size() == (unsigned)categories * NUM_PLAYERS ) + if (bFromCache) { - RadarValues v[NUM_PLAYERS]; - FOREACH_PlayerNumber( pn ) + vector saValues; + split( sParams[1], ",", saValues, true ); + + int categories = NUM_RadarCategory; + if( out.m_fVersion < VERSION_RADAR_FAKE ) + categories -= 1; + + if( saValues.size() == (unsigned)categories * NUM_PLAYERS ) { - // Can't use the foreach anymore due to flexible radar lines. - for( RadarCategory rc = (RadarCategory)0; rc < categories; - enum_add( rc, +1 ) ) + RadarValues v[NUM_PLAYERS]; + FOREACH_PlayerNumber( pn ) { - v[pn][rc] = StringToFloat( saValues[pn*categories + rc] ); + // Can't use the foreach anymore due to flexible radar lines. + for( RadarCategory rc = (RadarCategory)0; rc < categories; + enum_add( rc, +1 ) ) + { + v[pn][rc] = StringToFloat( saValues[pn*categories + rc] ); + } } + pNewNotes->SetCachedRadarValues( v ); } - pNewNotes->SetCachedRadarValues( v ); } + else + { + // just recalc at time. + } + } else if( sValueName=="CREDIT" ) @@ -588,6 +617,7 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach pNewNotes->m_Timing = stepsTiming; pNewNotes->SetSMNoteData( sParams[1] ); pNewNotes->TidyUpData(); + pNewNotes->SetFilename(sPath); out.AddSteps( pNewNotes ); } @@ -649,13 +679,39 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach else if( sValueName=="ATTACKS" ) { - // Step Attacks aren't in yet. + ProcessAttackString(pNewNotes->m_sAttackString, sParams); + ProcessAttacks(pNewNotes->m_Attacks, sParams); } else if( sValueName=="OFFSET" ) { stepsTiming.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); } + + else if( sValueName=="DISPLAYBPM" ) + { + // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; + if( sParams[1] == "*" ) + pNewNotes->SetDisplayBPM(DISPLAY_BPM_RANDOM); + else + { + pNewNotes->SetDisplayBPM(DISPLAY_BPM_SPECIFIED); + float min = StringToFloat(sParams[1]); + pNewNotes->SetMinBPM(min); + if(sParams[2].empty()) + pNewNotes->SetMaxBPM(min); + else + pNewNotes->SetMaxBPM(StringToFloat(sParams[2])); + } + } + else if( sValueName=="STEPFILENAME" ) + { + state = GETTING_SONG_INFO; + if( bHasOwnTiming ) + pNewNotes->m_Timing = stepsTiming; + pNewNotes->SetFilename(sParams[1]); + out.AddSteps( pNewNotes ); + } break; } } @@ -665,11 +721,6 @@ bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCach return true; } -void SSCLoader::GetApplicableFiles( const RString &sPath, vector &out ) -{ - GetDirListing( sPath + RString("*.ssc"), out ); -} - bool SSCLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) { LOG->Trace( "SSCLoader::LoadEditFromFile(%s)", sEditFilePath.c_str() ); @@ -677,21 +728,28 @@ bool SSCLoader::LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool int iBytes = FILEMAN->GetFileSizeInBytes( sEditFilePath ); if( iBytes > MAX_EDIT_STEPS_SIZE_BYTES ) { - LOG->UserLog( "Edit file", sEditFilePath, "is unreasonably large. It won't be loaded." ); + LOG->UserLog("Edit file", + sEditFilePath, + "is unreasonably large. It won't be loaded." ); return false; } MsdFile msd; if( !msd.ReadFile( sEditFilePath, true ) ) // unescape { - LOG->UserLog( "Edit file", sEditFilePath, "couldn't be opened: %s", msd.GetError().c_str() ); + LOG->UserLog("Edit file", + sEditFilePath, + "couldn't be opened: %s", msd.GetError().c_str() ); return false; } return LoadEditFromMsd( msd, sEditFilePath, slot, bAddStepsToSong ); } -bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) +bool SSCLoader::LoadEditFromMsd(const MsdFile &msd, + const RString &sEditFilePath, + ProfileSlot slot, + bool bAddStepsToSong ) { Song* pSong = NULL; Steps* pNewNotes = NULL; @@ -721,18 +779,25 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat } RString sSongFullTitle = sParams[1]; + this->SetSongTitle(sParams[1]); sSongFullTitle.Replace( '\\', '/' ); pSong = SONGMAN->FindSong( sSongFullTitle ); if( pSong == NULL ) { - LOG->UserLog( "Edit file", sEditFilePath, "requires a song \"%s\" that isn't present.", sSongFullTitle.c_str() ); + LOG->UserLog("Edit file", + sEditFilePath, + "requires a song \"%s\" that isn't present.", + sSongFullTitle.c_str() ); return false; } if( pSong->GetNumStepsLoadedFromProfile(slot) >= MAX_EDITS_PER_SONG_PER_PROFILE ) { - LOG->UserLog( "Song file", sSongFullTitle, "already has the maximum number of edits allowed for ProfileSlotP%d.", slot+1 ); + LOG->UserLog("Song file", + sSongFullTitle, + "already has the maximum number of edits allowed for ProfileSlotP%d.", + slot+1 ); return false; } } @@ -780,8 +845,8 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat { RadarValues v[NUM_PLAYERS]; FOREACH_PlayerNumber( pn ) - FOREACH_ENUM( RadarCategory, rc ) - v[pn][rc] = StringToFloat( saValues[pn*NUM_RadarCategory + rc] ); + FOREACH_ENUM( RadarCategory, rc ) + v[pn][rc] = StringToFloat( saValues[pn*NUM_RadarCategory + rc] ); pNewNotes->SetCachedRadarValues( v ); } bSSCFormat = true; @@ -857,13 +922,18 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat { if( pSong == NULL ) { - LOG->UserLog( "Edit file", sEditFilePath, "doesn't have a #SONG tag preceeding the first #NOTES tag." ); + LOG->UserLog("Edit file", + sEditFilePath, + "doesn't have a #SONG tag preceeding the first #NOTES tag." ); return false; } if ( !bSSCFormat && iNumParams < 7 ) { - LOG->UserLog( "Edit file", sEditFilePath, "has %d fields in a #NOTES tag, but should have at least 7.", iNumParams ); + LOG->UserLog("Edit file", + sEditFilePath, + "has %d fields in a #NOTES tag, but should have at least 7.", + iNumParams ); continue; } @@ -883,9 +953,13 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat else { pNewNotes = pSong->CreateSteps(); - SMLoader::LoadFromSMTokens( - sParams[1], sParams[2], sParams[3], sParams[4], sParams[5], sParams[6], - *pNewNotes); + LoadFromTokens(sParams[1], + sParams[2], + sParams[3], + sParams[4], + sParams[5], + sParams[6], + *pNewNotes); } pNewNotes->SetLoadedFromProfile( slot ); @@ -894,7 +968,9 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat if( pSong->IsEditAlreadyLoaded(pNewNotes) ) { - LOG->UserLog( "Edit file", sEditFilePath, "is a duplicate of another edit that was already loaded." ); + LOG->UserLog("Edit file", + sEditFilePath, + "is a duplicate of another edit that was already loaded." ); SAFE_DELETE( pNewNotes ); return false; } @@ -904,7 +980,10 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat } else { - LOG->UserLog( "Edit file", sEditFilePath, "has an unexpected value \"%s\".", sValueName.c_str() ); + LOG->UserLog("Edit file", + sEditFilePath, + "has an unexpected value \"%s\".", + sValueName.c_str() ); } } @@ -913,11 +992,6 @@ bool SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePat return bSSCFormat; } -void SSCLoader::TidyUpData( Song &song, bool bFromCache ) -{ - SMLoader::TidyUpData(song, bFromCache); -} - /* * (c) 2011 Jason Felds * All rights reserved. diff --git a/src/NotesLoaderSSC.h b/src/NotesLoaderSSC.h index 936a24e219..3d8f8ca634 100644 --- a/src/NotesLoaderSSC.h +++ b/src/NotesLoaderSSC.h @@ -3,6 +3,7 @@ #define NotesLoaderSSC_H #include "GameConstantsAndTypes.h" +#include "NotesLoaderSM.h" class MsdFile; class Song; @@ -25,19 +26,20 @@ const float VERSION_RADAR_FAKE = 0.53f; const float VERSION_WARP_SEGMENT = 0.56f; /** @brief The version that formally introduced Split Timing. */ const float VERSION_SPLIT_TIMING = 0.7f; +/** @brief The version that moved the step's Offset higher up. */ +const float VERSION_OFFSET_BEFORE_ATTACK = 0.72f; +/** @brief The version that introduced the Chart Name tag. */ +const float VERSION_CHART_NAME_TAG = 0.74f; +/** @brief The version that introduced the cache switch tag. */ +const float VERSION_CACHE_SWITCH_TAG = 0.77f; /** * @brief The SSCLoader handles all of the parsing needed for .ssc files. */ -namespace SSCLoader +struct SSCLoader : public SMLoader { - /** - * @brief Attempt to load a song from a specified path. - * @param sPath a const reference to the path on the hard drive to check. - * @param out a reference to the Song that will retrieve the song information. - * @return its success or failure. - */ - bool LoadFromDir( const RString &sPath, Song &out ); + SSCLoader() : SMLoader(".ssc") {} + /** * @brief Attempt to load the specified ssc file. * @param sPath a const reference to the path on the hard drive to check. @@ -45,13 +47,8 @@ namespace SSCLoader * @param bFromCache a check to see if we are getting certain information from the cache file. * @return its success or failure. */ - bool LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache = false ); - /** - * @brief Retrieve the list of .ssc files. - * @param sPath a const reference to the path on the hard drive to check. - * @param out a vector of files found in the path. - */ - void GetApplicableFiles( const RString &sPath, vector &out ); + virtual bool LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache = false ); + /** * @brief Attempt to load an edit from the hard drive. * @param sEditFilePath a path on the hard drive to check. @@ -69,21 +66,20 @@ namespace SSCLoader * @return its success or failure. */ bool LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); - /** - * @brief Perform some cleanup on the loaded song. - * @param song a reference to the song that may need cleaning up. - * @param bFromCache a flag to determine if this song is loaded from a cache file. - */ - void TidyUpData( Song &song, bool bFromCache ); + /** + * @brief Retrieve the specific NoteData from the file. + * @param cachePath the path to the cache file. + * @param out the Steps to receive just the particular notedata. + * @return true if successful, false otherwise. */ + virtual bool LoadNoteDataFromSimfile( const RString &cachePath, Steps &out ); void ProcessWarps( TimingData &, const RString, const float ); void ProcessLabels( TimingData &, const RString ); - void ProcessCombos( TimingData &, const RString ); - void ProcessSpeeds( TimingData &, const RString ); + virtual void ProcessCombos( TimingData &, const RString, const int = -1 ); void ProcessScrolls( TimingData &, const RString ); - void ProcessFakes( TimingData &, const RString ); -} +}; + #endif /** * @file diff --git a/src/NotesWriterDWI.cpp b/src/NotesWriterDWI.cpp index 3d0641c0e8..e64ecd17cd 100644 --- a/src/NotesWriterDWI.cpp +++ b/src/NotesWriterDWI.cpp @@ -11,6 +11,8 @@ #include "Song.h" #include "Steps.h" +RString OptimizeDWIString( RString holds, RString taps ); + /** * @brief Optimize an individual pair of characters whenever possible. * @param c1 the first character. @@ -350,9 +352,13 @@ bool NotesWriterDWI::Write( RString sPath, const Song &out ) /* Write transliterations, if we have them, since DWI doesn't support UTF-8. */ f.PutLine( ssprintf("#TITLE:%s;", DwiEscape(out.GetTranslitFullTitle()).c_str()) ); f.PutLine( ssprintf("#ARTIST:%s;", DwiEscape(out.GetTranslitArtist()).c_str()) ); - ASSERT( out.m_SongTiming.m_BPMSegments[0].GetRow() == 0 ); + + const vector &bpms = out.m_SongTiming.allTimingSegments[SEGMENT_BPM]; + + ASSERT_M(bpms[0]->GetRow() == 0, + ssprintf("The first BPM Segment must be defined at row 0, not %d!", bpms[0]->GetRow()) ); f.PutLine( ssprintf("#FILE:%s;", DwiEscape(out.m_sMusicFile).c_str()) ); - f.PutLine( ssprintf("#BPM:%.3f;", out.m_SongTiming.m_BPMSegments[0].GetBPM()) ); + f.PutLine( ssprintf("#BPM:%.3f;", static_cast(bpms[0])->GetBPM()) ); f.PutLine( ssprintf("#GAP:%ld;", -lrintf( out.m_SongTiming.m_fBeat0OffsetInSeconds*1000 )) ); f.PutLine( ssprintf("#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds) ); f.PutLine( ssprintf("#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds) ); @@ -374,29 +380,30 @@ bool NotesWriterDWI::Write( RString sPath, const Song &out ) break; } - if( !out.m_SongTiming.m_StopSegments.empty() ) + const vector &stops = out.m_SongTiming.allTimingSegments[SEGMENT_STOP_DELAY]; + if( !stops.empty() ) { f.Write( "#FREEZE:" ); - for( unsigned i=0; i(stops[i]); + f.Write( ssprintf("%.3f=%.3f", fs->GetRow() * 4.0f / ROWS_PER_BEAT, + roundf(fs->GetPause()*1000)) ); + if( i != stops.size()-1 ) f.Write( "," ); } f.PutLine( ";" ); } - if( out.m_SongTiming.m_BPMSegments.size() > 1) + if( bpms.size() > 1) { f.Write( "#CHANGEBPM:" ); - for( unsigned i=1; i(bpms[i]); + f.Write( ssprintf("%.3f=%.3f", bs->GetRow() * 4.0f / ROWS_PER_BEAT, bs->GetBPM() ) ); + if( i != bpms.size()-1 ) f.Write( "," ); } f.PutLine( ";" ); diff --git a/src/NotesWriterJson.cpp b/src/NotesWriterJson.cpp index a758444e30..984a895295 100644 --- a/src/NotesWriterJson.cpp +++ b/src/NotesWriterJson.cpp @@ -9,22 +9,23 @@ #include "NoteData.h" #include "GameManager.h" -void Serialize(const BPMSegment &seg, Json::Value &root) +static void Serialize(const TimingSegment &seg, Json::Value &root) { root["Beat"] = seg.GetBeat(); - root["BPM"] = seg.GetBPM(); -} - -static void Serialize(const StopSegment &seg, Json::Value &root) -{ - root["Beat"] = seg.GetBeat(); - root["Seconds"] = seg.GetPause(); + if (seg.GetType() == SEGMENT_BPM) + { + root["BPM"] = static_cast(const_cast(seg)).GetBPM(); + } + else + { + root["Seconds"] = static_cast(const_cast(seg)).GetPause(); + } } static void Serialize(const TimingData &td, Json::Value &root) { - JsonUtil::SerializeVectorObjects( td.m_BPMSegments, Serialize, root["BpmSegments"] ); - JsonUtil::SerializeVectorObjects( td.m_StopSegments, Serialize, root["StopSegments"] ); + JsonUtil::SerializeVectorPointers( td.allTimingSegments[SEGMENT_BPM], Serialize, root["BpmSegments"] ); + JsonUtil::SerializeVectorPointers( td.allTimingSegments[SEGMENT_STOP_DELAY], Serialize, root["StopSegments"] ); } static void Serialize(const LyricSegment &o, Json::Value &root) @@ -147,8 +148,8 @@ bool NotesWriterJson::WriteSong( const RString &sFile, const Song &out, bool bWr else root["Selectable"] = "YES"; - root["FirstBeat"] = out.m_fFirstBeat; - root["LastBeat"] = out.m_fLastBeat; + root["FirstBeat"] = out.GetFirstBeat(); + root["LastBeat"] = out.GetLastBeat(); root["SongFileName"] = out.m_sSongFileName; root["HasMusic"] = out.m_bHasMusic; root["HasBanner"] = out.m_bHasBanner; diff --git a/src/NotesWriterSM.cpp b/src/NotesWriterSM.cpp index 6b9f89c1fe..81eca70991 100644 --- a/src/NotesWriterSM.cpp +++ b/src/NotesWriterSM.cpp @@ -19,37 +19,13 @@ ThemeMetric USE_CREDIT ( "NotesWriterSM", "DescriptionUsesCreditField" ); -/** - * @brief Turn the BackgroundChange into a string. - * @param bgc the BackgroundChange in question. - * @return the converted string. */ -static RString BackgroundChangeToString( const BackgroundChange &bgc ) -{ - // TODO: Technically we need to double-escape the filename (because it might - // contain '=') and then unescape the value returned by the MsdFile. - RString s = ssprintf( - "%.3f=%s=%.3f=%d=%d=%d=%s=%s=%s=%s=%s", - bgc.m_fStartBeat, - SmEscape(bgc.m_def.m_sFile1).c_str(), - bgc.m_fRate, - bgc.m_sTransition == SBT_CrossFade, // backward compat - bgc.m_def.m_sEffect == SBE_StretchRewind, // backward compat - bgc.m_def.m_sEffect != SBE_StretchNoLoop, // backward compat - bgc.m_def.m_sEffect.c_str(), - bgc.m_def.m_sFile2.c_str(), - bgc.m_sTransition.c_str(), - SmEscape(RageColor::NormalizeColorString(bgc.m_def.m_sColor1)).c_str(), - SmEscape(RageColor::NormalizeColorString(bgc.m_def.m_sColor2)).c_str() - ); - return s; -} - /** * @brief Write out the common tags for .SM files. * @param f the file in question. * @param out the Song in question. */ static void WriteGlobalTags( RageFile &f, Song &out ) { + TimingData &timing = out.m_SongTiming; f.PutLine( ssprintf( "#TITLE:%s;", SmEscape(out.m_sMainTitle).c_str() ) ); f.PutLine( ssprintf( "#SUBTITLE:%s;", SmEscape(out.m_sSubTitle).c_str() ) ); f.PutLine( ssprintf( "#ARTIST:%s;", SmEscape(out.m_sArtist).c_str() ) ); @@ -66,8 +42,9 @@ static void WriteGlobalTags( RageFile &f, Song &out ) f.PutLine( ssprintf( "#OFFSET:%.3f;", out.m_SongTiming.m_fBeat0OffsetInSeconds ) ); f.PutLine( ssprintf( "#SAMPLESTART:%.3f;", out.m_fMusicSampleStartSeconds ) ); f.PutLine( ssprintf( "#SAMPLELENGTH:%.3f;", out.m_fMusicSampleLengthSeconds ) ); - if( out.m_fSpecifiedLastBeat > 0 ) - f.PutLine( ssprintf("#LASTBEATHINT:%.3f;", out.m_fSpecifiedLastBeat) ); + float specBeat = out.GetSpecifiedLastBeat(); + if( specBeat > 0 ) + f.PutLine( ssprintf("#LASTBEATHINT:%.3f;", specBeat) ); f.Write( "#SELECTABLE:" ); switch(out.m_SelectionDisplay) @@ -98,44 +75,46 @@ static void WriteGlobalTags( RageFile &f, Song &out ) f.Write( "#BPMS:" ); - for( unsigned i=0; i &bpms = timing.allTimingSegments[SEGMENT_BPM]; + for( unsigned i=0; i(bpms[i]); - f.PutLine( ssprintf( "%.3f=%.3f", bs.GetBeat(), bs.GetBPM() ) ); - if( i != out.m_SongTiming.m_BPMSegments.size()-1 ) + f.PutLine( ssprintf( "%.3f=%.3f", bs->GetBeat(), bs->GetBPM() ) ); + if( i != bpms.size()-1 ) f.Write( "," ); } f.PutLine( ";" ); - unsigned wSize = out.m_SongTiming.m_WarpSegments.size(); + vector &warps = timing.allTimingSegments[SEGMENT_WARP]; + unsigned wSize = warps.size(); if( wSize > 0 ) { for( unsigned i=0; i < wSize; i++ ) { - int iRow = out.m_SongTiming.m_WarpSegments[i].GetRow(); + const WarpSegment *ws = static_cast(warps[i]); + int iRow = ws->GetRow(); float fBPS = 60 / out.m_SongTiming.GetBPMAtRow(iRow); - float fSkip = fBPS * out.m_SongTiming.m_WarpSegments[i].GetLength(); - StopSegment ss(iRow, -fSkip, false); - out.m_SongTiming.AddStopSegment( ss ); + float fSkip = fBPS * ws->GetLength(); + out.m_SongTiming.AddSegment(SEGMENT_STOP_DELAY, + new StopSegment(iRow, -fSkip, false) ); } } f.Write( "#STOPS:" ); - for( unsigned i=0; i &stops = timing.allTimingSegments[SEGMENT_STOP_DELAY]; + for( unsigned i=0; i(stops[i]); + float fBeat = fs->GetBeat(); + if (fs->GetDelay()) fBeat--; - f.PutLine( ssprintf( "%.3f=%.3f", fBeat, fs.GetPause() ) ); - if( i != out.m_SongTiming.m_StopSegments.size()-1 ) + f.PutLine( ssprintf( "%.3f=%.3f", fBeat, fs->GetPause() ) ); + if( i != stops.size()-1 ) f.Write( "," ); - if( fs.GetPause() < 0 ) + if( fs->GetPause() < 0 ) { - out.m_SongTiming.m_StopSegments.erase( - out.m_SongTiming.m_StopSegments.begin()+i, - out.m_SongTiming.m_StopSegments.begin()+i+1 ); + stops.erase(stops.begin()+i,stops.begin()+i+1 ); i--; } } @@ -151,7 +130,7 @@ static void WriteGlobalTags( RageFile &f, Song &out ) f.Write( ssprintf("#BGCHANGES%d:", b+1) ); FOREACH_CONST( BackgroundChange, out.GetBackgroundChanges(b), bgc ) - f.PutLine( BackgroundChangeToString(*bgc)+"," ); + f.PutLine( (*bgc).ToString() +"," ); /* If there's an animation plan at all, add a dummy "-nosongbg-" tag to indicate that * this file doesn't want a song BG entry added at the end. See SMLoader::TidyUpData. @@ -167,7 +146,7 @@ static void WriteGlobalTags( RageFile &f, Song &out ) f.Write( "#FGCHANGES:" ); FOREACH_CONST( BackgroundChange, out.GetForegroundChanges(), bgc ) { - f.PutLine( BackgroundChangeToString(*bgc)+"," ); + f.PutLine( (*bgc).ToString() +"," ); } f.PutLine( ";" ); } @@ -181,16 +160,7 @@ static void WriteGlobalTags( RageFile &f, Song &out ) } f.PutLine( ";" ); - f.Write( "#ATTACKS:" ); - for( unsigned a=0; a < out.m_sAttackString.size(); a++ ) - { - RString sData = out.m_sAttackString[a]; - f.Write( ssprintf( "%s", sData.c_str() ) ); - - if( a != (out.m_sAttackString.size() - 1) ) - f.Write( ":" ); // Not the end, so write a divider ':' - } - f.PutLine( ";" ); + f.PutLine( ssprintf("#ATTACKS:%s;", out.GetAttackString().c_str()) ); } /** @@ -225,7 +195,7 @@ static RString GetSMNotesTag( const Song &song, const Steps &in ) GAMEMAN->GetStepsTypeInfo(in.m_StepsType).szName, SmEscape(in.GetDescription()).c_str()) ); lines.push_back( song.m_vsKeysoundFile.empty() ? "#NOTES:" : "#NOTES2:" ); lines.push_back( ssprintf( " %s:", GAMEMAN->GetStepsTypeInfo(in.m_StepsType).szName ) ); - RString desc = (USE_CREDIT ? in.GetCredit() : in.GetDescription()); + RString desc = (USE_CREDIT ? in.GetCredit() : in.GetChartName()); lines.push_back( ssprintf( " %s:", SmEscape(desc).c_str() ) ); lines.push_back( ssprintf( " %s:", DifficultyToString(in.GetDifficulty()).c_str() ) ); lines.push_back( ssprintf( " %d:", in.GetMeter() ) ); diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index cdd0659340..0a47768f41 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -16,31 +16,6 @@ #include "Song.h" #include "Steps.h" -/** - * @brief Turn the BackgroundChange into a string. - * @param bgc the BackgroundChange in question. - * @return the converted string. */ -static RString BackgroundChangeToString( const BackgroundChange &bgc ) -{ - // TODO: Technically we need to double-escape the filename (because it might contain '=') and then - // unescape the value returned by the MsdFile. - RString s = ssprintf( - "%.3f=%s=%.3f=%d=%d=%d=%s=%s=%s=%s=%s", - bgc.m_fStartBeat, - SmEscape(bgc.m_def.m_sFile1).c_str(), - bgc.m_fRate, - bgc.m_sTransition == SBT_CrossFade, // backward compat - bgc.m_def.m_sEffect == SBE_StretchRewind, // backward compat - bgc.m_def.m_sEffect != SBE_StretchNoLoop, // backward compat - bgc.m_def.m_sEffect.c_str(), - bgc.m_def.m_sFile2.c_str(), - bgc.m_sTransition.c_str(), - SmEscape(RageColor::NormalizeColorString(bgc.m_def.m_sColor1)).c_str(), - SmEscape(RageColor::NormalizeColorString(bgc.m_def.m_sColor2)).c_str() - ); - return s; -} - /** * @brief Turn a vector of lines into a single line joined by newline characters. * @param lines the list of lines to join. @@ -90,80 +65,144 @@ static void GetTimingTags( vector &lines, TimingData timing, bool bIsSo TimingTagWriter w ( &lines ); timing.TidyUpData(); + unsigned i = 0; w.Init( "BPMS" ); - FOREACH_CONST( BPMSegment, timing.m_BPMSegments, bs ) + vector &bpms = timing.allTimingSegments[SEGMENT_BPM]; + for (; i < bpms.size(); i++) + { + BPMSegment *bs = static_cast(bpms[i]); w.Write( bs->GetRow(), bs->GetBPM() ); + } w.Finish(); w.Init( "STOPS" ); - FOREACH_CONST( StopSegment, timing.m_StopSegments, ss ) + vector &stops = timing.allTimingSegments[SEGMENT_STOP_DELAY]; + for (i = 0; i < stops.size(); i++) + { + StopSegment *ss = static_cast(stops[i]); if( !ss->GetDelay() ) w.Write( ss->GetRow(), ss->GetPause() ); + } w.Finish(); w.Init( "DELAYS" ); - FOREACH_CONST( StopSegment, timing.m_StopSegments, ss ) + for (i = 0; i < stops.size(); i++) + { + StopSegment *ss = static_cast(stops[i]); if( ss->GetDelay() ) w.Write( ss->GetRow(), ss->GetPause() ); + } w.Finish(); w.Init( "WARPS" ); - FOREACH_CONST( WarpSegment, timing.m_WarpSegments, ws ) + vector &warps = timing.allTimingSegments[SEGMENT_WARP]; + for (i = 0; i < warps.size(); i++) + { + WarpSegment *ws = static_cast(warps[i]); w.Write( ws->GetRow(), ws->GetLength() ); + } w.Finish(); - ASSERT( !timing.m_vTimeSignatureSegments.empty() ); + vector &tSigs = timing.allTimingSegments[SEGMENT_TIME_SIG]; + ASSERT( !tSigs.empty() ); w.Init( "TIMESIGNATURES" ); - FOREACH_CONST( TimeSignatureSegment, timing.m_vTimeSignatureSegments, iter ) - w.Write( iter->GetRow(), iter->GetNum(), iter->GetDen() ); + for (i = 0; i < tSigs.size(); i++) + { + TimeSignatureSegment *ts = static_cast(tSigs[i]); + w.Write( ts->GetRow(), ts->GetNum(), ts->GetDen() ); + } w.Finish(); - ASSERT( !timing.m_TickcountSegments.empty() ); + vector &ticks = timing.allTimingSegments[SEGMENT_TICKCOUNT]; + ASSERT( !ticks.empty() ); w.Init( "TICKCOUNTS" ); - FOREACH_CONST( TickcountSegment, timing.m_TickcountSegments, ts ) + for (i = 0; i < ticks.size(); i++) + { + TickcountSegment *ts = static_cast(ticks[i]); w.Write( ts->GetRow(), ts->GetTicks() ); + } w.Finish(); - ASSERT( !timing.m_ComboSegments.empty() ); + vector &combos = timing.allTimingSegments[SEGMENT_COMBO]; + ASSERT( !combos.empty() ); w.Init( "COMBOS" ); - FOREACH_CONST( ComboSegment, timing.m_ComboSegments, cs ) - w.Write( cs->GetRow(), cs->GetCombo() ); + for (i = 0; i < combos.size(); i++) + { + ComboSegment *cs = static_cast(combos[i]); + if (cs->GetCombo() == cs->GetMissCombo()) + w.Write( cs->GetRow(), cs->GetCombo() ); + else + w.Write( cs->GetRow(), cs->GetCombo(), cs->GetMissCombo() ); + } w.Finish(); // Song Timing should only have the initial value. + vector &speeds = timing.allTimingSegments[SEGMENT_SPEED]; w.Init( "SPEEDS" ); - FOREACH_CONST( SpeedSegment, timing.m_SpeedSegments, ss ) + for (i = 0; i < speeds.size(); i++) + { + SpeedSegment *ss = static_cast(speeds[i]); w.Write( ss->GetRow(), ss->GetRatio(), ss->GetLength(), ss->GetUnit() ); + } w.Finish(); w.Init( "SCROLLS" ); - FOREACH_CONST( ScrollSegment, timing.m_ScrollSegments, ss ) + vector &scrolls = timing.allTimingSegments[SEGMENT_SCROLL]; + for (i = 0; i < scrolls.size(); i++) + { + ScrollSegment *ss = static_cast(scrolls[i]); w.Write( ss->GetRow(), ss->GetRatio() ); + } w.Finish(); if( !bIsSong ) { + vector &fakes = timing.allTimingSegments[SEGMENT_FAKE]; w.Init( "FAKES" ); - FOREACH_CONST( FakeSegment, timing.m_FakeSegments, fs ) + for (i = 0; i < fakes.size(); i++) + { + FakeSegment *fs = static_cast(fakes[i]); w.Write( fs->GetRow(), fs->GetLength() ); + } w.Finish(); } w.Init( "LABELS" ); - FOREACH_CONST( LabelSegment, timing.m_LabelSegments, ls ) + vector &labels = timing.allTimingSegments[SEGMENT_LABEL]; + for (i = 0; i < labels.size(); i++) + { + LabelSegment *ls = static_cast(labels[i]); w.Write( ls->GetRow(), ls->GetLabel().c_str() ); + } w.Finish(); } static void WriteTimingTags( RageFile &f, const TimingData &timing, bool bIsSong = false ) { - - vector lines; - - GetTimingTags( lines, timing, bIsSong ); - - f.PutLine( JoinLineList( lines ) ); + f.PutLine(ssprintf("#BPMS:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_BPM)).c_str())); + f.PutLine(ssprintf("#STOPS:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_STOP_DELAY, false)).c_str())); + f.PutLine(ssprintf("#DELAYS:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_STOP_DELAY, true)).c_str())); + f.PutLine(ssprintf("#WARPS:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_WARP)).c_str())); + f.PutLine(ssprintf("#TIMESIGNATURES:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_TIME_SIG)).c_str())); + f.PutLine(ssprintf("#TICKCOUNTS:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_TICKCOUNT)).c_str())); + f.PutLine(ssprintf("#COMBOS:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_COMBO)).c_str())); + f.PutLine(ssprintf("#SPEEDS:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_SPEED)).c_str())); + f.PutLine(ssprintf("#SCROLLS:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_SCROLL)).c_str())); + if (!bIsSong) + f.PutLine(ssprintf("#FAKES:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_FAKE)).c_str())); + f.PutLine(ssprintf("#LABELS:%s;", + join(",\r\n", timing.ToVectorString(SEGMENT_LABEL)).c_str())); } @@ -190,10 +229,7 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) f.PutLine( ssprintf( "#MUSIC:%s;", SmEscape(out.m_sMusicFile).c_str() ) ); { - vector vs; - FOREACH_ENUM( InstrumentTrack, it ) - if( out.HasInstrumentTrack(it) ) - vs.push_back( InstrumentTrackToString(it) + "=" + out.m_sInstrumentTrackFile[it] ); + vector vs = out.GetInstrumentTracksToVectorString(); if( !vs.empty() ) { RString s = join( ",", vs ); @@ -203,13 +239,11 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) f.PutLine( ssprintf( "#OFFSET:%.6f;", out.m_SongTiming.m_fBeat0OffsetInSeconds ) ); f.PutLine( ssprintf( "#SAMPLESTART:%.6f;", out.m_fMusicSampleStartSeconds ) ); f.PutLine( ssprintf( "#SAMPLELENGTH:%.6f;", out.m_fMusicSampleLengthSeconds ) ); - if( out.m_fSpecifiedLastBeat > 0 ) - f.PutLine( ssprintf("#LASTBEATHINT:%.6f;", out.m_fSpecifiedLastBeat) ); f.Write( "#SELECTABLE:" ); switch(out.m_SelectionDisplay) { - default: ASSERT(0); // fall through + default: ASSERT_M(0, "An invalid selectable value was found for this song!"); // fall through case Song::SHOW_ALWAYS: f.Write( "YES" ); break; //case Song::SHOW_NONSTOP: f.Write( "NONSTOP" ); break; case Song::SHOW_NEVER: f.Write( "NO" ); break; @@ -234,6 +268,9 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) WriteTimingTags( f, out.m_SongTiming, true ); + if( out.GetSpecifiedLastSecond() > 0 ) + f.PutLine( ssprintf("#LASTSECONDHINT:%.6f;", out.GetSpecifiedLastSecond()) ); + FOREACH_BackgroundLayer( b ) { if( b==0 ) @@ -244,7 +281,7 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) f.Write( ssprintf("#BGCHANGES%d:", b+1) ); FOREACH_CONST( BackgroundChange, out.GetBackgroundChanges(b), bgc ) - f.PutLine( BackgroundChangeToString(*bgc)+"," ); + f.PutLine( (*bgc).ToString() +"," ); /* If there's an animation plan at all, add a dummy "-nosongbg-" tag to * indicate that this file doesn't want a song BG entry added at the end. @@ -260,7 +297,7 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) f.Write( "#FGCHANGES:" ); FOREACH_CONST( BackgroundChange, out.GetForegroundChanges(), bgc ) { - f.PutLine( BackgroundChangeToString(*bgc)+"," ); + f.PutLine( (*bgc).ToString() +"," ); } f.PutLine( ";" ); } @@ -274,16 +311,7 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) } f.PutLine( ";" ); - f.Write( "#ATTACKS:" ); - for( unsigned a=0; a < out.m_sAttackString.size(); a++ ) - { - RString sData = out.m_sAttackString[a]; - f.Write( ssprintf( "%s", sData.c_str() ) ); - - if( a != (out.m_sAttackString.size() - 1) ) - f.Write( ":" ); // Not the end, so write a divider ':' - } - f.PutLine( ";" ); + f.PutLine( ssprintf("#ATTACKS:%s;", out.GetAttackString().c_str()) ); } /** @@ -301,6 +329,7 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa lines.push_back( ssprintf("//---------------%s - %s----------------", GAMEMAN->GetStepsTypeInfo(in.m_StepsType).szName, SmEscape(in.GetDescription()).c_str()) ); lines.push_back( "#NOTEDATA:;" ); // our new separator. + lines.push_back( ssprintf( "#CHARTNAME:%s;", SmEscape(in.GetChartName()).c_str())); lines.push_back( ssprintf( "#STEPSTYPE:%s;", GAMEMAN->GetStepsTypeInfo(in.m_StepsType).szName ) ); lines.push_back( ssprintf( "#DESCRIPTION:%s;", SmEscape(in.GetDescription()).c_str() ) ); lines.push_back( ssprintf( "#CHARTSTYLE:%s;", SmEscape(in.GetChartStyle()).c_str() ) ); @@ -317,22 +346,46 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa lines.push_back( ssprintf( "#RADARVALUES:%s;", join(",",asRadarValues).c_str() ) ); lines.push_back( ssprintf( "#CREDIT:%s;", SmEscape(in.GetCredit()).c_str() ) ); - - GetTimingTags( lines, in.m_Timing ); - - // For now, attacks are NOT in use for the step. - lines.push_back( "#ATTACKS:;" ); lines.push_back( ssprintf( "#OFFSET:%.6f;", in.m_Timing.m_fBeat0OffsetInSeconds ) ); - RString sNoteData; - in.GetSMNoteData( sNoteData ); + GetTimingTags( lines, in.m_Timing ); + + lines.push_back( ssprintf("#ATTACKS:%s;", in.GetAttackString().c_str())); + + switch( in.GetDisplayBPM() ) + { + case DISPLAY_BPM_ACTUAL: + // write nothing + break; + case DISPLAY_BPM_SPECIFIED: + { + float small = in.GetMinBPM(); + float big = in.GetMaxBPM(); + if (small == big) + lines.push_back( ssprintf( "#DISPLAYBPM:%.6f;", small ) ); + else + lines.push_back( ssprintf( "#DISPLAYBPM:%.6f:%.6f;", small, big ) ); + break; + } + case DISPLAY_BPM_RANDOM: + lines.push_back( ssprintf( "#DISPLAYBPM:*;" ) ); + break; + } + if (bSavingCache) + { + lines.push_back(ssprintf("#STEPFILENAME:%s;", in.GetFilename().c_str())); + } + else + { + RString sNoteData; + in.GetSMNoteData( sNoteData ); - lines.push_back( song.m_vsKeysoundFile.empty() ? "#NOTES:" : "#NOTES2:" ); - - TrimLeft(sNoteData); - split( sNoteData, "\n", lines, true ); - lines.push_back( ";" ); + lines.push_back( song.m_vsKeysoundFile.empty() ? "#NOTES:" : "#NOTES2:" ); + TrimLeft(sNoteData); + split( sNoteData, "\n", lines, true ); + lines.push_back( ";" ); + } return JoinLineList( lines ); } @@ -358,12 +411,12 @@ bool NotesWriterSSC::Write( RString sPath, const Song &out, const vector if( bSavingCache ) { f.PutLine( ssprintf( "// cache tags:" ) ); - f.PutLine( ssprintf( "#FIRSTBEAT:%.3f;", out.m_fFirstBeat ) ); - f.PutLine( ssprintf( "#LASTBEAT:%.3f;", out.m_fLastBeat ) ); + f.PutLine( ssprintf( "#FIRSTSECOND:%.6f;", out.GetFirstSecond() ) ); + f.PutLine( ssprintf( "#LASTSECOND:%.6f;", out.GetLastSecond() ) ); f.PutLine( ssprintf( "#SONGFILENAME:%s;", out.m_sSongFileName.c_str() ) ); f.PutLine( ssprintf( "#HASMUSIC:%i;", out.m_bHasMusic ) ); f.PutLine( ssprintf( "#HASBANNER:%i;", out.m_bHasBanner ) ); - f.PutLine( ssprintf( "#MUSICLENGTH:%.3f;", out.m_fMusicLengthSeconds ) ); + f.PutLine( ssprintf( "#MUSICLENGTH:%.6f;", out.m_fMusicLengthSeconds ) ); f.PutLine( ssprintf( "// end cache tags" ) ); } diff --git a/src/OptionRow.cpp b/src/OptionRow.cpp index ee043f65df..4f50268542 100644 --- a/src/OptionRow.cpp +++ b/src/OptionRow.cpp @@ -196,7 +196,7 @@ RString OptionRow::GetRowTitle() const if( GAMESTATE->m_pCurCourse ) { - const Trail* pTrail = GAMESTATE->m_pCurTrail[GAMESTATE->m_MasterPlayerNumber]; + const Trail* pTrail = GAMESTATE->m_pCurTrail[GAMESTATE->GetMasterPlayerNumber()]; ASSERT( pTrail != NULL ); const int iNumCourseEntries = pTrail->m_vEntries.size(); if( iNumCourseEntries > CommonMetrics::MAX_COURSE_ENTRIES_BEFORE_VARIOUS ) @@ -417,8 +417,8 @@ void OptionRow::AfterImportOptions( PlayerNumber pn ) // we need to copy p2 to p1, not p1 to p2. if( m_pHand->m_Def.m_bOneChoiceForAllPlayers ) { - PlayerNumber pnCopyFrom = GAMESTATE->m_MasterPlayerNumber; - if( GAMESTATE->m_MasterPlayerNumber == PLAYER_INVALID ) + PlayerNumber pnCopyFrom = GAMESTATE->GetMasterPlayerNumber(); + if( GAMESTATE->GetMasterPlayerNumber() == PLAYER_INVALID ) pnCopyFrom = PLAYER_1; FOREACH_PlayerNumber( p ) m_vbSelected[p] = m_vbSelected[pnCopyFrom]; diff --git a/src/OptionRow.h b/src/OptionRow.h index c2ef9fac4f..6ca653f88e 100644 --- a/src/OptionRow.h +++ b/src/OptionRow.h @@ -14,6 +14,9 @@ class OptionRowHandler; class GameCommand; struct OptionRowDefinition; +RString ITEMS_LONG_ROW_X_NAME( size_t p ); +RString MOD_ICON_X_NAME( size_t p ); + class OptionRowType { public: diff --git a/src/OptionRowHandler.cpp b/src/OptionRowHandler.cpp index 00125fa6b1..ebcee7a186 100644 --- a/src/OptionRowHandler.cpp +++ b/src/OptionRowHandler.cpp @@ -28,6 +28,7 @@ #define ENTRY_MODE(s,i) THEME->GetMetric ("ScreenOptionsMaster",ssprintf("%s,%i",(s).c_str(),(i+1))) #define ENTRY_DEFAULT(s) THEME->GetMetric ("ScreenOptionsMaster",(s) + "Default") #define NOTE_SKIN_SORT_ORDER THEME->GetMetric ("ScreenOptionsMaster","NoteSkinSortOrder") +#define STEPS_USE_CHART_NAME THEME->GetMetricB("ScreenOptionsMaster","StepsUseChartName") static const char *SelectTypeNames[] = { "SelectOne", @@ -449,17 +450,33 @@ class OptionRowHandlerListSteps : public OptionRowHandlerList Steps* pSteps = vpSteps[i]; RString s; + if (STEPS_USE_CHART_NAME) + { + s = pSteps->GetChartName(); + // TODO: find a way to make this use lua or metrics. + if (!(s == "" || s == "blank" || s == "Blank")) + { + goto nameGotten; + } + } if( pSteps->GetDifficulty() == Difficulty_Edit ) { - s = pSteps->GetDescription(); + s = pSteps->GetChartName(); + if (s == "" || s == "blank" || s == "Blank") + s = pSteps->GetDescription(); } else { if( pSteps->IsAnEdit() ) - s = pSteps->GetDescription(); + { + s = pSteps->GetChartName(); + if (s == "" || s == "blank" || s == "Blank") + s = pSteps->GetDescription(); + } else s = CustomDifficultyToLocalizedString( GetCustomDifficulty( pSteps->m_StepsType, pSteps->GetDifficulty(), CourseType_Invalid ) ); } + nameGotten: s += ssprintf( " %d", pSteps->GetMeter() ); m_Def.m_vsChoices.push_back( s ); GameCommand mc; diff --git a/src/PercentageDisplay.cpp b/src/PercentageDisplay.cpp index 502f8f6989..503f153eb7 100644 --- a/src/PercentageDisplay.cpp +++ b/src/PercentageDisplay.cpp @@ -137,26 +137,6 @@ void PercentageDisplay::Refresh() else { float fPercentDancePoints = m_pPlayerStageStats->GetPercentDancePoints(); - float fCurMaxPercentDancePoints = m_pPlayerStageStats->GetCurMaxPercentDancePoints(); - - if( m_bApplyScoreDisplayOptions ) - { - switch( m_pPlayerState->m_PlayerOptions.GetCurrent().m_ScoreDisplay ) - { - case PlayerOptions::SCORING_ADD: - // nothing to do - break; - case PlayerOptions::SCORING_SUBTRACT: - fPercentDancePoints = 1.0f - ( fCurMaxPercentDancePoints - fPercentDancePoints ); - break; - case PlayerOptions::SCORING_AVERAGE: - if( fCurMaxPercentDancePoints == 0.0f ) // don't divide by zero fats - fPercentDancePoints = 0.0f; - else - fPercentDancePoints = fPercentDancePoints / fCurMaxPercentDancePoints; - break; - } - } // clamp percentage - feedback is that negative numbers look weird here. CLAMP( fPercentDancePoints, 0.f, 1.f ); diff --git a/src/Player.cpp b/src/Player.cpp index 5bd48778f8..77a2b73698 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -42,6 +42,9 @@ #include "LocalizedString.h" #include "AdjustSync.h" +RString ATTACK_DISPLAY_X_NAME( size_t p, size_t both_sides ); +void TimingWindowSecondsInit( size_t /*TimingWindow*/ i, RString &sNameOut, float &defaultValueOut ); + /** * @brief Helper class to ensure that each row is only judged once without taking too much memory. */ @@ -112,7 +115,7 @@ void TimingWindowSecondsInit( size_t /*TimingWindow*/ i, RString &sNameOut, floa case TW_W5: defaultValueOut = 0.180f; break; case TW_Mine: defaultValueOut = 0.090f; break; // same as great case TW_Hold: defaultValueOut = 0.500f; break; // allow enough time to take foot off and put back on - case TW_Roll: defaultValueOut = 0.350f; break; + case TW_Roll: defaultValueOut = 0.500f; break; case TW_Attack: defaultValueOut = 0.135f; break; } } @@ -198,6 +201,12 @@ ThemeMetric COMBO_STOPPED_AT ( "Player", "ComboStoppedAt" ); ThemeMetric ATTACK_RUN_TIME_RANDOM ( "Player", "AttackRunTimeRandom" ); ThemeMetric ATTACK_RUN_TIME_MINE ( "Player", "AttackRunTimeMine" ); +/** + * @brief What is our highest cap for mMods? + * + * If set to 0 or less, assume the song takes over. */ +ThemeMetric M_MOD_HIGH_CAP("Player", "MModHighCap"); + /** @brief Will battle modes have their steps mirrored or kept the same? */ ThemeMetric BATTLE_RAVE_MIRROR ( "Player", "BattleRaveMirror" ); @@ -398,6 +407,75 @@ void Player::Init( break; } + // calculate M-mod speed here, so we can adjust properly on a per-song basis. + // XXX: can we find a better location for this? + if( m_pPlayerState->m_PlayerOptions.GetCurrent().m_fMaxScrollBPM != 0 ) + { + DisplayBpms bpms; + + if( GAMESTATE->IsCourseMode() ) + { + ASSERT( GAMESTATE->m_pCurTrail[pn] ); + GAMESTATE->m_pCurTrail[pn]->GetDisplayBpms( bpms ); + } + else + { + ASSERT( GAMESTATE->m_pCurSong ); + GAMESTATE->m_pCurSong->GetDisplayBpms( bpms ); + } + + float fMaxBPM = 0; + + /* TODO: Find a way to not go above a certain BPM range + * for getting the max BPM. Otherwise, you get songs + * like Tsuhsuixamush, M550, 0.18x speed. Even slow + * speed readers would not generally find this fun. + * -Wolfman2000 + */ + + // all BPMs are listed and available, so try them first. + // get the maximum listed value for the song or course. + // if the BPMs are < 0, reset and get the actual values. + if( !bpms.IsSecret() ) + { + fMaxBPM = (M_MOD_HIGH_CAP > 0 ? + bpms.GetMaxWithin(M_MOD_HIGH_CAP) : + bpms.GetMax()); + fMaxBPM = max( 0, fMaxBPM ); + } + + // we can't rely on the displayed BPMs, so manually calculate. + if( fMaxBPM == 0 ) + { + float fThrowAway = 0; + + if( GAMESTATE->IsCourseMode() ) + { + FOREACH_CONST( TrailEntry, GAMESTATE->m_pCurTrail[pn]->m_vEntries, e ) + { + float fMaxForEntry; + if (M_MOD_HIGH_CAP > 0) + e->pSong->m_SongTiming.GetActualBPM( fThrowAway, fMaxForEntry, M_MOD_HIGH_CAP ); + else + e->pSong->m_SongTiming.GetActualBPM( fThrowAway, fMaxForEntry ); + fMaxBPM = max( fMaxForEntry, fMaxBPM ); + } + } + else + { + if (M_MOD_HIGH_CAP > 0) + GAMESTATE->m_pCurSong->m_SongTiming.GetActualBPM( fThrowAway, fMaxBPM, M_MOD_HIGH_CAP ); + else + GAMESTATE->m_pCurSong->m_SongTiming.GetActualBPM( fThrowAway, fMaxBPM ); + } + } + + ASSERT( fMaxBPM > 0 ); + + // set an X-mod equal to Mnum / fMaxBPM (e.g. M600 with 150 becomes 4x) + PO_GROUP_ASSIGN(m_pPlayerState->m_PlayerOptions, ModsLevel_Preferred, m_fScrollSpeed, + m_pPlayerState->m_PlayerOptions.GetPreferred().m_fMaxScrollBPM / fMaxBPM); + } float fBalance = GameSoundManager::GetPlayerBalance( pn ); m_soundMine.SetProperty( "Pan", fBalance ); @@ -789,7 +867,7 @@ void Player::Update( float fDeltaTime ) Actor::TweenState::MakeWeightedAverage( m_pActorWithComboPosition->DestTweenState(), ts1, ts2, fPercentCentered ); } - float fNoteFieldZoom = 1 - fTinyPercent*0.5f; + float fNoteFieldZoom = 1 - fMiniPercent*0.5f; if( m_pNoteField ) m_pNoteField->SetZoom( fNoteFieldZoom ); if( m_pActorWithJudgmentPosition != NULL ) @@ -957,8 +1035,10 @@ void Player::Update( float fDeltaTime ) UpdateJudgedRows(); // Check for TapNote misses - UpdateTapNotesMissedOlderThan( GetMaxStepDistanceSeconds() ); - + if (!GAMESTATE->m_bInStepEditor) + { + UpdateTapNotesMissedOlderThan( GetMaxStepDistanceSeconds() ); + } // process transforms that are waiting to be applied ApplyWaitingTransforms(); } @@ -1323,14 +1403,9 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector= 0 && tn.iKeysoundIndex < (int) m_vKeysounds.size() ) { - if( tn.subType == TapNote::hold_head_roll ) - { - m_vKeysounds[tn.iKeysoundIndex].SetProperty ("Volume", max(0.0, min(1.0, fLifeFraction * 2.0))); - } - else - { - m_vKeysounds[tn.iKeysoundIndex].SetProperty ("Volume", max(0.0, min(1.0, fLifeFraction * 10.0 - 8.5))); - } + float factor = (tn.subType == TapNote::hold_head_roll ? 2 : 10.0f - 8.5f); + factor *= fLifeFraction; + m_vKeysounds[tn.iKeysoundIndex].SetProperty ("Volume", max(0.0f, min(1.0f, factor))); } } @@ -1375,7 +1450,7 @@ void Player::DrawPrimitives() // May have both players in doubles (for battle play); only draw primary player. if( GAMESTATE->GetCurrentStyle()->m_StyleType == StyleType_OnePlayerTwoSides && - pn != GAMESTATE->m_MasterPlayerNumber ) + pn != GAMESTATE->GetMasterPlayerNumber() ) return; // Draw these below everything else. @@ -1413,7 +1488,7 @@ void Player::DrawPrimitives() float fTiltDegrees = SCALE(fTilt,-1.f,+1.f,+30,-30) * (bReverse?-1:1); - float fZoom = SCALE( m_pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_TINY], 0.f, 1.f, 1.f, 0.5f ); + float fZoom = SCALE( m_pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_MINI], 0.f, 1.f, 1.f, 0.5f ); if( fTilt > 0 ) fZoom *= SCALE( fTilt, 0.f, 1.f, 1.f, 0.9f ); else @@ -1437,7 +1512,7 @@ void Player::DrawPrimitives() DISPLAY->PopMatrix(); // m_pNoteField->m_sprBoard->GetVisible() - if( !(bool)COMBO_UNDER_FIELD && m_pPlayerState->m_PlayerOptions.GetCurrent().m_fBlind == 0 ) + if( !COMBO_UNDER_FIELD && m_pPlayerState->m_PlayerOptions.GetCurrent().m_fBlind == 0 ) if( m_sprCombo ) m_sprCombo->Draw(); @@ -1538,7 +1613,7 @@ int Player::GetClosestNoteDirectional( int col, int iStartRow, int iEndRow, bool // Is this the row we want? do { const TapNote &tn = begin->second; - if( m_Timing->IsWarpAtRow( begin->first ) || m_Timing->IsFakeAtRow( begin->first ) ) + if (!m_Timing->IsJudgableAtRow( begin->first )) break; if( tn.type == TapNote::empty ) break; @@ -1594,7 +1669,7 @@ int Player::GetClosestNonEmptyRowDirectional( int iStartRow, int iEndRow, bool b ++iter; continue; } - if( m_Timing->IsWarpAtRow( iter.Row() ) || m_Timing->IsFakeAtRow( iter.Row() ) ) + if (!m_Timing->IsJudgableAtRow(iter.Row())) { ++iter; continue; @@ -2118,7 +2193,7 @@ void Player::StepStrumHopo( int col, int row, const RageTimer &tm, bool bHeld, b // Stepped too close to mine? if( !bRelease && ( REQUIRE_STEP_ON_MINES == !bHeld ) && fSecondsFromExact <= GetWindowSeconds(TW_Mine) && - !m_Timing->IsWarpAtRow(iSongRow) && !m_Timing->IsFakeAtRow(iSongRow)) + m_Timing->IsJudgableAtRow(iSongRow)) score = TNS_HitMine; break; @@ -2616,7 +2691,7 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds ) continue; // Ignore all notes in WarpSegments or FakeSegments. - if( m_Timing->IsWarpAtRow( iter.Row() ) || m_Timing->IsFakeAtRow( iter.Row() ) ) + if (!m_Timing->IsJudgableAtRow(iter.Row())) continue; if( tn.type == TapNote::mine ) @@ -2651,7 +2726,7 @@ void Player::UpdateJudgedRows() int iRow = iter.Row(); // Do not judge arrows in WarpSegments or FakeSegments - if( m_Timing->IsWarpAtRow(iRow) || m_Timing->IsFakeAtRow(iRow) ) + if (!m_Timing->IsJudgableAtRow(iRow)) continue; if( iLastSeenRow != iRow ) @@ -2852,7 +2927,8 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) // check to see if there's a note at the crossed row if( m_pPlayerState->m_PlayerController != PC_HUMAN ) { - if( tn.type != TapNote::empty && tn.type != TapNote::fake && tn.result.tns == TNS_None ) + if(tn.type != TapNote::empty && tn.type != TapNote::fake && tn.result.tns == TNS_None + && this->m_Timing->IsJudgableAtRow(iRow) ) { Step( iTrack, iRow, now, false, false ); if( m_pPlayerState->m_PlayerController == PC_AUTOPLAY ) @@ -2866,8 +2942,10 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) } - // Update hold checkpoints - if( HOLD_CHECKPOINTS ) + /* Update hold checkpoints + * + * TODO: Move this to a separate function. */ + if( HOLD_CHECKPOINTS && m_pPlayerState->m_PlayerController != PC_AUTOPLAY ) { int iCheckpointFrequencyRows = ROWS_PER_BEAT/2; if( CHECKPOINTS_USE_TICKCOUNTS ) @@ -2878,19 +2956,21 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) } else if( CHECKPOINTS_USE_TIME_SIGNATURES ) { - TimeSignatureSegment tSignature = m_Timing->GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iLastRowCrossed ) ); + TimeSignatureSegment * tSignature = m_Timing->GetTimeSignatureSegmentAtRow( iLastRowCrossed ); // Most songs are in 4/4 time. The frequency for checking tick counts should reflect that. - iCheckpointFrequencyRows = ROWS_PER_BEAT * tSignature.GetDen() / (tSignature.GetNum() * 4); + iCheckpointFrequencyRows = ROWS_PER_BEAT * tSignature->GetDen() / (tSignature->GetNum() * 4); } if( iCheckpointFrequencyRows > 0 ) { // "the first row after the start of the range that lands on a beat" - int iFirstCheckpointInRange = ((m_iFirstUncrossedRow+iCheckpointFrequencyRows-1)/iCheckpointFrequencyRows) * iCheckpointFrequencyRows; + int iFirstCheckpointInRange = ((m_iFirstUncrossedRow+iCheckpointFrequencyRows-1) + /iCheckpointFrequencyRows) * iCheckpointFrequencyRows; // "the last row or first row earlier that lands on a beat" - int iLastCheckpointInRange = ((iLastRowCrossed)/iCheckpointFrequencyRows) * iCheckpointFrequencyRows; + int iLastCheckpointInRange = ((iLastRowCrossed)/iCheckpointFrequencyRows) + * iCheckpointFrequencyRows; for( int r = iFirstCheckpointInRange; r <= iLastCheckpointInRange; r += iCheckpointFrequencyRows ) { @@ -2912,17 +2992,22 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) int iTrack = nIter.Track(); // "the first row after the hold head that lands on a beat" - int iFirstCheckpointOfHold = ((iStartRow+iCheckpointFrequencyRows)/iCheckpointFrequencyRows) * iCheckpointFrequencyRows; + int iFirstCheckpointOfHold = ((iStartRow+iCheckpointFrequencyRows)/iCheckpointFrequencyRows) + * iCheckpointFrequencyRows; // "the end row or the first earlier row that lands on a beat" - int iLastCheckpointOfHold = ((iEndRow)/iCheckpointFrequencyRows) * iCheckpointFrequencyRows; + int iLastCheckpointOfHold = ((iEndRow)/iCheckpointFrequencyRows) + * iCheckpointFrequencyRows; // count the end of the hold as a checkpoint bool bHoldOverlapsRow = iFirstCheckpointOfHold <= r && r <= iLastCheckpointOfHold; if( !bHoldOverlapsRow ) continue; + + viColsWithHold.push_back( iTrack ); + if( tn.HoldResult.fLife > 0 ) { ++iNumHoldsHeldThisRow; @@ -2934,11 +3019,15 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) ++tn.HoldResult.iCheckpointsMissed; } } + GAMESTATE->SetProcessedTimingData(this->m_Timing); // TODO: Find a better way of handling hold checkpoints with other taps. if( !viColsWithHold.empty() && ( CHECKPOINTS_TAPS_SEPARATE_JUDGMENT || m_NoteData.GetNumTapNotesInRow( iLastRowCrossed ) == 0 ) ) { - HandleHoldCheckpoint( r, iNumHoldsHeldThisRow, iNumHoldsMissedThisRow, viColsWithHold ); + HandleHoldCheckpoint(r, + iNumHoldsHeldThisRow, + iNumHoldsMissedThisRow, + viColsWithHold ); } } } @@ -2965,10 +3054,6 @@ void Player::RandomizeNotes( int iNoteRow ) const int iSwapWith = RandomInt( iNumOfTracks ); - // Make sure we're not swapping with ourselves. - if( t == iSwapWith ) - continue; - // Make sure this is empty. if( m_NoteData.FindTapNote(iSwapWith, iNewNoteRow) != m_NoteData.end(iSwapWith) ) continue; @@ -2990,7 +3075,7 @@ void Player::HandleTapRowScore( unsigned row ) #endif // Do not score rows in WarpSegments or FakeSegments - if( m_Timing->IsWarpAtRow( row ) || m_Timing->IsFakeAtRow( row ) ) + if (!m_Timing->IsJudgableAtRow(row)) return; if( GAMESTATE->m_bDemonstrationOrJukebox ) @@ -3086,7 +3171,10 @@ void Player::HandleTapRowScore( unsigned row ) ChangeLife( scoreOfLastTap ); } -void Player::HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumHoldsMissedThisRow, const vector &viColsWithHold ) +void Player::HandleHoldCheckpoint(int iRow, + int iNumHoldsHeldThisRow, + int iNumHoldsMissedThisRow, + const vector &viColsWithHold ) { bool bNoCheating = true; #ifdef DEBUG @@ -3094,7 +3182,7 @@ void Player::HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumH #endif // WarpSegments and FakeSegments aren't judged in any way. - if( m_Timing->IsWarpAtRow( iRow ) || m_Timing->IsFakeAtRow( iRow ) ) + if (!m_Timing->IsJudgableAtRow(iRow)) return; // don't accumulate combo if AutoPlay is on. @@ -3105,9 +3193,15 @@ void Player::HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumH const int iOldMissCombo = m_pPlayerStageStats ? m_pPlayerStageStats->m_iCurMissCombo : 0; if( m_pPrimaryScoreKeeper ) - m_pPrimaryScoreKeeper->HandleHoldCheckpointScore( m_NoteData, iRow, iNumHoldsHeldThisRow, iNumHoldsMissedThisRow ); + m_pPrimaryScoreKeeper->HandleHoldCheckpointScore(m_NoteData, + iRow, + iNumHoldsHeldThisRow, + iNumHoldsMissedThisRow ); if( m_pSecondaryScoreKeeper ) - m_pSecondaryScoreKeeper->HandleHoldCheckpointScore( m_NoteData, iRow, iNumHoldsHeldThisRow, iNumHoldsMissedThisRow ); + m_pSecondaryScoreKeeper->HandleHoldCheckpointScore(m_NoteData, + iRow, + iNumHoldsHeldThisRow, + iNumHoldsMissedThisRow ); if( iNumHoldsMissedThisRow == 0 ) { @@ -3116,7 +3210,8 @@ void Player::HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumH { FOREACH_CONST( int, viColsWithHold, i ) { - bool bBright = m_pPlayerStageStats && m_pPlayerStageStats->m_iCurCombo>(int)BRIGHT_GHOST_COMBO_THRESHOLD; + bool bBright = m_pPlayerStageStats + && m_pPlayerStageStats->m_iCurCombo>(int)BRIGHT_GHOST_COMBO_THRESHOLD; if( m_pNoteField ) m_pNoteField->DidHoldNote( *i, HNS_Held, bBright ); } @@ -3285,12 +3380,14 @@ void Player::SetCombo( int iCombo, int iMisses ) if( GAMESTATE->IsCourseMode() ) { int iSongIndexStartColoring = GAMESTATE->m_pCurCourse->GetEstimatedNumStages(); - iSongIndexStartColoring = static_cast(floor(iSongIndexStartColoring*PERCENT_UNTIL_COLOR_COMBO)); + iSongIndexStartColoring = + static_cast(floor(iSongIndexStartColoring*PERCENT_UNTIL_COLOR_COMBO)); bPastBeginning = GAMESTATE->GetCourseSongIndex() >= iSongIndexStartColoring; } else { - bPastBeginning = m_pPlayerState->m_Position.m_fMusicSeconds > GAMESTATE->m_pCurSong->m_fMusicLengthSeconds * PERCENT_UNTIL_COLOR_COMBO; + bPastBeginning = m_pPlayerState->m_Position.m_fMusicSeconds + > GAMESTATE->m_pCurSong->m_fMusicLengthSeconds * PERCENT_UNTIL_COLOR_COMBO; } if( m_bSendJudgmentAndComboMessages ) @@ -3332,13 +3429,29 @@ RString Player::ApplyRandomAttack() class LunaPlayer: public Luna { public: - static int SetActorWithJudgmentPosition( T* p, lua_State *L ) { Actor *pActor = Luna::check(L, 1); p->SetActorWithJudgmentPosition(pActor); return 0; } - static int SetActorWithComboPosition( T* p, lua_State *L ) { Actor *pActor = Luna::check(L, 1); p->SetActorWithComboPosition(pActor); return 0; } - + static int SetActorWithJudgmentPosition( T* p, lua_State *L ) + { + Actor *pActor = Luna::check(L, 1); + p->SetActorWithJudgmentPosition(pActor); + return 0; + } + static int SetActorWithComboPosition( T* p, lua_State *L ) + { + Actor *pActor = Luna::check(L, 1); + p->SetActorWithComboPosition(pActor); + return 0; + } + static int GetPlayerTimingData( T* p, lua_State *L ) + { + p->GetPlayerTimingData().PushSelf(L); + return 1; + } + LunaPlayer() { ADD_METHOD( SetActorWithJudgmentPosition ); ADD_METHOD( SetActorWithComboPosition ); + ADD_METHOD( GetPlayerTimingData ); } }; diff --git a/src/Player.h b/src/Player.h index 8d85733858..f2cb2c9b5c 100644 --- a/src/Player.h +++ b/src/Player.h @@ -69,6 +69,16 @@ public: void Load(); void CrossedRows( int iLastRowCrossed, const RageTimer &now ); bool IsOniDead() const; + + /** + * @brief Retrieve the Player's TimingData. + * + * This is primarily for a lua hook. + * @return the TimingData in question. */ + TimingData GetPlayerTimingData() const + { + return *(this->m_Timing); + } // Called when a fret, step, or strum type button changes void Fret( int col, int row, const RageTimer &tm, bool bHeld, bool bRelease ); diff --git a/src/PlayerOptions.cpp b/src/PlayerOptions.cpp index 363851cd6a..a6f279a107 100644 --- a/src/PlayerOptions.cpp +++ b/src/PlayerOptions.cpp @@ -12,6 +12,9 @@ #include "CommonMetrics.h" #include +void NextFloat( float fValues[], int size ); +void NextBool( bool bValues[], int size ); + ThemeMetric RANDOM_SPEED_CHANCE ( "PlayerOptions", "RandomSpeedChance" ); ThemeMetric RANDOM_REVERSE_CHANCE ( "PlayerOptions", "RandomReverseChance" ); ThemeMetric RANDOM_DARK_CHANCE ( "PlayerOptions", "RandomDarkChance" ); @@ -23,6 +26,7 @@ ThemeMetric RANDOM_SUDDEN_CHANCE ( "PlayerOptions", "RandomSuddenChance" void PlayerOptions::Init() { m_bSetScrollSpeed = false; + m_fMaxScrollBPM = 0; m_SpeedfMaxScrollBPM = 1.0f; m_fTimeSpacing = 0; m_SpeedfTimeSpacing = 1.0f; m_fScrollSpeed = 1.0f; m_SpeedfScrollSpeed = 1.0f; m_fScrollBPM = 200; m_SpeedfScrollBPM = 1.0f; @@ -34,7 +38,7 @@ void PlayerOptions::Init() m_fBlind = 0; m_SpeedfBlind = 1.0f; m_fCover = 0; m_SpeedfCover = 1.0f; m_fRandAttack = 0; m_SpeedfRandAttack = 1.0f; - m_fSongAttack = 0; m_SpeedfSongAttack = 1.0f; + m_fNoAttack = 0; m_SpeedfNoAttack = 1.0f; m_fPlayerAutoPlay = 0; m_SpeedfPlayerAutoPlay = 1.0f; m_bSetTiltOrSkew = false; m_fPerspectiveTilt = 0; m_SpeedfPerspectiveTilt = 1.0f; @@ -45,7 +49,6 @@ void PlayerOptions::Init() ZERO( m_bTransforms ); m_bMuteOnError = false; m_FailType = FAIL_IMMEDIATE; - m_ScoreDisplay = SCORING_ADD; m_sNoteSkin = ""; } @@ -58,6 +61,7 @@ void PlayerOptions::Approach( const PlayerOptions& other, float fDeltaSeconds ) APPROACH( fTimeSpacing ); APPROACH( fScrollSpeed ); + //APPROACH( fMaxScrollBPM ); fapproach( m_fScrollBPM, other.m_fScrollBPM, fDeltaSeconds * other.m_SpeedfScrollBPM*150 ); for( int i=0; i &AddTo, bool bForceNoteSkin ) const if( !m_fTimeSpacing ) { + if( m_fMaxScrollBPM ) + { + RString s = ssprintf( "m%.0f", m_fMaxScrollBPM ); + AddTo.push_back( s ); + } if( m_bSetScrollSpeed || m_fScrollSpeed != 1 ) { /* -> 1.00 */ @@ -179,7 +187,7 @@ void PlayerOptions::GetMods( vector &AddTo, bool bForceNoteSkin ) const AddPart( AddTo, m_fCover, "Cover" ); AddPart( AddTo, m_fRandAttack, "RandomAttacks" ); - AddPart( AddTo, m_fSongAttack, "SongAttacks" ); + AddPart( AddTo, m_fNoAttack, "NoAttacks" ); AddPart( AddTo, m_fPlayerAutoPlay, "PlayerAutoPlay" ); AddPart( AddTo, m_fPassmark, "Passmark" ); @@ -331,6 +339,7 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut SET_FLOAT( fScrollSpeed ) SET_FLOAT( fTimeSpacing ) m_fTimeSpacing = 0; + m_fMaxScrollBPM = 0; } else if( sscanf( sBit, "c%f", &level ) == 1 ) { @@ -339,17 +348,18 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut SET_FLOAT( fScrollBPM ) SET_FLOAT( fTimeSpacing ) m_fTimeSpacing = 1; + m_fMaxScrollBPM = 0; } - /* Port M-Mods from OpenITG, starting from r537 */ - // Midiman + // oITG's m-mods + // XXX: will not properly tween, I don't think. else if( sscanf( sBit, "m%f", &level ) == 1 ) { if( !isfinite(level) || level <= 0.0f ) - level = 200.0f; // Just pick some value. - SET_FLOAT( fScrollBPM ) - SET_FLOAT( fTimeSpacing ) - m_fTimeSpacing = 1; + level = 200.0f; + SET_FLOAT( fMaxScrollBPM ) + m_fTimeSpacing = 0; } + else if( sBit == "clearall" ) Init(); else if( sBit == "boost" ) SET_FLOAT( fAccels[ACCEL_BOOST] ) else if( sBit == "brake" || sBit == "land" ) SET_FLOAT( fAccels[ACCEL_BRAKE] ) @@ -416,7 +426,7 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut else if( sBit == "blind" ) SET_FLOAT( fBlind ) else if( sBit == "cover" ) SET_FLOAT( fCover ) else if( sBit == "randomattacks" ) SET_FLOAT( fRandAttack ) - else if( sBit == "songattacks" ) SET_FLOAT( fSongAttack ) + else if( sBit == "noattacks" ) SET_FLOAT( fNoAttack ) else if( sBit == "playerautoplay" ) SET_FLOAT( fPlayerAutoPlay ) else if( sBit == "passmark" ) SET_FLOAT( fPassmark ) else if( sBit == "overhead" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = 0; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; } @@ -439,9 +449,6 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut GAMESTATE->GetDefaultPlayerOptions( po ); m_FailType = po.m_FailType; } - else if( sBit == "addscore" ) m_ScoreDisplay = SCORING_ADD; - else if( sBit == "subtractscore" ) m_ScoreDisplay = SCORING_SUBTRACT; - else if( sBit == "averagescore" ) m_ScoreDisplay = SCORING_AVERAGE; else if( sBit == "muteonerror" ) m_bMuteOnError = on; else if( sBit == "random" ) ChooseRandomModifiers(); // deprecated mods/left in for compatibility @@ -652,15 +659,15 @@ bool PlayerOptions::operator==( const PlayerOptions &other ) const COMPARE(m_fTimeSpacing); COMPARE(m_fScrollSpeed); COMPARE(m_fScrollBPM); + COMPARE(m_fMaxScrollBPM); COMPARE(m_fRandomSpeed); - COMPARE(m_ScoreDisplay); COMPARE(m_FailType); COMPARE(m_bMuteOnError); COMPARE(m_fDark); COMPARE(m_fBlind); COMPARE(m_fCover); COMPARE(m_fRandAttack); - COMPARE(m_fSongAttack); + COMPARE(m_fNoAttack); COMPARE(m_fPlayerAutoPlay); COMPARE(m_fPerspectiveTilt); COMPARE(m_fSkew); @@ -715,7 +722,36 @@ bool PlayerOptions::IsEasierForSongAndSteps( Song* pSong, Steps* pSteps, PlayerN // This makes songs with sparse notes easier. if( m_bTransforms[TRANSFORM_ECHO] ) return true; + // Removing attacks is easier in general. + if (m_fNoAttack || (!m_fRandAttack && pSteps->HasAttacks())) + return true; + if( m_fCover ) return true; + + // M-mods make songs with indefinite BPMs easier because + // they ensure that the song has a scrollable speed. + if( m_fMaxScrollBPM != 0 ) + { + // BPM display is obfuscated +// if( pSong->m_DisplayBPMType == DISPLAY_BPM_RANDOM ) +// return true; + + DisplayBpms bpms; + if( GAMESTATE->IsCourseMode() ) + { + Trail *pTrail = GAMESTATE->m_pCurCourse->GetTrail( GAMESTATE->GetCurrentStyle()->m_StepsType ); + pTrail->GetDisplayBpms( bpms ); + } + else + { + GAMESTATE->m_pCurSong->GetDisplayBpms( bpms ); + } + pSong->GetDisplayBpms( bpms ); + + // maximum BPM is obfuscated, so M-mods will set a playable speed. + if( bpms.GetMax() <= 0 ) + return true; + } if( m_fPlayerAutoPlay ) return true; return false; } @@ -787,6 +823,7 @@ RString PlayerOptions::GetSavedPrefsString() const SAVE( m_fTimeSpacing ); SAVE( m_fScrollSpeed ); SAVE( m_fScrollBPM ); + SAVE( m_fMaxScrollBPM ); SAVE( m_fScrolls[SCROLL_REVERSE] ); SAVE( m_fPerspectiveTilt ); SAVE( m_bTransforms[TRANSFORM_NOHOLDS] ); @@ -798,7 +835,6 @@ RString PlayerOptions::GetSavedPrefsString() const SAVE( m_bTransforms[TRANSFORM_NOSTRETCH] ); SAVE( m_bTransforms[TRANSFORM_NOLIFTS] ); SAVE( m_bTransforms[TRANSFORM_NOFAKES] ); - SAVE( m_ScoreDisplay ); SAVE( m_bMuteOnError ); SAVE( m_sNoteSkin ); #undef SAVE @@ -816,6 +852,7 @@ void PlayerOptions::ResetPrefs( ResetPrefsType type ) CPY( m_fTimeSpacing ); CPY( m_fScrollSpeed ); CPY( m_fScrollBPM ); + CPY( m_fMaxScrollBPM ); break; case saved_prefs_invalid_for_course: break; @@ -961,7 +998,20 @@ public: DEFINE_METHOD( GetBlind, m_fBlind ) DEFINE_METHOD( GetCover, m_fCover ) DEFINE_METHOD( GetRandomAttacks, m_fRandAttack ) - DEFINE_METHOD( GetSongAttacks, m_fSongAttack ) + + static int GetStepAttacks( T *p, lua_State *L ) + { + lua_pushnumber(L, + (p->m_fNoAttack > 0 || p->m_fRandAttack > 0 ? 0 : 1 )); + return 1; + } + + // This one is deprecated. + static int GetSongAttacks( T *p, lua_State *L ) + { + return GetStepAttacks(p, L); + } + DEFINE_METHOD( GetNoAttacks, m_fNoAttack ) DEFINE_METHOD( GetSkew, m_fSkew ) DEFINE_METHOD( GetPassmark, m_fPassmark ) DEFINE_METHOD( GetRandomSpeed, m_fRandomSpeed ) @@ -988,6 +1038,8 @@ public: // SetSkew ADD_METHOD( GetSongAttacks ); // SetSongAttacks + ADD_METHOD( GetStepAttacks ); + ADD_METHOD( GetNoAttacks ); ADD_METHOD( GetCMod ); ADD_METHOD( GetXMod ); diff --git a/src/PlayerOptions.h b/src/PlayerOptions.h index c6ea986160..0166af9c4e 100644 --- a/src/PlayerOptions.h +++ b/src/PlayerOptions.h @@ -27,15 +27,14 @@ public: m_fBlind(0), m_SpeedfBlind(1.0f), m_fCover(0), m_SpeedfCover(1.0f), m_fRandAttack(0), m_SpeedfRandAttack(1.0f), - m_fSongAttack(0), m_SpeedfSongAttack(1.0f), + m_fNoAttack(0), m_SpeedfNoAttack(1.0f), m_fPlayerAutoPlay(0), m_SpeedfPlayerAutoPlay(1.0f), m_bSetTiltOrSkew(false), m_fPerspectiveTilt(0), m_SpeedfPerspectiveTilt(1.0f), m_fSkew(0), m_SpeedfSkew(1.0f), m_fPassmark(0), m_SpeedfPassmark(1.0f), m_fRandomSpeed(0), m_SpeedfRandomSpeed(1.0f), - m_bMuteOnError(false), m_FailType(FAIL_IMMEDIATE), - m_ScoreDisplay(SCORING_ADD) + m_bMuteOnError(false), m_FailType(FAIL_IMMEDIATE) { m_sNoteSkin = ""; ZERO( m_fAccels ); ONE( m_SpeedfAccels ); @@ -151,12 +150,6 @@ public: SCROLL_CENTERED, NUM_SCROLLS }; - enum ScoreDisplay { - SCORING_ADD=0, - SCORING_SUBTRACT, - SCORING_AVERAGE, - NUM_SCOREDISPLAYS - }; float GetReversePercentForColumn( int iCol ) const; // accounts for all Directions @@ -164,6 +157,7 @@ public: * PlayerOptions::Approach approaches. */ bool m_bSetScrollSpeed; // true if the scroll speed was set by FromString float m_fTimeSpacing, m_SpeedfTimeSpacing; // instead of Beat spacing (CMods, mMods) + float m_fMaxScrollBPM, m_SpeedfMaxScrollBPM; float m_fScrollSpeed, m_SpeedfScrollSpeed; // used if !m_bTimeSpacing (xMods) float m_fScrollBPM, m_SpeedfScrollBPM; // used if m_bTimeSpacing (CMod) float m_fAccels[NUM_ACCELS], m_SpeedfAccels[NUM_ACCELS]; @@ -174,7 +168,7 @@ public: float m_fBlind, m_SpeedfBlind; float m_fCover, m_SpeedfCover; // hide the background per-player--can't think of a good name float m_fRandAttack, m_SpeedfRandAttack; - float m_fSongAttack, m_SpeedfSongAttack; + float m_fNoAttack, m_SpeedfNoAttack; float m_fPlayerAutoPlay, m_SpeedfPlayerAutoPlay; bool m_bSetTiltOrSkew; // true if the tilt or skew was set by FromString float m_fPerspectiveTilt, m_SpeedfPerspectiveTilt; // -1 = near, 0 = overhead, +1 = space @@ -198,7 +192,6 @@ public: }; /** @brief The method for which a player can fail a song. */ FailType m_FailType; - ScoreDisplay m_ScoreDisplay; /** * @brief The Noteskin to use. diff --git a/src/PlayerState.cpp b/src/PlayerState.cpp index 9d7b652851..c30805daf9 100644 --- a/src/PlayerState.cpp +++ b/src/PlayerState.cpp @@ -162,7 +162,7 @@ void PlayerState::RebuildPlayerOptionsFromActiveAttacks() so.FromString( m_ActiveAttacks[s].sModifiers ); } m_PlayerOptions.Assign( ModsLevel_Song, po ); - if( m_PlayerNumber == GAMESTATE->m_MasterPlayerNumber ) + if( m_PlayerNumber == GAMESTATE->GetMasterPlayerNumber() ) GAMESTATE->m_SongOptions.Assign( ModsLevel_Song, so ); int iSumOfAttackLevels = GetSumOfActiveAttackLevels(); diff --git a/src/PrefsManager.h b/src/PrefsManager.h index 2d1f564bb3..589da26533 100644 --- a/src/PrefsManager.h +++ b/src/PrefsManager.h @@ -5,6 +5,9 @@ class IniFile; +void ValidateDisplayAspectRatio( float &val ); +void ValidateSongsPerPlay( int &val ); + /** @brief How many songs can be played during a normal game max? * * This assumes no extra stages, no event mode, no course modes. */ diff --git a/src/ProductInfo.h b/src/ProductInfo.h index e6cd9db7a8..26abef4c1f 100644 --- a/src/ProductInfo.h +++ b/src/ProductInfo.h @@ -35,7 +35,7 @@ * */ #ifndef PRODUCT_VER_BARE -#define PRODUCT_VER_BARE v5.0 Preview 1a +#define PRODUCT_VER_BARE v5.0 Preview 2 #endif /** @@ -54,7 +54,7 @@ #define PRODUCT_VER PRODUCT_XSTRINGIFY(PRODUCT_VER_BARE) #define PRODUCT_ID_VER PRODUCT_XSTRINGIFY(PRODUCT_ID_VER_BARE) -#define VIDEO_TROUBLESHOOTING_URL "http://www.stepmania.com/stepmania/mediawiki.php?title=Video_Driver_Troubleshooting" +#define VIDEO_TROUBLESHOOTING_URL "http://www.stepmania.com/stepmaniawiki.php?title=Video_Driver_Troubleshooting" /** @brief The URL to report bugs on the program. */ #define REPORT_BUG_URL "http://ssc.ajworld.net/sm-ssc/bugtracker/" diff --git a/src/ProductInfo.inc b/src/ProductInfo.inc index 56c9ce457d..f34a704abf 100644 --- a/src/ProductInfo.inc +++ b/src/ProductInfo.inc @@ -5,12 +5,12 @@ ; see ProductInfo.h for use descriptions !define PRODUCT_ID "StepMania" -!define PRODUCT_VER "v5.0 Preview 1a" +!define PRODUCT_VER "v5.0 Preview 2" !define PRODUCT_DISPLAY "${PRODUCT_ID} ${PRODUCT_VER}" -!define PRODUCT_BITMAP "ssc" +!define PRODUCT_BITMAP "sm5" !define PRODUCT_URL "http://www.stepmania.com/" -!define UPDATES_URL "http://www.stepmania.com/" +!define UPDATES_URL "http://code.google.com/p/sm-ssc/downloads/list" ;!define INSTALL_EXTERNAL_PCKS ;!define INSTALL_INTERNAL_PCKS diff --git a/src/RageDisplay.h b/src/RageDisplay.h index 9cad4f74c4..ca881c85f5 100644 --- a/src/RageDisplay.h +++ b/src/RageDisplay.h @@ -112,7 +112,7 @@ public: bpp(0), rate(0), vsync(false), interlaced(false), bSmoothLines(false), bTrilinearFiltering(false), bAnisotropicFiltering(false), sWindowTitle(RString()), - sIconFile(RString()), PAL(false), fDisplayAspectRatio(0.0) {} + sIconFile(RString()), PAL(false), fDisplayAspectRatio(0.0f) {} bool windowed; int width; diff --git a/src/RageDisplay_Legacy.cpp b/src/RageDisplay_Legacy.cpp index b2ea632c5d..2b664f2f5b 100644 --- a/src/RageDisplay_Legacy.cpp +++ b/src/RageDisplay_Legacy.cpp @@ -31,6 +31,13 @@ using namespace RageDisplay_Legacy_Helpers; #define glFlush() #endif +RString GetInfoLog( GLhandleARB h ); +GLhandleARB CompileShader( GLenum ShaderType, RString sFile, vector asDefines ); +GLhandleARB LoadShader( GLenum ShaderType, RString sFile, vector asDefines ); +void InitShaders(); +void SetupExtensions(); +void SetPixelMapForSurface( int glImageFormat, int glTexFormat, const RageSurfacePalette *palette ); + // // Globals // @@ -333,7 +340,7 @@ GLhandleARB CompileShader( GLenum ShaderType, RString sFile, vector asD GLhandleARB LoadShader( GLenum ShaderType, RString sFile, vector asDefines ) { // Don't do anything here if not the hardware/driver can't do it! - if (!GLEW_ARB_fragment_program && GLEW_ARB_shading_language_100 && ShaderType == GL_FRAGMENT_SHADER_ARB) + if (!GLEW_ARB_fragment_shader && ShaderType == GL_FRAGMENT_SHADER_ARB) return 0; if (!GLEW_ARB_vertex_shader && ShaderType == GL_VERTEX_SHADER_ARB) return 0; @@ -1655,7 +1662,7 @@ void RageDisplay_Legacy::SetTextureFiltering( TextureUnit tu, bool b ) void RageDisplay_Legacy::SetEffectMode( EffectMode effect ) { - if (!GLEW_ARB_fragment_program && !GLEW_ARB_shading_language_100) + if (!GLEW_ARB_fragment_shader) return; GLhandleARB hShader = 0; @@ -2561,7 +2568,7 @@ RString RageDisplay_Legacy::GetTextureDiagnostics(unsigned iTexture) const void RageDisplay_Legacy::SetAlphaTest(bool b) { // Previously this was 0.01, rather than 0x01. - glAlphaFunc(GL_GREATER, 0.00390625 /* 1/256 */); + glAlphaFunc(GL_GREATER, 0.00390625f /* 1/256 */); if (b) glEnable(GL_ALPHA_TEST); else @@ -2641,11 +2648,9 @@ void RageDisplay_Legacy::SetSphereEnvironmentMapping(TextureUnit tu, bool b) } } -GLint iCelTexture1, iCelTexture2 = 0; - void RageDisplay_Legacy::SetCelShaded( int stage ) { - if (!GLEW_ARB_fragment_program && !GL_ARB_shading_language_100) + if (!GLEW_ARB_fragment_shader) return; // not supported switch (stage) diff --git a/src/RageFileManager.cpp b/src/RageFileManager.cpp index 6219b6288c..b107a27a51 100644 --- a/src/RageFileManager.cpp +++ b/src/RageFileManager.cpp @@ -731,6 +731,42 @@ int RageFileManager::GetFileHash( const RString &sPath_ ) return iRet; } +RString RageFileManager::ResolvePath(const RString &path) +{ + RString tmpPath = path; + NormalizePath(tmpPath); + + RString resolvedPath = tmpPath; + + vector apDriverList; + ReferenceAllDrivers( apDriverList ); + + for( unsigned i = 0; i < apDriverList.size(); ++i ) + { + LoadedDriver *pDriver = apDriverList[i]; + const RString driverPath = pDriver->GetPath( tmpPath ); + + if ( driverPath.empty() || pDriver->m_sRoot.empty() ) + continue; + + if ( pDriver->m_sType != "dir" && pDriver->m_sType != "dirro" ) + continue; + + int iMountPointLen = pDriver->m_sMountPoint.length(); + if( tmpPath.substr(0, iMountPointLen) != pDriver->m_sMountPoint ) + continue; + + resolvedPath = pDriver->m_sRoot + "/" + RString(tmpPath.substr(iMountPointLen)); + break; + } + + UnreferenceAllDrivers( apDriverList ); + + NormalizePath( resolvedPath ); + + return resolvedPath; +} + static bool SortBySecond( const pair &a, const pair &b ) { return a.second < b.second; diff --git a/src/RageFileManager.h b/src/RageFileManager.h index 59767b7aa4..7eaa445852 100644 --- a/src/RageFileManager.h +++ b/src/RageFileManager.h @@ -10,6 +10,10 @@ namespace RageFileManagerUtil class RageFileDriver; class RageFileBasic; struct lua_State; + +bool ilt( const RString &a, const RString &b ); +bool ieq( const RString &a, const RString &b ); + /** @brief File utilities and high-level manager for RageFile objects. */ class RageFileManager { @@ -33,6 +37,12 @@ public: int GetFileSizeInBytes( const RString &sPath ); int GetFileHash( const RString &sPath ); + + /** + * @brief Get the absolte path from the VPS. + * @param path the VPS path. + * @return the absolute path. */ + RString ResolvePath(const RString &path); bool Mount( const RString &sType, const RString &sRealPath, const RString &sMountPoint, bool bAddToEnd = true ); void Mount( RageFileDriver *pDriver, const RString &sMountPoint, bool bAddToEnd = true ); diff --git a/src/RageLog.cpp b/src/RageLog.cpp index 5c517f209e..8e619766a8 100644 --- a/src/RageLog.cpp +++ b/src/RageLog.cpp @@ -262,7 +262,7 @@ void RageLog::Write( int where, const RString &sLine ) sStr.insert( 0, sWarning ); if( m_bShowLogOutput || (where&WRITE_TO_INFO) ) - puts( sStr ); + puts(sStr); //fputws( (const wchar_t *)sStr.c_str(), stdout ); if( where & WRITE_TO_INFO ) AddToInfo( sStr ); if( m_bLogToDisk && (where&WRITE_TO_INFO) && g_fileInfo->IsOpen() ) diff --git a/src/RageSoundReader_Extend.cpp b/src/RageSoundReader_Extend.cpp index 0c316c7a50..38beacfa35 100644 --- a/src/RageSoundReader_Extend.cpp +++ b/src/RageSoundReader_Extend.cpp @@ -15,6 +15,7 @@ RageSoundReader_Extend::RageSoundReader_Extend( RageSoundReader *pSource ): RageSoundReader_Filter( pSource ) { + ASSERT_M(pSource, "The music file was not found! Was it deleted or moved while the game was on?"); m_iPositionFrames = pSource->GetNextSourceFrame(); m_StopMode = M_STOP; diff --git a/src/RageSoundReader_MP3.cpp b/src/RageSoundReader_MP3.cpp index 048b20e508..cb7829c09f 100644 --- a/src/RageSoundReader_MP3.cpp +++ b/src/RageSoundReader_MP3.cpp @@ -26,7 +26,6 @@ enum tagtype { TAGTYPE_ID3V2_FOOTER }; -typedef unsigned long id3_length_t; static const int ID3_TAG_FLAG_FOOTERPRESENT = 0x10; static tagtype tagtype( const unsigned char *data, id3_length_t length ) diff --git a/src/RageSoundReader_MP3.h b/src/RageSoundReader_MP3.h index cc8862808a..815e8e7c27 100644 --- a/src/RageSoundReader_MP3.h +++ b/src/RageSoundReader_MP3.h @@ -8,6 +8,11 @@ struct madlib_t; +typedef unsigned long id3_length_t; + +signed long id3_tag_query( const unsigned char *data, id3_length_t length ); +void fill_frame_index_cache( madlib_t *mad ); + class RageSoundReader_MP3: public RageSoundReader_FileReader { public: diff --git a/src/RageSoundReader_Pan.cpp b/src/RageSoundReader_Pan.cpp index ee592c2fff..3b8d505154 100644 --- a/src/RageSoundReader_Pan.cpp +++ b/src/RageSoundReader_Pan.cpp @@ -5,7 +5,7 @@ RageSoundReader_Pan::RageSoundReader_Pan( RageSoundReader *pSource ): RageSoundReader_Filter( pSource ) { - m_fPan = 0.0; + m_fPan = 0; } diff --git a/src/RageSoundReader_WAV.h b/src/RageSoundReader_WAV.h index 20dcdeeaa2..53cf48d18d 100644 --- a/src/RageSoundReader_WAV.h +++ b/src/RageSoundReader_WAV.h @@ -7,6 +7,9 @@ #include "RageFile.h" struct WavReader; + +RString ReadString( RageFileBasic &f, int iSize, RString &sError ); + class RageSoundReader_WAV: public RageSoundReader_FileReader { public: diff --git a/src/RageTexture.cpp b/src/RageTexture.cpp index b049ba159d..0d9e17fd90 100644 --- a/src/RageTexture.cpp +++ b/src/RageTexture.cpp @@ -7,7 +7,7 @@ RageTexture::RageTexture( RageTextureID name ): - m_ID(name), m_iRefCount(1), m_bWasUsed(false), + m_iRefCount(1), m_bWasUsed(false), m_ID(name), m_iSourceWidth(0), m_iSourceHeight(0), m_iTextureWidth(0), m_iTextureHeight(0), m_iImageWidth(0), m_iImageHeight(0), diff --git a/src/RageThreads.cpp b/src/RageThreads.cpp index 5b86d22999..4d502a8a94 100644 --- a/src/RageThreads.cpp +++ b/src/RageThreads.cpp @@ -322,6 +322,17 @@ int RageThread::Wait() return ret; } +void RageThread::Halt(bool Kill) { + ASSERT( m_pSlot != NULL ); + ASSERT( m_pSlot->m_pImpl != NULL ); + m_pSlot->m_pImpl->Halt(Kill); +} + +void RageThread::Resume() { + ASSERT( m_pSlot != NULL ); + ASSERT( m_pSlot->m_pImpl != NULL ); + m_pSlot->m_pImpl->Resume(); +} void RageThread::HaltAllThreads( bool Kill ) { @@ -514,7 +525,7 @@ static set *g_FreeMutexIDs = NULL; #endif RageMutex::RageMutex( const RString &name ): - m_sName( name ), m_pMutex( MakeMutex (this ) ), + m_pMutex( MakeMutex (this ) ), m_sName(name), m_LockedBy(GetInvalidThreadId()), m_LockCnt(0) { @@ -721,7 +732,7 @@ bool RageEvent::WaitTimeoutSupported() const } RageSemaphore::RageSemaphore( RString sName, int iInitialValue ): - m_sName( sName ), m_pSema(MakeSemaphore( iInitialValue )) {} + m_pSema(MakeSemaphore( iInitialValue )), m_sName(sName) {} RageSemaphore::~RageSemaphore() { diff --git a/src/RageThreads.h b/src/RageThreads.h index 5f43ccc330..1fc7c7f49f 100644 --- a/src/RageThreads.h +++ b/src/RageThreads.h @@ -15,6 +15,9 @@ public: RString GetName() const { return m_sName; } void Create( int (*fn)(void *), void *data ); + void Halt( bool Kill=false); + void Resume(); + /* For crash handlers: kill or suspend all threads (except for * the running one) immediately. */ static void HaltAllThreads( bool Kill=false ); diff --git a/src/RageUtil.cpp b/src/RageUtil.cpp index 4f068df600..bcfadb1720 100644 --- a/src/RageUtil.cpp +++ b/src/RageUtil.cpp @@ -16,6 +16,10 @@ #include #include +bool HexToBinary(const RString&, RString&); +void utf8_sanitize(RString &); +void UnicodeUpperLower(wchar_t *, size_t, const unsigned char *); + RandomGen g_RandomNumberGenerator; MersenneTwister::MersenneTwister( int iSeed ) : m_iNext(0) @@ -88,7 +92,7 @@ int MersenneTwister::operator()() void fapproach( float& val, float other_val, float to_move ) { - ASSERT_M( to_move >= 0, ssprintf("to_move: %f", to_move) ); + ASSERT_M( to_move >= 0, ssprintf("to_move: %f < 0", to_move) ); if( val == other_val ) return; float fDelta = other_val - val; @@ -430,7 +434,7 @@ RString ConvertI64FormatString( const RString &sStr ) RString ConvertI64FormatString( const RString &sStr ) { return sStr; } #endif -/* ISO-639-1 codes: http://www.loc.gov/standards/iso639-2/langcodes.html +/* ISO-639-1 codes: http://www.loc.gov/standards/iso639-2/php/code_list.php * native forms: http://people.w3.org/rishida/names/languages.html * We don't use 3-letter codes, so we don't bother supporting them. */ static const LanguageInfo g_langs[] = @@ -1238,14 +1242,14 @@ bool GetFileContents( const RString &sPath, RString &sOut, bool bOneLine ) /* Don't warn if the file doesn't exist, but do warn if it exists and fails to open. */ if( !IsAFile(sPath) ) return false; - + RageFile file; if( !file.Open(sPath) ) { LOG->Warn( "GetFileContents(%s): %s", sPath.c_str(), file.GetError().c_str() ); return false; } - + RString sData; int iGot; if( bOneLine ) @@ -1261,7 +1265,7 @@ bool GetFileContents( const RString &sPath, RString &sOut, bool bOneLine ) if( bOneLine ) StripCrnl( sData ); - + sOut = sData; return true; } @@ -1727,6 +1731,13 @@ bool StringToFloat( const RString &sString, float &fOut ) return sString.size() && *endPtr == '\0' && isfinite( fOut ); } +RString FloatToString( const float &num ) +{ + stringstream ss; + ss << num; + return ss.str(); +} + const wchar_t INVALID_CHAR = 0xFFFD; /* U+FFFD REPLACEMENT CHARACTER */ wstring RStringToWstring( const RString &s ) diff --git a/src/RageUtil.h b/src/RageUtil.h index 17f4d24f0e..e3a83e576f 100644 --- a/src/RageUtil.h +++ b/src/RageUtil.h @@ -416,6 +416,7 @@ int StringToInt( const RString &sString ); * @return the string we are after. */ RString IntToString( const int &iNum ); float StringToFloat( const RString &sString ); +RString FloatToString( const float &num ); bool StringToFloat( const RString &sString, float &fOut ); RString WStringToRString( const wstring &sString ); diff --git a/src/ScoreDisplayNormal.cpp b/src/ScoreDisplayNormal.cpp index f34613a1d9..dad9eeed02 100644 --- a/src/ScoreDisplayNormal.cpp +++ b/src/ScoreDisplayNormal.cpp @@ -46,36 +46,6 @@ void ScoreDisplayNormal::SetScore( int iNewScore ) { float fScore = (float)iNewScore; - // TODO: Remove use of PlayerNumber. - PlayerNumber pn = m_pPlayerState->m_PlayerNumber; - - // Play some games to display the correct score -- the actual internal - // score does not change at all but the displayed one can (ie: displayed - // score for subtractive is MaxScore - score). - - int iMaxScore = STATSMAN->m_CurStageStats.m_player[pn].m_iMaxScore; - int iCurMaxScore = STATSMAN->m_CurStageStats.m_player[pn].m_iCurMaxScore; - - switch( m_pPlayerState->m_PlayerOptions.GetCurrent().m_ScoreDisplay ) - { - case PlayerOptions::SCORING_ADD: - // nothing to do - break; - case PlayerOptions::SCORING_SUBTRACT: - fScore = iMaxScore - ( iCurMaxScore - fScore ); - break; - case PlayerOptions::SCORING_AVERAGE: - if( iCurMaxScore == 0 ) // don't divide by zero fats - { - fScore = 0; - } - else - { - float fScoreRatio = fScore / (float)iCurMaxScore; - fScore = fScoreRatio * iMaxScore; - } - } - m_text.SetTargetNumber( fScore ); } diff --git a/src/ScoreKeeperNormal.cpp b/src/ScoreKeeperNormal.cpp index ce3874aa5a..695c640a28 100644 --- a/src/ScoreKeeperNormal.cpp +++ b/src/ScoreKeeperNormal.cpp @@ -120,6 +120,7 @@ void ScoreKeeperNormal::Load( * forced and not chosen by the user. */ NoteDataUtil::TransformNoteData( nd, aa, pSteps->m_StepsType, pSong ); RadarValues rvPre; + GAMESTATE->SetProcessedTimingData(&pSteps->m_Timing); NoteDataUtil::CalculateRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPre ); /* Apply user transforms to find out how the notes will really look. @@ -132,6 +133,7 @@ void ScoreKeeperNormal::Load( NoteDataUtil::TransformNoteData( nd, m_pPlayerState->m_PlayerOptions.GetStage(), pSteps->m_StepsType ); RadarValues rvPost; NoteDataUtil::CalculateRadarValues( nd, pSong->m_fMusicLengthSeconds, rvPost ); + GAMESTATE->SetProcessedTimingData(NULL); iTotalPossibleDancePoints += this->GetPossibleDancePoints( rvPre, rvPost ); iTotalPossibleGradePoints += this->GetPossibleGradePoints( rvPre, rvPost ); @@ -217,6 +219,8 @@ void ScoreKeeperNormal::OnNextSong( int iSongInCourseIndex, const Steps* pSteps, ASSERT( m_iMaxPossiblePoints >= 0 ); m_iMaxScoreSoFar += m_iMaxPossiblePoints; + GAMESTATE->SetProcessedTimingData(const_cast(&pSteps->m_Timing)); + m_iNumTapsAndHolds = pNoteData->GetNumRowsWithTapOrHoldHead() + pNoteData->GetNumHoldNotes() + pNoteData->GetNumRolls(); @@ -230,6 +234,8 @@ void ScoreKeeperNormal::OnNextSong( int iSongInCourseIndex, const Steps* pSteps, ASSERT( m_iPointBonus >= 0 ); m_iTapNotesHit = 0; + + GAMESTATE->SetProcessedTimingData(NULL); } static int GetScore(int p, int Z, int S, int n) @@ -410,18 +416,32 @@ void ScoreKeeperNormal::HandleTapScore( const TapNote &tn ) void ScoreKeeperNormal::HandleHoldCheckpointScore( const NoteData &nd, int iRow, int iNumHoldsHeldThisRow, int iNumHoldsMissedThisRow ) { - HandleTapNoteScoreInternal( iNumHoldsMissedThisRow == 0? TNS_CheckpointHit:TNS_CheckpointMiss, TNS_CheckpointHit ); + HandleTapNoteScoreInternal(iNumHoldsMissedThisRow == 0 ? TNS_CheckpointHit:TNS_CheckpointMiss, + TNS_CheckpointHit, iRow); HandleComboInternal( iNumHoldsHeldThisRow, 0, iNumHoldsMissedThisRow, iRow ); } -void ScoreKeeperNormal::HandleTapNoteScoreInternal( TapNoteScore tns, TapNoteScore maximum ) +void ScoreKeeperNormal::HandleTapNoteScoreInternal( TapNoteScore tns, TapNoteScore maximum, int row ) { // Update dance points. if( !m_pPlayerStageStats->m_bFailed ) m_pPlayerStageStats->m_iActualDancePoints += TapNoteScoreToDancePoints( tns ); - // update judged row totals - m_pPlayerStageStats->m_iTapNoteScores[tns] += 1; + // update judged row totals. Respect Combo segments here. + TimingData &td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; + ComboSegment *cs = td.GetComboSegmentAtRow(row); + if (tns == TNS_CheckpointHit || tns >= m_MinScoreToContinueCombo) + { + m_pPlayerStageStats->m_iTapNoteScores[tns] += cs->GetCombo(); + } + else if (tns == TNS_CheckpointMiss || tns < m_MinScoreToMaintainCombo) + { + m_pPlayerStageStats->m_iTapNoteScores[tns] += cs->GetMissCombo(); + } + else + { + m_pPlayerStageStats->m_iTapNoteScores[tns] += 1; + } // increment the current total possible dance score m_pPlayerStageStats->m_iCurPossibleDancePoints += TapNoteScoreToDancePoints( maximum ); @@ -441,17 +461,17 @@ void ScoreKeeperNormal::HandleComboInternal( int iNumHitContinueCombo, int iNumH { m_pPlayerStageStats->m_iCurMissCombo = 0; } - + TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; if( iNumBreakCombo == 0 ) { - TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; - int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).GetCombo() ); + int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow )->GetCombo() ); m_pPlayerStageStats->m_iCurCombo += iNumHitContinueCombo * multiplier; } else { m_pPlayerStageStats->m_iCurCombo = 0; - m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumBreakCombo ); + int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow(iRow)->GetMissCombo()); + m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumBreakCombo ) * multiplier; } } @@ -461,11 +481,11 @@ void ScoreKeeperNormal::HandleRowComboInternal( TapNoteScore tns, int iNumTapsIn { iNumTapsInRow = min( iNumTapsInRow, 1); } + TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; if ( tns >= m_MinScoreToContinueCombo ) { m_pPlayerStageStats->m_iCurMissCombo = 0; - TimingData td = GAMESTATE->m_pCurSteps[m_pPlayerState->m_PlayerNumber]->m_Timing; - int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow ).GetCombo() ); + int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow( iRow )->GetCombo() ); m_pPlayerStageStats->m_iCurCombo += iNumTapsInRow * multiplier; } else if ( tns < m_MinScoreToMaintainCombo ) @@ -473,7 +493,10 @@ void ScoreKeeperNormal::HandleRowComboInternal( TapNoteScore tns, int iNumTapsIn m_pPlayerStageStats->m_iCurCombo = 0; if( tns <= m_MaxScoreToIncrementMissCombo ) - m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumTapsInRow ); + { + int multiplier = ( iRow == -1 ? 1 : td.GetComboSegmentAtRow(iRow)->GetMissCombo()); + m_pPlayerStageStats->m_iCurMissCombo += ( m_MissComboIsPerRow ? 1 : iNumTapsInRow ) * multiplier; + } } } @@ -510,7 +533,7 @@ void ScoreKeeperNormal::HandleTapRowScore( const NoteData &nd, int iRow ) m_iNumNotesHitThisRow = iNumTapsInRow; TapNoteScore scoreOfLastTap = NoteDataWithScoring::LastTapNoteWithResult( nd, iRow ).result.tns; - HandleTapNoteScoreInternal( scoreOfLastTap, TNS_W1 ); + HandleTapNoteScoreInternal( scoreOfLastTap, TNS_W1, iRow ); if ( GAMESTATE->GetCurrentGame()->m_bCountNotesSeparately ) { diff --git a/src/ScoreKeeperNormal.h b/src/ScoreKeeperNormal.h index 9c9ab104bc..81a314a499 100644 --- a/src/ScoreKeeperNormal.h +++ b/src/ScoreKeeperNormal.h @@ -90,7 +90,12 @@ public: static int HoldNoteScoreToGradePoints( HoldNoteScore hns, bool bBeginner ); private: - void HandleTapNoteScoreInternal( TapNoteScore tns, TapNoteScore maximum ); + /** + * @brief Take care of some internal work with our scoring systems. + * @param tns the Tap Note score earned. + * @param maximum the best tap note score possible. + * @param row the row the score was earned. Mainly for ComboSegment stuff. */ + void HandleTapNoteScoreInternal( TapNoteScore tns, TapNoteScore maximum, int row ); void HandleComboInternal( int iNumHitContinueCombo, int iNumHitMaintainCombo, int iNumBreakCombo, int iRow = -1 ); void HandleRowComboInternal( TapNoteScore tns, int iNumTapsInRow, int iRow = -1 ); void GetRowCounts( const NoteData &nd, int iRow, int &iNumHitContinueCombo, int &iNumHitMaintainCombo, int &iNumBreakCombo ); diff --git a/src/ScoreKeeperShared.cpp b/src/ScoreKeeperShared.cpp index 95a28a8599..6686adf4f2 100644 --- a/src/ScoreKeeperShared.cpp +++ b/src/ScoreKeeperShared.cpp @@ -16,7 +16,7 @@ void ScoreKeeperShared::Load( const vector &apSteps, const vector &asModifiers ) { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::Load( apSongs, apSteps, asModifiers ); } @@ -24,63 +24,63 @@ void ScoreKeeperShared::Load( // These ScoreKeepers don't get to draw. void ScoreKeeperShared::DrawPrimitives() { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::DrawPrimitives(); } void ScoreKeeperShared::Update( float fDelta ) { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::Update( fDelta ); } void ScoreKeeperShared::OnNextSong( int iSongInCourseIndex, const Steps* pSteps, const NoteData* pNoteData ) { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::OnNextSong( iSongInCourseIndex, pSteps, pNoteData ); } void ScoreKeeperShared::HandleTapScore( const TapNote &tn ) { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::HandleTapScore( tn ); } void ScoreKeeperShared::HandleTapRowScore( const NoteData &nd, int iRow ) { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::HandleTapRowScore( nd, iRow ); } void ScoreKeeperShared::HandleHoldScore( const TapNote &tn ) { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::HandleHoldScore( tn ); } void ScoreKeeperShared::HandleHoldActiveSeconds( float fMusicSecondsHeld ) { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::HandleHoldActiveSeconds( fMusicSecondsHeld ); } void ScoreKeeperShared::HandleHoldCheckpointScore( const NoteData &nd, int iRow, int iNumHoldsHeldThisRow, int iNumHoldsMissedThisRow ) { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::HandleHoldCheckpointScore( nd, iRow, iNumHoldsHeldThisRow, iNumHoldsMissedThisRow ); } void ScoreKeeperShared::HandleTapScoreNone() { - if( m_pPlayerState->m_PlayerNumber != GAMESTATE->m_MasterPlayerNumber ) + if( m_pPlayerState->m_PlayerNumber != GAMESTATE->GetMasterPlayerNumber() ) return; ScoreKeeperNormal::HandleTapScoreNone(); } diff --git a/src/ScreenDebugOverlay.cpp b/src/ScreenDebugOverlay.cpp index b65b0efc7d..e6c731fa2c 100644 --- a/src/ScreenDebugOverlay.cpp +++ b/src/ScreenDebugOverlay.cpp @@ -196,8 +196,8 @@ void ScreenDebugOverlay::Init() g_Mappings.debugButton[i++] = DeviceInput(DEVICE_KEYBOARD, KEY_Cq); g_Mappings.debugButton[i++] = DeviceInput(DEVICE_KEYBOARD, KEY_Cw); g_Mappings.debugButton[i++] = DeviceInput(DEVICE_KEYBOARD, KEY_Ce); - g_Mappings.debugButton[i++] = DeviceInput(DEVICE_KEYBOARD, KEY_Ct); g_Mappings.debugButton[i++] = DeviceInput(DEVICE_KEYBOARD, KEY_Cr); + g_Mappings.debugButton[i++] = DeviceInput(DEVICE_KEYBOARD, KEY_Ct); g_Mappings.debugButton[i++] = DeviceInput(DEVICE_KEYBOARD, KEY_Cy); g_Mappings.debugButton[i++] = DeviceInput(DEVICE_KEYBOARD, KEY_Cu); g_Mappings.debugButton[i++] = DeviceInput(DEVICE_KEYBOARD, KEY_Ci); @@ -598,8 +598,8 @@ class DebugLineAutoplay : public IDebugLine virtual bool IsEnabled() { return GamePreferences::m_AutoPlay.Get() != PC_HUMAN; } virtual void DoAndLog( RString &sMessageOut ) { - ASSERT( GAMESTATE->m_MasterPlayerNumber != PLAYER_INVALID ); - PlayerController pc = GAMESTATE->m_pPlayerState[GAMESTATE->m_MasterPlayerNumber]->m_PlayerController; + ASSERT( GAMESTATE->GetMasterPlayerNumber() != PLAYER_INVALID ); + PlayerController pc = GAMESTATE->m_pPlayerState[GAMESTATE->GetMasterPlayerNumber()]->m_PlayerController; bool bHoldingShift = INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT) ) || INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT) ); @@ -639,7 +639,7 @@ class DebugLineAssist : public IDebugLine virtual bool IsEnabled() { return GAMESTATE->m_SongOptions.GetSong().m_bAssistClap || GAMESTATE->m_SongOptions.GetSong().m_bAssistMetronome; } virtual void DoAndLog( RString &sMessageOut ) { - ASSERT( GAMESTATE->m_MasterPlayerNumber != PLAYER_INVALID ); + ASSERT( GAMESTATE->GetMasterPlayerNumber() != PLAYER_INVALID ); bool bHoldingShift = INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT) ); bool b; if( bHoldingShift ) @@ -1226,10 +1226,10 @@ DECLARE_ONE( DebugLineWritePreferences ); DECLARE_ONE( DebugLineMenuTimer ); DECLARE_ONE( DebugLineFlushLog ); DECLARE_ONE( DebugLinePullBackCamera ); -DECLARE_ONE( DebugLineVolumeUp ); DECLARE_ONE( DebugLineVolumeDown ); -DECLARE_ONE( DebugLineVisualDelayUp ); +DECLARE_ONE( DebugLineVolumeUp ); DECLARE_ONE( DebugLineVisualDelayDown ); +DECLARE_ONE( DebugLineVisualDelayUp ); DECLARE_ONE( DebugLineForceCrash ); DECLARE_ONE( DebugLineUptime ); diff --git a/src/ScreenDebugOverlay.h b/src/ScreenDebugOverlay.h index 0dc03f3c1a..bd06795c84 100644 --- a/src/ScreenDebugOverlay.h +++ b/src/ScreenDebugOverlay.h @@ -7,6 +7,9 @@ #include "BitmapText.h" #include "Quad.h" +void ChangeVolume( float fDelta ); +void ChangeVisualDelay( float fDelta ); + class ScreenDebugOverlay : public Screen { public: diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index 5928323256..0f88bf0985 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -41,7 +41,7 @@ static Preference g_iDefaultRecordLength( "DefaultRecordLength", 4 ); static Preference g_bEditorShowBGChangesPlay( "EditorShowBGChangesPlay", true ); -// Defines specific to ScreenEdit +/** @brief How long must the button be held to generate a hold in record mode? */ const float RECORD_HOLD_SECONDS = 0.3f; #define PLAYER_X (SCREEN_CENTER_X) @@ -61,12 +61,16 @@ const float RECORD_HOLD_SECONDS = 0.3f; AutoScreenMessage( SM_UpdateTextInfo ); AutoScreenMessage( SM_BackFromMainMenu ); AutoScreenMessage( SM_BackFromAreaMenu ); +AutoScreenMessage( SM_BackFromAlterMenu ); AutoScreenMessage( SM_BackFromStepsInformation ); +AutoScreenMessage( SM_BackFromStepsData ); AutoScreenMessage( SM_BackFromOptions ); AutoScreenMessage( SM_BackFromSongInformation ); AutoScreenMessage( SM_BackFromBGChange ); AutoScreenMessage( SM_BackFromInsertTapAttack ); AutoScreenMessage( SM_BackFromInsertTapAttackPlayerOptions ); +AutoScreenMessage( SM_BackFromInsertStepAttack ); +AutoScreenMessage( SM_BackFromInsertStepAttackPlayerOptions ); AutoScreenMessage( SM_BackFromInsertCourseAttack ); AutoScreenMessage( SM_BackFromInsertCourseAttackPlayerOptions ); AutoScreenMessage( SM_BackFromCourseModeMenu ); @@ -127,18 +131,29 @@ void ScreenEdit::InitEditMappings() m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_UP_PAGE][1] = DeviceInput(DEVICE_KEYBOARD, KEY_SEMICOLON); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_DOWN_PAGE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PGDN); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_DOWN_PAGE][1] = DeviceInput(DEVICE_KEYBOARD, KEY_SQUOTE); + + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SCROLL_UP_TS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SCROLL_UP_TS][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_UP_TS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PGUP); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_UP_TS][1] = DeviceInput(DEVICE_KEYBOARD, KEY_SEMICOLON); + + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SCROLL_DOWN_TS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SCROLL_DOWN_TS][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_DOWN_TS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PGDN); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_DOWN_TS][1] = DeviceInput(DEVICE_KEYBOARD, KEY_SQUOTE); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_HOME][0] = DeviceInput(DEVICE_KEYBOARD, KEY_HOME); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_END][0] = DeviceInput(DEVICE_KEYBOARD, KEY_END); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PERIOD); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_COMMA); - m_EditMappingsDeviceInput.button[EDIT_BUTTON_LABEL_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PERIOD); - m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); - m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_NEXT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SEGMENT_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PERIOD); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SEGMENT_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SEGMENT_NEXT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); - m_EditMappingsDeviceInput.button[EDIT_BUTTON_LABEL_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_COMMA); - m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); - m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_PREV][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SEGMENT_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_COMMA); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SEGMENT_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SEGMENT_PREV][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_SELECT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_SELECT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT); @@ -170,6 +185,7 @@ void ScreenEdit::InitEditMappings() m_EditMappingsMenuButton.button [EDIT_BUTTON_OPEN_EDIT_MENU][0] = GAME_BUTTON_START; m_EditMappingsMenuButton.button [EDIT_BUTTON_OPEN_EDIT_MENU][1] = GAME_BUTTON_BACK; + // Escape, Enter = exit play/record m_PlayMappingsDeviceInput.button [EDIT_BUTTON_RETURN_TO_EDIT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ENTER); m_PlayMappingsDeviceInput.button [EDIT_BUTTON_RETURN_TO_EDIT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_ESC); @@ -231,8 +247,8 @@ void ScreenEdit::InitEditMappings() m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cb); m_EditMappingsDeviceInput.hold[EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT); m_EditMappingsDeviceInput.hold[EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT); - m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_COURSE_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cc); - m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cv); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_ADD_STEP_MODS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cc); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_STEP_ATTACK_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cv); m_EditMappingsDeviceInput.button[EDIT_BUTTON_INSERT_SHIFT_PAUSES][0] = DeviceInput(DEVICE_KEYBOARD, KEY_INSERT); m_EditMappingsDeviceInput.hold[EDIT_BUTTON_INSERT_SHIFT_PAUSES][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); @@ -263,6 +279,14 @@ void ScreenEdit::InitEditMappings() m_EditMappingsDeviceInput.button[EDIT_BUTTON_CYCLE_TAP_LEFT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cn); m_EditMappingsDeviceInput.button[EDIT_BUTTON_CYCLE_TAP_RIGHT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cm); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_CYCLE_SEGMENT_LEFT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cn); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_CYCLE_SEGMENT_LEFT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_CYCLE_SEGMENT_LEFT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); + + m_EditMappingsDeviceInput.button[EDIT_BUTTON_CYCLE_SEGMENT_RIGHT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cm); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_CYCLE_SEGMENT_RIGHT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); + m_EditMappingsDeviceInput.hold[EDIT_BUTTON_CYCLE_SEGMENT_RIGHT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); + m_EditMappingsDeviceInput.button [EDIT_BUTTON_SCROLL_SPEED_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_UP); m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SCROLL_SPEED_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL); m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SCROLL_SPEED_UP][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL); @@ -281,6 +305,7 @@ void ScreenEdit::InitEditMappings() m_EditMappingsMenuButton.button[EDIT_BUTTON_OPEN_EDIT_MENU][0] = GAME_BUTTON_START; m_EditMappingsMenuButton.button[EDIT_BUTTON_OPEN_EDIT_MENU][1] = GAME_BUTTON_BACK; m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_AREA_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ENTER); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_ALTER_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Ca); m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_INPUT_HELP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_F1); m_EditMappingsDeviceInput.button[EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cb); @@ -320,8 +345,10 @@ void ScreenEdit::InitEditMappings() // Allow song and step timing to be swapped. m_EditMappingsDeviceInput.button[EDIT_BUTTON_SWITCH_TIMINGS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Ct); - m_PlayMappingsDeviceInput.button[EDIT_BUTTON_RETURN_TO_EDIT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ESC); - m_PlayMappingsMenuButton.button[EDIT_BUTTON_RETURN_TO_EDIT][1] = GAME_BUTTON_BACK; + m_PlayMappingsDeviceInput.button[EDIT_BUTTON_RETURN_TO_EDIT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_ENTER); + m_PlayMappingsDeviceInput.button[EDIT_BUTTON_RETURN_TO_EDIT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_ESC); + m_PlayMappingsMenuButton.button[EDIT_BUTTON_RETURN_TO_EDIT][0] = GAME_BUTTON_BACK; + m_PlayMappingsMenuButton.button[EDIT_BUTTON_RETURN_TO_EDIT][1] = GAME_BUTTON_START; m_RecordMappingsDeviceInput.button[EDIT_BUTTON_LAY_ROLL][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT); m_RecordMappingsDeviceInput.button[EDIT_BUTTON_LAY_ROLL][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT); @@ -496,58 +523,114 @@ static MenuDef g_MainMenu( MenuRowDef( ScreenEdit::play_selection, "Play selection", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::set_selection_start, "Set selection start", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::set_selection_end, "Set selection end", true, EditMode_Practice, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::edit_steps_information, "Edit steps information", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::revert_to_last_save, "Revert to last save", true, EditMode_Home, true, true, 0, NULL ), MenuRowDef( ScreenEdit::revert_from_disk, "Revert from disk", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::options, "Editor options", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::edit_song_info, "Edit song info", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::edit_steps_information, "Edit steps information", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::edit_timing_data, "Edit Timing Data", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::view_steps_data, "View steps data", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::play_preview_music, "Play preview music", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::exit, "Exit Edit Mode", true, EditMode_Practice, true, true, 0, NULL ) ); +static MenuDef g_AlterMenu( + "ScreenMiniMenuAlterMenu", + MenuRowDef(ScreenEdit::cut, "Cut", true, + EditMode_Practice, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::copy, "Copy", true, + EditMode_Practice, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::clear, "Clear area", true, + EditMode_Practice, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::quantize, "Quantize", true, + EditMode_Practice, true, true, 0, + "4th","8th","12th","16th","24th","32nd","48th","64th","192nd"), + MenuRowDef(ScreenEdit::turn, "Turn", true, + EditMode_Practice, true, true, 0, "Left","Right","Mirror","Shuffle","SuperShuffle" ), + MenuRowDef(ScreenEdit::transform, "Transform", true, + EditMode_Practice, true, true, 0, "NoHolds","NoMines","Little","Wide", + "Big","Quick","Skippy","Mines","Echo","Stomp","Planted","Floored", + "Twister","NoJumps","NoHands","NoQuads","NoStretch" ), + MenuRowDef(ScreenEdit::alter, "Alter", true, + EditMode_Practice, true, true, 0, "Autogen To Fill Width","Backwards","Swap Sides", + "Copy Left To Right","Copy Right To Left","Clear Left","Clear Right", + "Collapse To One","Collapse Left","Shift Left","Shift Right" ), + MenuRowDef(ScreenEdit::tempo, "Tempo", true, + EditMode_Full, true, true, 0, "Compress 2x","Compress 3->2", + "Compress 4->3","Expand 3->4","Expand 2->3","Expand 2x" ), + MenuRowDef(ScreenEdit::play, "Play selection", true, + EditMode_Practice, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::record, "Record in selection", true, + EditMode_Practice, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::preview_designation, "Designate as Music Preview", true, + EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::convert_to_pause, "Convert selection to pause", true, + EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::convert_to_delay, "Convert selection to delay", true, + EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::convert_to_warp, "Convert selection to warp", true, + EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::convert_to_fake, "Convert selection to fake", true, + EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::convert_to_attack, "Convert selection to attack", true, + EditMode_Full, true, true, 0, NULL), + MenuRowDef(ScreenEdit::routine_invert_notes, "Invert notes' player", true, + EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::routine_mirror_1_to_2, "Mirror Player 1 to 2", true, + EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::routine_mirror_2_to_1, "Mirror Player 2 to 1", true, + EditMode_Full, true, true, 0, NULL ) +); + static MenuDef g_AreaMenu( "ScreenMiniMenuAreaMenu", - MenuRowDef( ScreenEdit::cut, "Cut", true, EditMode_Practice, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::copy, "Copy", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::paste_at_current_beat, "Paste at current beat", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::paste_at_begin_marker, "Paste at begin marker", true, EditMode_Practice, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::clear, "Clear area", true, EditMode_Practice, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::quantize, "Quantize", true, EditMode_Practice, true, true, 0, "4th","8th","12th","16th","24th","32nd","48th","64th","192nd"), - MenuRowDef( ScreenEdit::turn, "Turn", true, EditMode_Practice, true, true, 0, "Left","Right","Mirror","Shuffle","SuperShuffle" ), - MenuRowDef( ScreenEdit::transform, "Transform", true, EditMode_Practice, true, true, 0, "NoHolds","NoMines","Little","Wide","Big","Quick","Skippy","Mines","Echo","Stomp","Planted","Floored","Twister","NoJumps","NoHands","NoQuads","NoStretch" ), - MenuRowDef( ScreenEdit::alter, "Alter", true, EditMode_Practice, true, true, 0, "Autogen To Fill Width","Backwards","Swap Sides","Copy Left To Right","Copy Right To Left","Clear Left","Clear Right","Collapse To One","Collapse Left","Shift Left","Shift Right" ), - MenuRowDef( ScreenEdit::tempo, "Tempo", true, EditMode_Full, true, true, 0, "Compress 2x","Compress 3->2","Compress 4->3","Expand 3->4","Expand 2->3","Expand 2x" ), - MenuRowDef( ScreenEdit::play, "Play selection", true, EditMode_Practice, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::record, "Record in selection", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::insert_and_shift, "Insert beat and shift down", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::delete_and_shift, "Delete beat and shift up", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::shift_pauses_forward, "Shift all timing changes down", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::shift_pauses_backward, "Shift all timing changes up", true, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::convert_to_pause, "Convert selection to pause", true, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::convert_pause_to_beat, "Convert pause to beats", true, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::undo, "Undo", true, EditMode_Practice, true, true, 0, NULL ) + MenuRowDef(ScreenEdit::convert_pause_to_beat, "Convert pause to beats", true, + EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::convert_delay_to_beat, "Convert delay to beats", true, + EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::last_second_at_beat, "Designate last second at current beat", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::undo, "Undo", true, EditMode_Practice, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::clear_clipboard, "Clear clipboard", true, + EditMode_Practice, true, true, 0, NULL ) + ); static MenuDef g_StepsInformation( "ScreenMiniMenuStepsInformation", MenuRowDef( ScreenEdit::difficulty, "Difficulty", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::meter, "Meter", true, EditMode_Practice, true, false, 0, NULL ), + MenuRowDef( ScreenEdit::predict_meter, "Predicted Meter", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::chartname, "Chart Name", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::description, "Description", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::chartstyle, "Chart Style", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::step_credit, "Step Author", true, EditMode_Practice, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::predict_meter, "Predicted Meter", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::tap_notes, "Tap Steps", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::jumps, "Jumps", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::hands, "Hands", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::quads, "Quads", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::holds, "Holds", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::mines, "Mines", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::stream, "Stream", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::voltage, "Voltage", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::air, "Air", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::freeze, "Freeze", false, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::chaos, "Chaos", false, EditMode_Full, true, true, 0, NULL ) + MenuRowDef( ScreenEdit::step_display_bpm, "Display BPM", true, EditMode_Full, true, true, 0, "Actual", "Specified", "Random" ), + MenuRowDef( ScreenEdit::step_min_bpm, "Min BPM", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::step_max_bpm, "Max BPM", true, EditMode_Full, true, true, 0, NULL ) +); + +static MenuDef g_StepsData( + "ScreenMiniMenuStepsData", + MenuRowDef( ScreenEdit::tap_notes, "Tap Steps", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::jumps, "Jumps", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::hands, "Hands", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::quads, "Quads", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::holds, "Holds", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::mines, "Mines", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::rolls, "Rolls", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::lifts, "Lifts", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::fakes, "Fakes", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::stream, "Stream", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::voltage, "Voltage", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::air, "Air", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::freeze, "Freeze", false, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::chaos, "Chaos", false, EditMode_Full, true, true, 0, NULL ) ); static MenuDef g_SongInformation( @@ -560,7 +643,7 @@ static MenuDef g_SongInformation( MenuRowDef( ScreenEdit::main_title_transliteration, "Main title transliteration", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::sub_title_transliteration, "Sub title transliteration", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::artist_transliteration, "Artist transliteration", true, EditMode_Practice, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::last_beat_hint, "Last beat hint", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::last_second_hint, "Last second hint", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::preview_start, "Preview Start", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::preview_length, "Preview Length", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::display_bpm, "Display BPM", true, EditMode_Full, true, true, 0, "Actual", "Specified", "Random" ), @@ -585,6 +668,8 @@ static MenuDef g_TimingDataInformation( MenuRowDef( ScreenEdit::speed_mode, "Edit speed (mode)", true, EditMode_Full, true, true, 0, "Beats", "Seconds" ), MenuRowDef( ScreenEdit::scroll, "Edit scrolling factor", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::fake, "Edit fake", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::copy_timing, "Copy timing data", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::paste_timing, "Paste timing data", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::erase_step_timing, "Erase step timing", true, EditMode_Full, true, true, 0, NULL ) ); @@ -673,6 +758,11 @@ static MenuDef g_InsertCourseAttack( MenuRowDef( ScreenEdit::remove, "Remove", true, EditMode_Practice, true, true, 0, "Press Start" ) ); +static MenuDef g_InsertStepAttack("ScreenMiniMenuInsertCourseAttack", + MenuRowDef( ScreenEdit::sa_duration, "Duration seconds", true, EditMode_Practice, true, false, 3, "5","10","15","20","25","30","35","40","45" ), + MenuRowDef( ScreenEdit::sa_set_mods, "Set modifiers", true, EditMode_Practice, true, true, 0, "Press Start" ), + MenuRowDef( ScreenEdit::sa_remove, "Remove", true, EditMode_Practice, true, true, 0, "Press Start" )); + static MenuDef g_CourseMode( "ScreenMiniMenuCourseDisplay", MenuRowDef( -1, "Play mods from course", true, EditMode_Practice, true, false, 0, NULL ) @@ -722,6 +812,8 @@ void ScreenEdit::Init() ScreenWithMenuElements::Init(); InitEditMappings(); + + currentCycleSegment = SEGMENT_LABEL; // save the originals for reverting later CopyToLastSave(); @@ -793,6 +885,8 @@ void ScreenEdit::Init() PO_GROUP_ASSIGN( m_PlayerStateEdit.m_PlayerOptions, ModsLevel_Stage, m_sNoteSkin, GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.GetStage().m_sNoteSkin ); } m_PlayerStateEdit.m_PlayerOptions.FromString( ModsLevel_Stage, EDIT_MODIFIERS ); + + this->originalPlayerOptions.FromString(ModsLevel_Stage, EDIT_MODIFIERS); m_pSteps->GetNoteData( m_NoteDataEdit ); m_NoteFieldEdit.SetXY( EDIT_X, EDIT_Y ); @@ -813,6 +907,8 @@ void ScreenEdit::Init() m_bRemoveNoteButtonDown = false; m_Clipboard.SetNumTracks( m_NoteDataEdit.GetNumTracks() ); + + clipboardTiming = GAMESTATE->m_pCurSong->m_SongTiming; // always have a backup. m_bHasUndo = false; m_Undo.SetNumTracks( m_NoteDataEdit.GetNumTracks() ); @@ -1048,11 +1144,14 @@ static LocalizedString NOTES("ScreenEdit", "%s notes"); static LocalizedString SELECTION_BEAT("ScreenEdit", "Selection beat"); static LocalizedString DIFFICULTY("ScreenEdit", "Difficulty"); static LocalizedString ROUTINE_PLAYER("ScreenEdit", "Routine Player"); +static LocalizedString CHART_NAME("ScreenEdit", "Chart Name"); static LocalizedString DESCRIPTION("ScreenEdit", "Description"); static LocalizedString CHART_STYLE("ScreenEdit", "Chart Style"); +static LocalizedString STEP_AUTHOR("ScreenEdit", "Step Author"); static LocalizedString MAIN_TITLE("ScreenEdit", "Main title"); static LocalizedString SUBTITLE("ScreenEdit", "Subtitle"); static LocalizedString TAP_NOTE_TYPE("ScreenEdit", "Tap Note"); +static LocalizedString SEGMENT_TYPE("ScreenEdit", "Segment"); static LocalizedString TAP_STEPS("ScreenEdit", "Tap Steps"); static LocalizedString JUMPS("ScreenEdit", "Jumps"); static LocalizedString HANDS("ScreenEdit", "Hands"); @@ -1076,11 +1175,14 @@ static ThemeMetric SELECTION_BEAT_UNFINISHED_FORMAT("ScreenEdit", "Sele static ThemeMetric SELECTION_BEAT_END_FORMAT("ScreenEdit", "SelectionBeatEndFormat"); static ThemeMetric DIFFICULTY_FORMAT("ScreenEdit", "DifficultyFormat"); static ThemeMetric ROUTINE_PLAYER_FORMAT("ScreenEdit", "RoutinePlayerFormat"); +static ThemeMetric CHART_NAME_FORMAT("ScreenEdit", "ChartNameFormat"); static ThemeMetric DESCRIPTION_FORMAT("ScreenEdit", "DescriptionFormat"); static ThemeMetric CHART_STYLE_FORMAT("ScreenEdit", "ChartStyleFormat"); +static ThemeMetric STEP_AUTHOR_FORMAT("ScreenEdit", "StepAuthorFormat"); static ThemeMetric MAIN_TITLE_FORMAT("ScreenEdit", "MainTitleFormat"); static ThemeMetric SUBTITLE_FORMAT("ScreenEdit", "SubtitleFormat"); static ThemeMetric TAP_NOTE_TYPE_FORMAT("ScreenEdit", "TapNoteTypeFormat"); +static ThemeMetric SEGMENT_TYPE_FORMAT("ScreenEdit", "SegmentTypeFormat"); static ThemeMetric NUM_STEPS_FORMAT("ScreenEdit", "NumStepsFormat"); static ThemeMetric NUM_JUMPS_FORMAT("ScreenEdit", "NumJumpsFormat"); static ThemeMetric NUM_HOLDS_FORMAT("ScreenEdit", "NumHoldsFormat"); @@ -1089,6 +1191,14 @@ static ThemeMetric NUM_HANDS_FORMAT("ScreenEdit", "NumHandsFormat"); static ThemeMetric NUM_ROLLS_FORMAT("ScreenEdit", "NumRollsFormat"); static ThemeMetric NUM_LIFTS_FORMAT("ScreenEdit", "NumLiftsFormat"); static ThemeMetric NUM_FAKES_FORMAT("ScreenEdit", "NumFakesFormat"); +static ThemeMetric NUM_STEPS_FORMAT_TWO_PLAYER("ScreenEdit", "NumStepsFormatTwoPlayer"); +static ThemeMetric NUM_JUMPS_FORMAT_TWO_PLAYER("ScreenEdit", "NumJumpsFormatTwoPlayer"); +static ThemeMetric NUM_HOLDS_FORMAT_TWO_PLAYER("ScreenEdit", "NumHoldsFormatTwoPlayer"); +static ThemeMetric NUM_MINES_FORMAT_TWO_PLAYER("ScreenEdit", "NumMinesFormatTwoPlayer"); +static ThemeMetric NUM_HANDS_FORMAT_TWO_PLAYER("ScreenEdit", "NumHandsFormatTwoPlayer"); +static ThemeMetric NUM_ROLLS_FORMAT_TWO_PLAYER("ScreenEdit", "NumRollsFormatTwoPlayer"); +static ThemeMetric NUM_LIFTS_FORMAT_TWO_PLAYER("ScreenEdit", "NumLiftsFormatTwoPlayer"); +static ThemeMetric NUM_FAKES_FORMAT_TWO_PLAYER("ScreenEdit", "NumFakesFormatTwoPlayer"); static ThemeMetric TIMING_MODE_FORMAT("ScreenEdit", "TimingModeFormat"); static ThemeMetric BEAT_0_OFFSET_FORMAT("ScreenEdit", "Beat0OffsetFormat"); static ThemeMetric PREVIEW_START_FORMAT("ScreenEdit", "PreviewStartFormat"); @@ -1145,22 +1255,66 @@ void ScreenEdit::UpdateTextInfo() sText += ssprintf( DIFFICULTY_FORMAT.GetValue(), DIFFICULTY.GetValue().c_str(), DifficultyToString( m_pSteps->GetDifficulty() ).c_str() ); if ( m_InputPlayerNumber != PLAYER_INVALID ) sText += ssprintf( ROUTINE_PLAYER_FORMAT.GetValue(), ROUTINE_PLAYER.GetValue().c_str(), m_InputPlayerNumber + 1 ); - sText += ssprintf( DESCRIPTION_FORMAT.GetValue(), DESCRIPTION.GetValue().c_str(), m_pSteps->GetDescription().c_str() ); - sText += ssprintf( CHART_STYLE_FORMAT.GetValue(), CHART_STYLE.GetValue().c_str(), m_pSteps->GetChartStyle().c_str() ); + //sText += ssprintf( DESCRIPTION_FORMAT.GetValue(), DESCRIPTION.GetValue().c_str(), m_pSteps->GetDescription().c_str() ); + sText += ssprintf( CHART_NAME_FORMAT.GetValue(), CHART_NAME.GetValue().c_str(), m_pSteps->GetChartName().c_str() ); + sText += ssprintf( STEP_AUTHOR_FORMAT.GetValue(), STEP_AUTHOR.GetValue().c_str(), m_pSteps->GetCredit().c_str() ); + //sText += ssprintf( CHART_STYLE_FORMAT.GetValue(), CHART_STYLE.GetValue().c_str(), m_pSteps->GetChartStyle().c_str() ); sText += ssprintf( MAIN_TITLE_FORMAT.GetValue(), MAIN_TITLE.GetValue().c_str(), m_pSong->m_sMainTitle.c_str() ); if( m_pSong->m_sSubTitle.size() ) sText += ssprintf( SUBTITLE_FORMAT.GetValue(), SUBTITLE.GetValue().c_str(), m_pSong->m_sSubTitle.c_str() ); + sText += ssprintf( SEGMENT_TYPE_FORMAT.GetValue(), SEGMENT_TYPE.GetValue().c_str(), TimingSegmentTypeToString(currentCycleSegment).c_str() ); sText += ssprintf( TAP_NOTE_TYPE_FORMAT.GetValue(), TAP_NOTE_TYPE.GetValue().c_str(), TapNoteTypeToString( m_selectedTap.type ).c_str() ); - break; + break; + } + + GAMESTATE->SetProcessedTimingData(&m_pSteps->m_Timing); + const StepsTypeCategory &cat = GAMEMAN->GetStepsTypeInfo(m_pSteps->m_StepsType).m_StepsTypeCategory; + if (cat == StepsTypeCategory_Couple || cat == StepsTypeCategory_Routine) + { + pair tmp = m_NoteDataEdit.GetNumTapNotesTwoPlayer(); + sText += ssprintf(NUM_STEPS_FORMAT_TWO_PLAYER.GetValue(), + TAP_STEPS.GetValue().c_str(), + tmp.first, tmp.second); + tmp = m_NoteDataEdit.GetNumJumpsTwoPlayer(); + sText += ssprintf(NUM_JUMPS_FORMAT_TWO_PLAYER.GetValue(), + JUMPS.GetValue().c_str(), + tmp.first, tmp.second); + tmp = m_NoteDataEdit.GetNumHandsTwoPlayer(); + sText += ssprintf(NUM_HANDS_FORMAT_TWO_PLAYER.GetValue(), + HANDS.GetValue().c_str(), + tmp.first, tmp.second); + tmp = m_NoteDataEdit.GetNumHoldNotesTwoPlayer(); + sText += ssprintf(NUM_HOLDS_FORMAT_TWO_PLAYER.GetValue(), + HOLDS.GetValue().c_str(), + tmp.first, tmp.second); + tmp = m_NoteDataEdit.GetNumMinesTwoPlayer(); + sText += ssprintf(NUM_MINES_FORMAT_TWO_PLAYER.GetValue(), + MINES.GetValue().c_str(), + tmp.first, tmp.second); + tmp = m_NoteDataEdit.GetNumRollsTwoPlayer(); + sText += ssprintf(NUM_ROLLS_FORMAT_TWO_PLAYER.GetValue(), + ROLLS.GetValue().c_str(), + tmp.first, tmp.second); + tmp = m_NoteDataEdit.GetNumLiftsTwoPlayer(); + sText += ssprintf(NUM_LIFTS_FORMAT_TWO_PLAYER.GetValue(), + LIFTS.GetValue().c_str(), + tmp.first, tmp.second); + tmp = m_NoteDataEdit.GetNumFakesTwoPlayer(); + sText += ssprintf(NUM_FAKES_FORMAT_TWO_PLAYER.GetValue(), + FAKES.GetValue().c_str(), + tmp.first, tmp.second); + } + else + { + sText += ssprintf( NUM_STEPS_FORMAT.GetValue(), TAP_STEPS.GetValue().c_str(), m_NoteDataEdit.GetNumTapNotes() ); + sText += ssprintf( NUM_JUMPS_FORMAT.GetValue(), JUMPS.GetValue().c_str(), m_NoteDataEdit.GetNumJumps() ); + sText += ssprintf( NUM_HANDS_FORMAT.GetValue(), HANDS.GetValue().c_str(), m_NoteDataEdit.GetNumHands() ); + sText += ssprintf( NUM_HOLDS_FORMAT.GetValue(), HOLDS.GetValue().c_str(), m_NoteDataEdit.GetNumHoldNotes() ); + sText += ssprintf( NUM_MINES_FORMAT.GetValue(), MINES.GetValue().c_str(), m_NoteDataEdit.GetNumMines() ); + sText += ssprintf( NUM_ROLLS_FORMAT.GetValue(), ROLLS.GetValue().c_str(), m_NoteDataEdit.GetNumRolls() ); + sText += ssprintf( NUM_LIFTS_FORMAT.GetValue(), LIFTS.GetValue().c_str(), m_NoteDataEdit.GetNumLifts() ); + sText += ssprintf( NUM_FAKES_FORMAT.GetValue(), FAKES.GetValue().c_str(), m_NoteDataEdit.GetNumFakes() ); } - sText += ssprintf( NUM_STEPS_FORMAT.GetValue(), TAP_STEPS.GetValue().c_str(), m_NoteDataEdit.GetNumTapNotes() ); - sText += ssprintf( NUM_JUMPS_FORMAT.GetValue(), JUMPS.GetValue().c_str(), m_NoteDataEdit.GetNumJumps() ); - sText += ssprintf( NUM_HANDS_FORMAT.GetValue(), HANDS.GetValue().c_str(), m_NoteDataEdit.GetNumHands() ); - sText += ssprintf( NUM_HOLDS_FORMAT.GetValue(), HOLDS.GetValue().c_str(), m_NoteDataEdit.GetNumHoldNotes() ); - sText += ssprintf( NUM_MINES_FORMAT.GetValue(), MINES.GetValue().c_str(), m_NoteDataEdit.GetNumMines() ); - sText += ssprintf( NUM_ROLLS_FORMAT.GetValue(), ROLLS.GetValue().c_str(), m_NoteDataEdit.GetNumRolls() ); - sText += ssprintf( NUM_LIFTS_FORMAT.GetValue(), LIFTS.GetValue().c_str(), m_NoteDataEdit.GetNumLifts() ); - sText += ssprintf( NUM_FAKES_FORMAT.GetValue(), FAKES.GetValue().c_str(), m_NoteDataEdit.GetNumFakes() ); switch( EDIT_MODE.GetValue() ) { DEFAULT_FAIL( EDIT_MODE.GetValue() ); @@ -1183,6 +1337,8 @@ void ScreenEdit::UpdateTextInfo() } m_textInfo.SetText( sText ); + + GAMESTATE->SetProcessedTimingData(NULL); } void ScreenEdit::DrawPrimitives() @@ -1295,7 +1451,7 @@ static int FindAttackAtTime( const AttackArray& attacks, float fStartTime ) } static LocalizedString BG_CHANGE_STEP_TIMING ( "ScreenEdit", "You must be in Song Timing Mode to edit BG Changes." ); - +static LocalizedString ALTER_MENU_NO_SELECTION ( "ScreenEdit", "You must have an area selected to enter the Alter Menu." ); static LocalizedString SWITCHED_TO ( "ScreenEdit", "Switched to" ); static LocalizedString NO_BACKGROUNDS_AVAILABLE ( "ScreenEdit", "No backgrounds available" ); static ThemeMetric INVERT_SCROLL_BUTTONS ( "ScreenEdit", "InvertScrollSpeedButtons" ); @@ -1308,9 +1464,9 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) m_iShiftAnchor = -1; return; } - TimingData &sTiming = GAMESTATE->m_pCurSong->m_SongTiming; + TimingData &sTiming = GetAppropriateTiming(); float playerBeat = GetAppropriatePosition().m_fSongBeat; - int beatsPerMeasure = sTiming.GetTimeSignatureSegmentAtBeat( playerBeat ).GetNum(); + int beatsPerMeasure = sTiming.GetTimeSignatureSegmentAtBeat( playerBeat )->GetNum(); switch( EditB ) { @@ -1402,6 +1558,17 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) } break; } + case EDIT_BUTTON_CYCLE_SEGMENT_LEFT: + { + int tmp = enum_add2( this->currentCycleSegment, -1 ); + wrap( *ConvertValue(&tmp), NUM_TimingSegmentType ); + break; + } + case EDIT_BUTTON_CYCLE_SEGMENT_RIGHT: + { + int tmp = enum_add2( this->currentCycleSegment, +1 ); + wrap( *ConvertValue(&tmp), NUM_TimingSegmentType ); + break; } case EDIT_BUTTON_SCROLL_SPEED_UP: case EDIT_BUTTON_SCROLL_SPEED_DOWN: { @@ -1450,8 +1617,10 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) break; case EDIT_BUTTON_SCROLL_UP_LINE: case EDIT_BUTTON_SCROLL_UP_PAGE: + case EDIT_BUTTON_SCROLL_UP_TS: case EDIT_BUTTON_SCROLL_DOWN_LINE: case EDIT_BUTTON_SCROLL_DOWN_PAGE: + case EDIT_BUTTON_SCROLL_DOWN_TS: { float fBeatsToMove=0.f; switch( EditB ) @@ -1465,10 +1634,16 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) break; case EDIT_BUTTON_SCROLL_UP_PAGE: case EDIT_BUTTON_SCROLL_DOWN_PAGE: - fBeatsToMove = beatsPerMeasure; + fBeatsToMove = 4; if( EditB == EDIT_BUTTON_SCROLL_UP_PAGE ) fBeatsToMove *= -1; break; + case EDIT_BUTTON_SCROLL_UP_TS: + case EDIT_BUTTON_SCROLL_DOWN_TS: + fBeatsToMove = beatsPerMeasure; + if( EditB == EDIT_BUTTON_SCROLL_UP_TS ) + fBeatsToMove *= -1; + break; } if( m_PlayerStateEdit.m_PlayerOptions.GetSong().m_fScrolls[PlayerOptions::SCROLL_REVERSE] > 0.5 ) @@ -1508,16 +1683,22 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) ScrollTo( NoteRowToBeat(iRow) ); } break; - case EDIT_BUTTON_LABEL_NEXT: - { - ScrollTo( GetAppropriateTiming().GetNextLabelSegmentBeatAtBeat( GetBeat() ) ); - } - break; - case EDIT_BUTTON_LABEL_PREV: - { - ScrollTo( GetAppropriateTiming().GetPreviousLabelSegmentBeatAtBeat( GetBeat() ) ); - } - break; + case EDIT_BUTTON_SEGMENT_NEXT: + { + // TODO: Work around Stops and Delays. We MAY have to separate them. + TimingData &timing = GetAppropriateTiming(); + ScrollTo(timing.GetNextSegmentBeatAtBeat(this->currentCycleSegment, + GetBeat())); + } + break; + case EDIT_BUTTON_SEGMENT_PREV: + { + // TODO: Work around Stops and Delays. We MAY have to separate them. + TimingData &timing = GetAppropriateTiming(); + ScrollTo(timing.GetPreviousSegmentBeatAtBeat(this->currentCycleSegment, + GetBeat())); + } + break; case EDIT_BUTTON_SNAP_NEXT: if( m_SnapDisplay.PrevSnapMode() ) OnSnapModeChange(); @@ -1557,24 +1738,31 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) case EDIT_BUTTON_OPEN_AREA_MENU: { // update enabled/disabled in g_AreaMenu - bool bAreaSelected = m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1; - g_AreaMenu.rows[cut].bEnabled = bAreaSelected; - g_AreaMenu.rows[copy].bEnabled = bAreaSelected; g_AreaMenu.rows[paste_at_current_beat].bEnabled = !m_Clipboard.IsEmpty(); g_AreaMenu.rows[paste_at_begin_marker].bEnabled = !m_Clipboard.IsEmpty() != 0 && m_NoteFieldEdit.m_iBeginMarker!=-1; - g_AreaMenu.rows[clear].bEnabled = bAreaSelected; - g_AreaMenu.rows[quantize].bEnabled = bAreaSelected; - g_AreaMenu.rows[turn].bEnabled = bAreaSelected; - g_AreaMenu.rows[transform].bEnabled = bAreaSelected; - g_AreaMenu.rows[alter].bEnabled = bAreaSelected; - g_AreaMenu.rows[tempo].bEnabled = bAreaSelected; - g_AreaMenu.rows[play].bEnabled = bAreaSelected; - g_AreaMenu.rows[record].bEnabled = bAreaSelected; - g_AreaMenu.rows[convert_to_pause].bEnabled = bAreaSelected; g_AreaMenu.rows[undo].bEnabled = m_bHasUndo; EditMiniMenu( &g_AreaMenu, SM_BackFromAreaMenu ); } break; + case EDIT_BUTTON_OPEN_ALTER_MENU: + { + bool bAreaSelected = m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1; + if (!bAreaSelected) + { + SCREENMAN->SystemMessage( ALTER_MENU_NO_SELECTION ); + SCREENMAN->PlayInvalidSound(); + } + else + { + bool isRoutine = (m_InputPlayerNumber != PLAYER_INVALID); + g_AlterMenu.rows[routine_invert_notes].bEnabled = isRoutine; + g_AlterMenu.rows[routine_mirror_1_to_2].bEnabled = isRoutine; + g_AlterMenu.rows[routine_mirror_2_to_1].bEnabled = isRoutine; + EditMiniMenu(&g_AlterMenu, SM_BackFromAlterMenu); + } + break; + + } case EDIT_BUTTON_OPEN_EDIT_MENU: EditMiniMenu( &g_MainMenu, SM_BackFromMainMenu ); break; @@ -1592,6 +1780,9 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) // don't keep undo when changing Steps ClearUndo(); + // get the second of the current step. + float curSecond = GetAppropriateTiming().GetElapsedTimeFromBeat(GetBeat()); + // save current steps Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; ASSERT( pSteps ); @@ -1644,6 +1835,8 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) int(vSteps.size()) ); SCREENMAN->SystemMessage( s ); m_soundSwitchSteps.Play(); + + ScrollTo( GetAppropriateTiming().GetBeatFromElapsedTime(curSecond) ); } break; case EDIT_BUTTON_BPM_UP: @@ -1697,24 +1890,26 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) fDelta *= 40; } unsigned i; - for( i=0; i &stops = GetAppropriateTiming().allTimingSegments[SEGMENT_STOP_DELAY]; + for( i=0; iGetRow() == GetRow() ) break; } - if( i == GetAppropriateTiming().m_StopSegments.size() ) // there is no StopSegment at the current beat + if( i == stops.size() ) // there is no StopSegment at the current beat { // create a new StopSegment if( fDelta > 0 ) - GetAppropriateTiming().AddStopSegment( StopSegment( GetRow(), fDelta) ); + GetAppropriateTiming().AddSegment(SEGMENT_STOP_DELAY, + new StopSegment( GetRow(), fDelta) ); } else // StopSegment being modified is m_SongTiming.m_StopSegments[i] { - vector &s = GetAppropriateTiming().m_StopSegments; - s[i].SetPause(s[i].GetPause() + fDelta); - if( s[i].GetPause() <= 0 ) - s.erase( s.begin()+i, s.begin()+i+1); + StopSegment *s = static_cast(stops[i]); + s->SetPause(s->GetPause() + fDelta); + if( s->GetPause() <= 0 ) + stops.erase( stops.begin()+i, stops.begin()+i+1); } (fDelta>0 ? m_soundValueIncrease : m_soundValueDecrease).Play(); SetDirty( true ); @@ -1744,6 +1939,15 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) } GetAppropriateTiming().m_fBeat0OffsetInSeconds += fDelta; (fDelta>0 ? m_soundValueIncrease : m_soundValueDecrease).Play(); + if (GAMESTATE->m_bIsUsingStepTiming) + { + GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks.UpdateStartTimes(fDelta); + } + else + { + GAMESTATE->m_pCurSong->m_Attacks.UpdateStartTimes(fDelta); + GAMESTATE->m_pCurSong->m_fMusicSampleStartSeconds += fDelta; + } SetDirty( true ); } break; @@ -1926,6 +2130,35 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) EditMiniMenu( &g_CourseMode, SM_BackFromCourseModeMenu ); } break; + case EDIT_BUTTON_OPEN_STEP_ATTACK_MENU: + { + TimingData &timing = GetAppropriateTiming(); + float startTime = timing.GetElapsedTimeFromBeat(GetBeat()); + AttackArray &attacks = + (GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks); + int index = FindAttackAtTime(attacks, startTime); + + if (index >= 0) + { + const RString sDuration = ssprintf( "%.6f", attacks[index].fSecsRemaining ); + + g_InsertStepAttack.rows[sa_remove].bEnabled = true; + if( g_InsertStepAttack.rows[sa_duration].choices.size() == 9 ) + g_InsertStepAttack.rows[sa_duration].choices.push_back( sDuration ); + else + g_InsertStepAttack.rows[sa_duration].choices.back() = sDuration; + g_InsertStepAttack.rows[sa_duration].iDefaultChoice = 9; + } + else + { + if( g_InsertStepAttack.rows[sa_duration].choices.size() == 10 ) + g_InsertStepAttack.rows[sa_duration].choices.pop_back(); + g_InsertStepAttack.rows[sa_duration].iDefaultChoice = 3; + } + EditMiniMenu( &g_InsertStepAttack, SM_BackFromInsertStepAttack ); + + break; + } case EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU: { // TODO: Give Song/Step Timing switches/functions here? @@ -1938,7 +2171,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) if( iAttack >= 0 ) { - const RString sDuration = ssprintf( "%.5f", ce.attacks[iAttack].fSecsRemaining ); + const RString sDuration = ssprintf( "%.6f", ce.attacks[iAttack].fSecsRemaining ); g_InsertCourseAttack.rows[remove].bEnabled = true; if( g_InsertCourseAttack.rows[duration].choices.size() == 9 ) @@ -1957,6 +2190,46 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) EditMiniMenu( &g_InsertCourseAttack, SM_BackFromInsertCourseAttack ); } break; + case EDIT_BUTTON_ADD_STEP_MODS: + { + float start = -1; + float end = -1; + PlayerOptions po; + + if (m_NoteFieldEdit.m_iBeginMarker == -1) // not highlighted + { + po.FromString(""); + } + else + { + TimingData &timing = GetAppropriateTiming(); + start = timing.GetElapsedTimeFromBeat(NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker)); + AttackArray &attacks = + (GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks); + int index = FindAttackAtTime(attacks, start); + + if (index >= 0) + { + po.FromString(""); + } + if (m_NoteFieldEdit.m_iEndMarker == -1) + { + end = m_pSong->m_fMusicLengthSeconds; + } + else + { + end = timing.GetElapsedTimeFromBeat(NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker)); + } + + } + ModsGroup &toEdit = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions; + this->originalPlayerOptions.Assign(ModsLevel_Preferred, toEdit.GetPreferred()); + g_fLastInsertAttackPositionSeconds = start; + g_fLastInsertAttackDurationSeconds = end - start; + toEdit.Assign( ModsLevel_Stage, po ); + SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptions", SM_BackFromInsertStepAttackPlayerOptions ); + break; + } case EDIT_BUTTON_ADD_COURSE_MODS: { float fStart, fEnd; @@ -2040,7 +2313,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) case EDIT_BUTTON_RECORD_SELECTION: if( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ) { - HandleAreaMenuChoice( record ); + HandleAlterMenuChoice( record ); } else { @@ -2309,6 +2582,10 @@ void ScreenEdit::InputPlay( const InputEventPlus &input, EditButton EditB ) } GetAppropriateTiming().m_fBeat0OffsetInSeconds += fOffsetDelta; + if (!GAMESTATE->m_bIsUsingStepTiming) + { + GAMESTATE->m_pCurSong->m_fMusicSampleStartSeconds += fOffsetDelta; + } } break; default: break; @@ -2459,7 +2736,7 @@ void ScreenEdit::TransitionEditState( EditState em ) Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; ASSERT( pSteps ); pSteps->SetNoteData( m_NoteDataEdit ); - m_pSong->ReCalculateRadarValuesAndLastBeat(); + m_pSong->ReCalculateRadarValuesAndLastSecond(); m_Background.Unload(); m_Background.LoadFromSong( m_pSong ); @@ -2649,10 +2926,20 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) { HandleAreaMenuChoice( (AreaMenuChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers ); } + else if( SM == SM_BackFromAlterMenu ) + { + HandleAlterMenuChoice( (AlterMenuChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers ); + } else if( SM == SM_BackFromStepsInformation ) { HandleStepsInformationChoice( (StepsInformationChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers ); } + else if (SM == SM_BackFromStepsData) + { + HandleStepsDataChoice((StepsDataChoice)ScreenMiniMenu::s_iLastRowCode, + ScreenMiniMenu::s_viLastAnswers); + } + else if( SM == SM_BackFromSongInformation ) { HandleSongInformationChoice( (SongInformationChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers ); @@ -2708,10 +2995,10 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) } else if ( SM == SM_BackFromComboChange && !ScreenTextEntry::s_bCancelledLast ) { - int iCombo = StringToInt( ScreenTextEntry::s_sLastAnswer ); - if ( iCombo >= 0 ) + int iCombo, iMiss; + if (sscanf(ScreenTextEntry::s_sLastAnswer.c_str(), " %d / %d ", &iCombo, &iMiss) == 2) { - GetAppropriateTiming().SetComboAtBeat( GetBeat(), iCombo ); + GetAppropriateTiming().SetComboAtBeat( GetBeat(), iCombo, iMiss ); } SetDirty( true ); } @@ -2853,6 +3140,32 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) m_NoteDataEdit.SetTapNote( g_iLastInsertTapAttackTrack, row, tn ); CheckNumberOfNotesAndUndo(); } + else if (SM == SM_BackFromInsertStepAttack) + { + int iDurationChoice = ScreenMiniMenu::s_viLastAnswers[0]; + TimingData &timing = GetAppropriateTiming(); + g_fLastInsertAttackPositionSeconds = timing.GetElapsedTimeFromBeat( GetBeat() ); + g_fLastInsertAttackDurationSeconds = StringToFloat( g_InsertStepAttack.rows[0].choices[iDurationChoice] ); + AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks; + int iAttack = FindAttackAtTime(attacks, g_fLastInsertAttackPositionSeconds); + + if (ScreenMiniMenu::s_iLastRowCode == ScreenEdit::remove ) + { + if (iAttack > 0) + attacks.erase(attacks.begin() + iAttack); + } + else + { + ModsGroup &toEdit = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions; + this->originalPlayerOptions.Assign(ModsLevel_Preferred, toEdit.GetPreferred()); + PlayerOptions po; + if (iAttack >= 0) + po.FromString(attacks[iAttack].sModifiers); + + toEdit.Assign( ModsLevel_Preferred, po ); + SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptions", SM_BackFromInsertStepAttackPlayerOptions ); + } + } else if( SM == SM_BackFromInsertCourseAttack ) { int iDurationChoice = ScreenMiniMenu::s_viLastAnswers[0]; @@ -2882,6 +3195,29 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptions", SM_BackFromInsertCourseAttackPlayerOptions ); } } + else if (SM == SM_BackFromInsertStepAttackPlayerOptions) + { + ModsGroup &toRestore = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions; + PlayerOptions poChosen = toRestore.GetPreferred(); + RString mods = poChosen.GetString(); + + if (g_fLastInsertAttackPositionSeconds >= 0) + { + Attack a(ATTACK_LEVEL_1, + g_fLastInsertAttackPositionSeconds, + g_fLastInsertAttackDurationSeconds, + mods, + false, + false); + AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks; + int index = FindAttackAtTime(attacks, g_fLastInsertAttackPositionSeconds); + if (index >= 0) + attacks[index] = a; + else + attacks.push_back(a); + } + toRestore.Assign(ModsLevel_Preferred, this->originalPlayerOptions.GetPreferred()); + } else if( SM == SM_BackFromInsertCourseAttackPlayerOptions ) { PlayerOptions poChosen = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.GetPreferred(); @@ -3066,6 +3402,12 @@ static void ChangeDescription( const RString &sNew ) pSteps->SetDescription(sNew); } +static void ChangeChartName( const RString &sNew ) +{ + Steps *pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; + pSteps->SetChartName(sNew); +} + static void ChangeChartStyle( const RString &sNew ) { Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; @@ -3128,13 +3470,27 @@ static void ChangeArtistTranslit( const RString &sNew ) static void ChangeBeat0Offset( const RString &sNew ) { - TimingData &timing = GAMESTATE->m_bIsUsingStepTiming ? GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing : GAMESTATE->m_pCurSong->m_SongTiming; + TimingData &timing = (GAMESTATE->m_bIsUsingStepTiming ? + GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing : + GAMESTATE->m_pCurSong->m_SongTiming); + float old = timing.m_fBeat0OffsetInSeconds; timing.m_fBeat0OffsetInSeconds = StringToFloat( sNew ); + float delta = timing.m_fBeat0OffsetInSeconds - old; + if (GAMESTATE->m_bIsUsingStepTiming) + { + GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks.UpdateStartTimes(delta); + } + else + { + GAMESTATE->m_pCurSong->m_Attacks.UpdateStartTimes(delta); + GAMESTATE->m_pCurSong->m_fMusicSampleStartSeconds += delta; + } } -static void ChangeLastBeatHint( const RString &sNew ) +static void ChangeLastSecondHint( const RString &sNew ) { - GAMESTATE->m_pCurSong->m_fSpecifiedLastBeat = StringToFloat( sNew ); + Song &s = *GAMESTATE->m_pCurSong; + s.SetSpecifiedLastSecond(StringToFloat(sNew)); } static void ChangePreviewStart( const RString &sNew ) @@ -3152,11 +3508,23 @@ static void ChangeMinBPM( const RString &sNew ) GAMESTATE->m_pCurSong->m_fSpecifiedBPMMin = StringToFloat( sNew ); } +static void ChangeStepsMinBPM(const RString &sNew) +{ + Steps *step = GAMESTATE->m_pCurSteps[PLAYER_1]; + step->SetMinBPM(StringToFloat(sNew)); +} + static void ChangeMaxBPM( const RString &sNew ) { GAMESTATE->m_pCurSong->m_fSpecifiedBPMMax = StringToFloat( sNew ); } +static void ChangeStepsMaxBPM(const RString &sNew) +{ + Steps *step = GAMESTATE->m_pCurSteps[PLAYER_1]; + step->SetMaxBPM(StringToFloat(sNew)); +} + TimingData & ScreenEdit::GetAppropriateTiming() const { if( GAMESTATE->m_bIsUsingStepTiming ) @@ -3207,25 +3575,29 @@ void ScreenEdit::DisplayTimingMenu() { float fBeat = GetBeat(); TimingData &pTime = GetAppropriateTiming(); - bool bHasSpeedOnThisRow = pTime.GetSpeedSegmentAtBeat( fBeat ).GetBeat() == fBeat; + bool bHasSpeedOnThisRow = pTime.GetSpeedSegmentAtBeat( fBeat )->GetBeat() == fBeat; - g_TimingDataInformation.rows[beat_0_offset].SetOneUnthemedChoice( ssprintf("%.5f", pTime.m_fBeat0OffsetInSeconds) ); - g_TimingDataInformation.rows[bpm].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetBPMAtBeat( fBeat ) ) ); - g_TimingDataInformation.rows[stop].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetStopAtBeat( fBeat ) ) ) ; - g_TimingDataInformation.rows[delay].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetDelayAtBeat( fBeat ) ) ); - g_TimingDataInformation.rows[time_signature].SetOneUnthemedChoice( ssprintf("%d / %d", pTime.GetTimeSignatureNumeratorAtBeat( fBeat ), pTime.GetTimeSignatureDenominatorAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[beat_0_offset].SetOneUnthemedChoice( ssprintf("%.6f", pTime.m_fBeat0OffsetInSeconds) ); + g_TimingDataInformation.rows[bpm].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetBPMAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[stop].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetStopAtBeat( fBeat ) ) ) ; + g_TimingDataInformation.rows[delay].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetDelayAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[time_signature].SetOneUnthemedChoice(ssprintf("%d / %d", + pTime.GetTimeSignatureNumeratorAtBeat( fBeat ), + pTime.GetTimeSignatureDenominatorAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[label].SetOneUnthemedChoice( pTime.GetLabelAtBeat( fBeat ).c_str() ); g_TimingDataInformation.rows[tickcount].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTickcountAtBeat( fBeat ) ) ); - g_TimingDataInformation.rows[combo].SetOneUnthemedChoice( ssprintf("%d", pTime.GetComboAtBeat( fBeat ) ) ); - g_TimingDataInformation.rows[warp].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetWarpAtBeat( fBeat ) ) ); - g_TimingDataInformation.rows[speed_percent].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.5f", pTime.GetSpeedPercentAtBeat( fBeat ) ) : "---" ); - g_TimingDataInformation.rows[speed_wait].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.5f", pTime.GetSpeedWaitAtBeat( fBeat ) ) : "---" ); + g_TimingDataInformation.rows[combo].SetOneUnthemedChoice( ssprintf("%d / %d", + pTime.GetComboAtBeat( fBeat ), + pTime.GetMissComboAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[warp].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetWarpAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[speed_percent].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.6f", pTime.GetSpeedPercentAtBeat( fBeat ) ) : "---" ); + g_TimingDataInformation.rows[speed_wait].SetOneUnthemedChoice( bHasSpeedOnThisRow ? ssprintf("%.6f", pTime.GetSpeedWaitAtBeat( fBeat ) ) : "---" ); RString starting = ( pTime.GetSpeedModeAtBeat( fBeat ) == 1 ? "Seconds" : "Beats" ); g_TimingDataInformation.rows[speed_mode].SetOneUnthemedChoice( starting.c_str() ); - g_TimingDataInformation.rows[scroll].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetScrollAtBeat( fBeat ) ) ); - g_TimingDataInformation.rows[fake].SetOneUnthemedChoice( ssprintf("%.5f", pTime.GetFakeAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[scroll].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetScrollAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[fake].SetOneUnthemedChoice( ssprintf("%.6f", pTime.GetFakeAtBeat( fBeat ) ) ); g_TimingDataInformation.rows[tickcount].bEnabled = GAMESTATE->m_bIsUsingStepTiming; g_TimingDataInformation.rows[combo].bEnabled = GAMESTATE->m_bIsUsingStepTiming; @@ -3247,12 +3619,13 @@ static LocalizedString SAVE_CHANGES_BEFORE_EXITING ( "ScreenEdit", "Do you want void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAnswers ) { + GAMESTATE->SetProcessedTimingData(&m_pSteps->m_Timing); switch( c ) { DEFAULT_FAIL( c ); case play_selection: if( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ) - HandleAreaMenuChoice( play ); + HandleAlterMenuChoice( play ); else if( m_NoteFieldEdit.m_iBeginMarker!=-1 ) HandleMainMenuChoice( play_selection_start_to_end ); else @@ -3312,7 +3685,6 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns /* XXX: If the difficulty is changed from EDIT, and pSteps->WasLoadedFromProfile() * is true, we should warn that the steps will no longer be saved to the profile. */ Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; - float fMusicSeconds = m_pSoundMusic->GetLengthSeconds(); g_StepsInformation.rows[difficulty].choices.clear(); FOREACH_ENUM( Difficulty, dc ) @@ -3324,26 +3696,66 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns g_StepsInformation.rows[meter].SetOneUnthemedChoice( ssprintf("%d", pSteps->GetMeter()) ); g_StepsInformation.rows[meter].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Home); g_StepsInformation.rows[predict_meter].SetOneUnthemedChoice( ssprintf("%.2f",pSteps->PredictMeter()) ); + g_StepsInformation.rows[chartname].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full); + g_StepsInformation.rows[chartname].SetOneUnthemedChoice(pSteps->GetChartName()); g_StepsInformation.rows[description].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full); g_StepsInformation.rows[description].SetOneUnthemedChoice( pSteps->GetDescription() ); g_StepsInformation.rows[chartstyle].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full); g_StepsInformation.rows[chartstyle].SetOneUnthemedChoice( pSteps->GetChartStyle() ); g_StepsInformation.rows[step_credit].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full); g_StepsInformation.rows[step_credit].SetOneUnthemedChoice( pSteps->GetCredit() ); - g_StepsInformation.rows[tap_notes].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumTapNotes()) ); - g_StepsInformation.rows[jumps].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumJumps()) ); - g_StepsInformation.rows[hands].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumHands()) ); - g_StepsInformation.rows[quads].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumQuads()) ); - g_StepsInformation.rows[holds].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumHoldNotes()) ); - g_StepsInformation.rows[mines].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumMines()) ); - g_StepsInformation.rows[stream].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetStreamRadarValue(m_NoteDataEdit,fMusicSeconds)) ); - g_StepsInformation.rows[voltage].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetVoltageRadarValue(m_NoteDataEdit,fMusicSeconds)) ); - g_StepsInformation.rows[air].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetAirRadarValue(m_NoteDataEdit,fMusicSeconds)) ); - g_StepsInformation.rows[freeze].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetFreezeRadarValue(m_NoteDataEdit,fMusicSeconds)) ); - g_StepsInformation.rows[chaos].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetChaosRadarValue(m_NoteDataEdit,fMusicSeconds)) ); + g_StepsInformation.rows[step_display_bpm].iDefaultChoice = pSteps->GetDisplayBPM(); + g_StepsInformation.rows[step_min_bpm].SetOneUnthemedChoice( ssprintf("%.6f", pSteps->GetMinBPM())); + g_StepsInformation.rows[step_max_bpm].SetOneUnthemedChoice( ssprintf("%.6f", pSteps->GetMaxBPM())); EditMiniMenu( &g_StepsInformation, SM_BackFromStepsInformation, SM_None ); } break; + case view_steps_data: + { + float fMusicSeconds = m_pSoundMusic->GetLengthSeconds(); + Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; + const StepsTypeCategory &cat = GAMEMAN->GetStepsTypeInfo(pSteps->m_StepsType).m_StepsTypeCategory; + if (cat == StepsTypeCategory_Couple || cat == StepsTypeCategory_Routine) + { + pair tmp = m_NoteDataEdit.GetNumTapNotesTwoPlayer(); + g_StepsData.rows[tap_notes].SetOneUnthemedChoice( ssprintf("%d / %d", tmp.first, tmp.second) ); + tmp = m_NoteDataEdit.GetNumJumpsTwoPlayer(); + g_StepsData.rows[jumps].SetOneUnthemedChoice( ssprintf("%d / %d", tmp.first, tmp.second) ); + tmp = m_NoteDataEdit.GetNumHandsTwoPlayer(); + g_StepsData.rows[hands].SetOneUnthemedChoice( ssprintf("%d / %d", tmp.first, tmp.second) ); + tmp = m_NoteDataEdit.GetNumQuadsTwoPlayer(); + g_StepsData.rows[quads].SetOneUnthemedChoice( ssprintf("%d / %d", tmp.first, tmp.second) ); + tmp = m_NoteDataEdit.GetNumHoldNotesTwoPlayer(); + g_StepsData.rows[holds].SetOneUnthemedChoice( ssprintf("%d / %d", tmp.first, tmp.second) ); + tmp = m_NoteDataEdit.GetNumMinesTwoPlayer(); + g_StepsData.rows[mines].SetOneUnthemedChoice( ssprintf("%d / %d", tmp.first, tmp.second) ); + tmp = m_NoteDataEdit.GetNumRollsTwoPlayer(); + g_StepsData.rows[rolls].SetOneUnthemedChoice( ssprintf("%d / %d", tmp.first, tmp.second) ); + tmp = m_NoteDataEdit.GetNumLiftsTwoPlayer(); + g_StepsData.rows[lifts].SetOneUnthemedChoice( ssprintf("%d / %d", tmp.first, tmp.second) ); + tmp = m_NoteDataEdit.GetNumFakesTwoPlayer(); + g_StepsData.rows[fakes].SetOneUnthemedChoice( ssprintf("%d / %d", tmp.first, tmp.second) ); + } + else + { + g_StepsData.rows[tap_notes].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumTapNotes()) ); + g_StepsData.rows[jumps].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumJumps()) ); + g_StepsData.rows[hands].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumHands()) ); + g_StepsData.rows[quads].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumQuads()) ); + g_StepsData.rows[holds].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumHoldNotes()) ); + g_StepsData.rows[mines].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumMines()) ); + g_StepsData.rows[rolls].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumRolls()) ); + g_StepsData.rows[lifts].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumLifts()) ); + g_StepsData.rows[fakes].SetOneUnthemedChoice( ssprintf("%d", m_NoteDataEdit.GetNumFakes()) ); + } + g_StepsData.rows[stream].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetStreamRadarValue(m_NoteDataEdit,fMusicSeconds)) ); + g_StepsData.rows[voltage].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetVoltageRadarValue(m_NoteDataEdit,fMusicSeconds)) ); + g_StepsData.rows[air].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetAirRadarValue(m_NoteDataEdit,fMusicSeconds)) ); + g_StepsData.rows[freeze].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetFreezeRadarValue(m_NoteDataEdit,fMusicSeconds)) ); + g_StepsData.rows[chaos].SetOneUnthemedChoice( ssprintf("%.2f", NoteDataUtil::GetChaosRadarValue(m_NoteDataEdit,fMusicSeconds)) ); + EditMiniMenu( &g_StepsData, SM_BackFromStepsData, SM_None ); + break; + } case save: case save_on_exit: { @@ -3351,6 +3763,12 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns // copy edit into current Steps m_pSteps->SetNoteData( m_NoteDataEdit ); + + // don't forget the attacks. + m_pSong->m_Attacks = GAMESTATE->m_pCurSong->m_Attacks; + m_pSong->m_sAttackString = GAMESTATE->m_pCurSong->m_Attacks.ToVectorString(); + m_pSteps->m_Attacks = GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks; + m_pSteps->m_sAttackString = GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks.ToVectorString(); switch( EDIT_MODE.GetValue() ) { @@ -3428,12 +3846,12 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns g_SongInformation.rows[main_title_transliteration].SetOneUnthemedChoice( pSong->m_sMainTitleTranslit ); g_SongInformation.rows[sub_title_transliteration].SetOneUnthemedChoice( pSong->m_sSubTitleTranslit ); g_SongInformation.rows[artist_transliteration].SetOneUnthemedChoice( pSong->m_sArtistTranslit ); - g_SongInformation.rows[last_beat_hint].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fSpecifiedLastBeat) ); - g_SongInformation.rows[preview_start].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fMusicSampleStartSeconds) ); - g_SongInformation.rows[preview_length].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fMusicSampleLengthSeconds) ); + g_SongInformation.rows[last_second_hint].SetOneUnthemedChoice( ssprintf("%.6f", pSong->GetSpecifiedLastSecond()) ); + g_SongInformation.rows[preview_start].SetOneUnthemedChoice( ssprintf("%.6f", pSong->m_fMusicSampleStartSeconds) ); + g_SongInformation.rows[preview_length].SetOneUnthemedChoice( ssprintf("%.6f", pSong->m_fMusicSampleLengthSeconds) ); g_SongInformation.rows[display_bpm].iDefaultChoice = pSong->m_DisplayBPMType; - g_SongInformation.rows[min_bpm].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fSpecifiedBPMMin) ); - g_SongInformation.rows[max_bpm].SetOneUnthemedChoice( ssprintf("%.5f", pSong->m_fSpecifiedBPMMax) ); + g_SongInformation.rows[min_bpm].SetOneUnthemedChoice( ssprintf("%.6f", pSong->m_fSpecifiedBPMMin) ); + g_SongInformation.rows[max_bpm].SetOneUnthemedChoice( ssprintf("%.6f", pSong->m_fSpecifiedBPMMax) ); EditMiniMenu( &g_SongInformation, SM_BackFromSongInformation ); } @@ -3465,36 +3883,382 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns } break; }; + GAMESTATE->SetProcessedTimingData(NULL); +} + +void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector &iAnswers, bool bAllowUndo) +{ + bool bSaveUndo = true; + switch (c) + { + case play: + case record: + case cut: + case copy: + { + bSaveUndo = false; + } + default: + break; + } + + if( bSaveUndo ) + SetDirty( true ); + + /* We call HandleAreaMenuChoice recursively. Only the outermost + * HandleAreaMenuChoice should allow Undo so that the inner calls don't + * also save Undo and mess up the outermost */ + if( !bAllowUndo ) + bSaveUndo = false; + + if( bSaveUndo ) + SaveUndo(); + + switch(c) + { + case cut: + { + HandleAlterMenuChoice( copy ); + HandleAlterMenuChoice( clear ); + } + break; + case copy: + { + ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); + m_Clipboard.ClearAll(); + m_Clipboard.CopyRange( m_NoteDataEdit, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker ); + } + break; + case clear: + { + ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); + m_NoteDataEdit.ClearRange( m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker ); + } + break; + case quantize: + { + NoteType nt = (NoteType)iAnswers[c]; + NoteDataUtil::SnapToNearestNoteType(m_NoteDataEdit, nt, nt, + m_NoteFieldEdit.m_iBeginMarker, + m_NoteFieldEdit.m_iEndMarker ); + break; + } + case turn: + { + const NoteData OldClipboard( m_Clipboard ); + HandleAlterMenuChoice( cut ); + + StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; + TurnType tt = (TurnType)iAnswers[c]; + switch( tt ) + { + DEFAULT_FAIL( tt ); + case left: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::left ); break; + case right: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::right ); break; + case mirror: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::mirror ); break; + case shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::shuffle ); break; + case super_shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::super_shuffle ); break; + } + + HandleAreaMenuChoice( paste_at_begin_marker ); + m_Clipboard = OldClipboard; + } + break; + case transform: + { + int iBeginRow = m_NoteFieldEdit.m_iBeginMarker; + int iEndRow = m_NoteFieldEdit.m_iEndMarker; + TransformType tt = (TransformType)iAnswers[c]; + StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; + + switch( tt ) + { + DEFAULT_FAIL( tt ); + case noholds: NoteDataUtil::RemoveHoldNotes( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case nomines: NoteDataUtil::RemoveMines( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case little: NoteDataUtil::Little( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case wide: NoteDataUtil::Wide( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case big: NoteDataUtil::Big( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case quick: NoteDataUtil::Quick( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case skippy: NoteDataUtil::Skippy( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case add_mines: NoteDataUtil::AddMines( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case echo: NoteDataUtil::Echo( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case stomp: NoteDataUtil::Stomp( m_NoteDataEdit, st, iBeginRow, iEndRow ); break; + case planted: NoteDataUtil::Planted( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case floored: NoteDataUtil::Floored( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case twister: NoteDataUtil::Twister( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case nojumps: NoteDataUtil::RemoveJumps( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case nohands: NoteDataUtil::RemoveHands( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case noquads: NoteDataUtil::RemoveQuads( m_NoteDataEdit, iBeginRow, iEndRow ); break; + case nostretch: NoteDataUtil::RemoveStretch( m_NoteDataEdit, st, iBeginRow, iBeginRow );break; + } + + // bake in the additions + NoteDataUtil::ConvertAdditionsToRegular( m_NoteDataEdit ); + break; + } + case alter: + { + const NoteData OldClipboard( m_Clipboard ); + HandleAlterMenuChoice( cut ); + + AlterType at = (AlterType)iAnswers[c]; + switch( at ) + { + DEFAULT_FAIL( at ); + case autogen_to_fill_width: + { + NoteData temp( m_Clipboard ); + int iMaxNonEmptyTrack = NoteDataUtil::GetMaxNonEmptyTrack( temp ); + if( iMaxNonEmptyTrack == -1 ) + break; + temp.SetNumTracks( iMaxNonEmptyTrack+1 ); + NoteDataUtil::LoadTransformedSlidingWindow( temp, m_Clipboard, m_Clipboard.GetNumTracks() ); + NoteDataUtil::RemoveStretch( m_Clipboard, GAMESTATE->m_pCurSteps[0]->m_StepsType ); + } + break; + case backwards: NoteDataUtil::Backwards( m_Clipboard ); break; + case swap_sides: NoteDataUtil::SwapSides( m_Clipboard ); break; + case copy_left_to_right: NoteDataUtil::CopyLeftToRight( m_Clipboard ); break; + case copy_right_to_left: NoteDataUtil::CopyRightToLeft( m_Clipboard ); break; + case clear_left: NoteDataUtil::ClearLeft( m_Clipboard ); break; + case clear_right: NoteDataUtil::ClearRight( m_Clipboard ); break; + case collapse_to_one: NoteDataUtil::CollapseToOne( m_Clipboard ); break; + case collapse_left: NoteDataUtil::CollapseLeft( m_Clipboard ); break; + case shift_left: NoteDataUtil::ShiftLeft( m_Clipboard ); break; + case shift_right: NoteDataUtil::ShiftRight( m_Clipboard ); break; + } + + HandleAreaMenuChoice( paste_at_begin_marker ); + m_Clipboard = OldClipboard; + break; + } + case tempo: + { + // This affects all steps. + AlterType at = (AlterType)iAnswers[c]; + float fScale = -1; + + switch( at ) + { + DEFAULT_FAIL( at ); + case compress_2x: fScale = 0.5f; break; + case compress_3_2: fScale = 2.0f/3; break; + case compress_4_3: fScale = 0.75f; break; + case expand_4_3: fScale = 4.0f/3; break; + case expand_3_2: fScale = 1.5f; break; + case expand_2x: fScale = 2; break; + } + + int iStartIndex = m_NoteFieldEdit.m_iBeginMarker; + int iEndIndex = m_NoteFieldEdit.m_iEndMarker; + int iNewEndIndex = iEndIndex + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) ); + + // scale currently editing notes + NoteDataUtil::ScaleRegion( m_NoteDataEdit, fScale, iStartIndex, iEndIndex ); + + // scale timing data + GetAppropriateTiming().ScaleRegion(fScale, + m_NoteFieldEdit.m_iBeginMarker, + m_NoteFieldEdit.m_iEndMarker, true ); + + m_NoteFieldEdit.m_iEndMarker = iNewEndIndex; + break; + + } + + case play: + ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); + m_iStartPlayingAt = m_NoteFieldEdit.m_iBeginMarker; + m_iStopPlayingAt = m_NoteFieldEdit.m_iEndMarker; + TransitionEditState( STATE_PLAYING ); + break; + case record: + ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); + m_iStartPlayingAt = m_NoteFieldEdit.m_iBeginMarker; + m_iStopPlayingAt = m_NoteFieldEdit.m_iEndMarker; + TransitionEditState( STATE_RECORDING ); + break; + case preview_designation: + { + ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); + float fMarkerStart = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); + float fMarkerEnd = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); + GAMESTATE->m_pCurSong->m_fMusicSampleStartSeconds = fMarkerStart; + GAMESTATE->m_pCurSong->m_fMusicSampleLengthSeconds = fMarkerEnd - fMarkerStart; + break; + } + case convert_to_pause: + { + ASSERT_M( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1, "Attempted to convert beats outside the notefield to pauses!" ); + float fMarkerStart = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); + float fMarkerEnd = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); + + // The length of the stop segment we're going to create. This includes time spent in any + // stops in the selection, which will be deleted and subsumed into the new stop. + float fStopLength = fMarkerEnd - fMarkerStart; + + // be sure not to clobber the row at the start - a row at the end + // can be dropped safely, though + NoteDataUtil::DeleteRows( m_NoteDataEdit, + m_NoteFieldEdit.m_iBeginMarker + 1, + m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker + ); + GetAppropriateTiming().DeleteRows( m_NoteFieldEdit.m_iBeginMarker + 1, + m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker ); + GetAppropriateTiming().SetStopAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength ); + m_NoteFieldEdit.m_iBeginMarker = -1; + m_NoteFieldEdit.m_iEndMarker = -1; + break; + } + case convert_to_delay: + { + ASSERT_M( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1, "Attempted to convert beats outside the notefield to pauses!" ); + float fMarkerStart = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); + float fMarkerEnd = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); + + // The length of the delay segment we're going to create. This includes time spent in any + // stops in the selection, which will be deleted and subsumed into the new stop. + float fStopLength = fMarkerEnd - fMarkerStart; + + NoteDataUtil::DeleteRows( m_NoteDataEdit, + m_NoteFieldEdit.m_iBeginMarker, + m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker + ); + GetAppropriateTiming().DeleteRows( m_NoteFieldEdit.m_iBeginMarker, + m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker ); + GetAppropriateTiming().SetDelayAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength ); + m_NoteFieldEdit.m_iBeginMarker = -1; + m_NoteFieldEdit.m_iEndMarker = -1; + break; + } + case convert_to_warp: + { + float startBeat = NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker); + float lengthBeat = NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) - startBeat; + GetAppropriateTiming().SetWarpAtBeat(startBeat,lengthBeat); + SetDirty(true); + break; + } + case convert_to_attack: + { + float startBeat = NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker); + float endBeat = NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker); + TimingData &timing = GetAppropriateTiming(); + float &start = g_fLastInsertAttackPositionSeconds; + float &length = g_fLastInsertAttackDurationSeconds; + start = timing.GetElapsedTimeFromBeat(startBeat); + length = timing.GetElapsedTimeFromBeat(endBeat) - start; + + AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ? + m_pSteps->m_Attacks : m_pSong->m_Attacks; + int iAttack = FindAttackAtTime(attacks, start); + + ModsGroup &toEdit = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions; + this->originalPlayerOptions.Assign(ModsLevel_Preferred, toEdit.GetPreferred()); + PlayerOptions po; + if (iAttack >= 0) + po.FromString(attacks[iAttack].sModifiers); + + toEdit.Assign( ModsLevel_Preferred, po ); + SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptions", SM_BackFromInsertStepAttackPlayerOptions ); + SetDirty(true); + break; + } + case convert_to_fake: + { + float startBeat = NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker); + float lengthBeat = NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) - startBeat; + GetAppropriateTiming().SetFakeAtBeat(startBeat,lengthBeat); + SetDirty(true); + break; + } + case routine_invert_notes: + { + NoteData &nd = this->m_NoteDataEdit; + NoteField &nf = this->m_NoteFieldEdit; + FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE(nd, r, + nf.m_iBeginMarker, + nf.m_iEndMarker) + { + for (int t = 0; t < nd.GetNumTracks(); t++) + { + const TapNote &tn = nd.GetTapNote(t, r); + if (tn.type != TapNote::empty) + { + TapNote nTap = tn; + nTap.pn = (tn.pn == PLAYER_1 ? + PLAYER_2 : PLAYER_1); + m_NoteDataEdit.SetTapNote(t, r, nTap); + } + } + } + break; + } + case routine_mirror_1_to_2: + case routine_mirror_2_to_1: + { + PlayerNumber oPN = (c == routine_mirror_1_to_2 ? + PLAYER_1 : PLAYER_2); + PlayerNumber nPN = (c == routine_mirror_1_to_2 ? + PLAYER_2 : PLAYER_1); + int nTrack = -1; + NoteData &nd = this->m_NoteDataEdit; + NoteField &nf = this->m_NoteFieldEdit; + int tracks = nd.GetNumTracks(); + FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE(nd, r, + nf.m_iBeginMarker, + nf.m_iEndMarker) + { + for (int t = 0; t < tracks; t++) + { + const TapNote &tn = nd.GetTapNote(t, r); + if (tn.type != TapNote::empty && tn.pn == oPN) + { + TapNote nTap = tn; + nTap.pn = nPN; + StepsType curType = GAMESTATE->m_pCurSteps[PLAYER_1]->m_StepsType; + if (curType == StepsType_dance_routine) + { + nTrack = tracks - t - 1; + } + else if (curType == StepsType_pump_routine) + { + switch (t) + { + case 0: nTrack = 8; break; + case 1: nTrack = 9; break; + case 2: nTrack = 7; break; + case 3: nTrack = 5; break; + case 4: nTrack = 6; break; + case 5: nTrack = 3; break; + case 6: nTrack = 4; break; + case 7: nTrack = 2; break; + case 8: nTrack = 0; break; + case 9: nTrack = 1; break; + default: FAIL_M(ssprintf("Invalid column %d for pump-routine", t)); break; + } + } + m_NoteDataEdit.SetTapNote(nTrack, r, nTap); + } + } + } + break; + } + } + } void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAnswers, bool bAllowUndo ) { - bool bSaveUndo = false; + bool bSaveUndo = true; switch( c ) { - DEFAULT_FAIL( c ); - case cut: - case copy: - case play: - case record: + case clear_clipboard: case undo: bSaveUndo = false; break; - case paste_at_current_beat: - case paste_at_begin_marker: - case clear: - case quantize: - case turn: - case transform: - case alter: - case tempo: - case insert_and_shift: - case delete_and_shift: - case shift_pauses_forward: - case shift_pauses_backward: - case convert_to_pause: - case convert_pause_to_beat: - bSaveUndo = true; + default: break; } @@ -3513,19 +4277,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns switch( c ) { DEFAULT_FAIL( c ); - case cut: - { - HandleAreaMenuChoice( copy ); - HandleAreaMenuChoice( clear ); - } - break; - case copy: - { - ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); - m_Clipboard.ClearAll(); - m_Clipboard.CopyRange( m_NoteDataEdit, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker ); - } - break; + case paste_at_current_beat: case paste_at_begin_marker: { @@ -3546,172 +4298,6 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns m_NoteDataEdit.CopyRange( m_Clipboard, 0, iRowsToCopy, iDestFirstRow ); } break; - case clear: - { - ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); - m_NoteDataEdit.ClearRange( m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker ); - } - break; - case quantize: - { - NoteType nt = (NoteType)iAnswers[c]; - NoteDataUtil::SnapToNearestNoteType( m_NoteDataEdit, nt, nt, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker ); - } - break; - case turn: - { - const NoteData OldClipboard( m_Clipboard ); - HandleAreaMenuChoice( cut ); - - StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; - TurnType tt = (TurnType)iAnswers[c]; - switch( tt ) - { - DEFAULT_FAIL( tt ); - case left: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::left ); break; - case right: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::right ); break; - case mirror: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::mirror ); break; - case shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::shuffle ); break; - case super_shuffle: NoteDataUtil::Turn( m_Clipboard, st, NoteDataUtil::super_shuffle ); break; - } - - HandleAreaMenuChoice( paste_at_begin_marker ); - m_Clipboard = OldClipboard; - } - break; - case transform: - { - int iBeginRow = m_NoteFieldEdit.m_iBeginMarker; - int iEndRow = m_NoteFieldEdit.m_iEndMarker; - TransformType tt = (TransformType)iAnswers[c]; - StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; - - switch( tt ) - { - DEFAULT_FAIL( tt ); - case noholds: NoteDataUtil::RemoveHoldNotes( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case nomines: NoteDataUtil::RemoveMines( m_NoteDataEdit, iBeginRow, iBeginRow ); break; - case little: NoteDataUtil::Little( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case wide: NoteDataUtil::Wide( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case big: NoteDataUtil::Big( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case quick: NoteDataUtil::Quick( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case skippy: NoteDataUtil::Skippy( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case add_mines: NoteDataUtil::AddMines( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case echo: NoteDataUtil::Echo( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case stomp: NoteDataUtil::Stomp( m_NoteDataEdit, st, iBeginRow, iEndRow ); break; - case planted: NoteDataUtil::Planted( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case floored: NoteDataUtil::Floored( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case twister: NoteDataUtil::Twister( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case nojumps: NoteDataUtil::RemoveJumps( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case nohands: NoteDataUtil::RemoveHands( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case noquads: NoteDataUtil::RemoveQuads( m_NoteDataEdit, iBeginRow, iEndRow ); break; - case nostretch: NoteDataUtil::RemoveStretch( m_NoteDataEdit, st, iBeginRow, iBeginRow );break; - } - - // bake in the additions - NoteDataUtil::ConvertAdditionsToRegular( m_NoteDataEdit ); - } - break; - case alter: - { - const NoteData OldClipboard( m_Clipboard ); - HandleAreaMenuChoice( cut ); - - AlterType at = (AlterType)iAnswers[c]; - switch( at ) - { - DEFAULT_FAIL( at ); - case autogen_to_fill_width: - { - NoteData temp( m_Clipboard ); - int iMaxNonEmptyTrack = NoteDataUtil::GetMaxNonEmptyTrack( temp ); - if( iMaxNonEmptyTrack == -1 ) - break; - temp.SetNumTracks( iMaxNonEmptyTrack+1 ); - NoteDataUtil::LoadTransformedSlidingWindow( temp, m_Clipboard, m_Clipboard.GetNumTracks() ); - NoteDataUtil::RemoveStretch( m_Clipboard, GAMESTATE->m_pCurSteps[0]->m_StepsType ); - } - break; - case backwards: NoteDataUtil::Backwards( m_Clipboard ); break; - case swap_sides: NoteDataUtil::SwapSides( m_Clipboard ); break; - case copy_left_to_right: NoteDataUtil::CopyLeftToRight( m_Clipboard ); break; - case copy_right_to_left: NoteDataUtil::CopyRightToLeft( m_Clipboard ); break; - case clear_left: NoteDataUtil::ClearLeft( m_Clipboard ); break; - case clear_right: NoteDataUtil::ClearRight( m_Clipboard ); break; - case collapse_to_one: NoteDataUtil::CollapseToOne( m_Clipboard ); break; - case collapse_left: NoteDataUtil::CollapseLeft( m_Clipboard ); break; - case shift_left: NoteDataUtil::ShiftLeft( m_Clipboard ); break; - case shift_right: NoteDataUtil::ShiftRight( m_Clipboard ); break; - } - - HandleAreaMenuChoice( paste_at_begin_marker ); - m_Clipboard = OldClipboard; - } - break; - case tempo: - { - // This affects all steps. - AlterType at = (AlterType)iAnswers[c]; - float fScale = -1; - - switch( at ) - { - DEFAULT_FAIL( at ); - case compress_2x: fScale = 0.5f; break; - case compress_3_2: fScale = 2.0f/3; break; - case compress_4_3: fScale = 0.75f; break; - case expand_4_3: fScale = 4.0f/3; break; - case expand_3_2: fScale = 1.5f; break; - case expand_2x: fScale = 2; break; - } - - int iStartIndex = m_NoteFieldEdit.m_iBeginMarker; - int iEndIndex = m_NoteFieldEdit.m_iEndMarker; - int iNewEndIndex = iEndIndex + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) ); - - // scale currently editing notes - NoteDataUtil::ScaleRegion( m_NoteDataEdit, fScale, iStartIndex, iEndIndex ); - - // scale timing data - GetAppropriateTiming().ScaleRegion( fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker, true ); - - // scale all other steps. - /* - const vector sIter = m_pSong->GetAllSteps(); - RString sTempStyle, sTempDiff; - for( unsigned i = 0; i < sIter.size(); i++ ) - { - if( sIter[i]->IsAutogen() ) - continue; - - // XXX: Edits are distinguished by description. - // Compare vs m_pSteps. - if( (sIter[i]->m_StepsType == GAMESTATE->m_pCurSteps[PLAYER_1]->m_StepsType) && - (sIter[i]->GetDifficulty() == GAMESTATE->m_pCurSteps[PLAYER_1]->GetDifficulty()) ) - continue; - - NoteData ndTemp; - sIter[i]->GetNoteData( ndTemp ); - NoteDataUtil::ScaleRegion( ndTemp, fScale, m_NoteFieldEdit.m_iBeginMarker, m_NoteFieldEdit.m_iEndMarker ); - sIter[i]->SetNoteData( ndTemp ); - } - */ - m_NoteFieldEdit.m_iEndMarker = iNewEndIndex; - - } - break; - case play: - ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); - m_iStartPlayingAt = m_NoteFieldEdit.m_iBeginMarker; - m_iStopPlayingAt = m_NoteFieldEdit.m_iEndMarker; - TransitionEditState( STATE_PLAYING ); - break; - case record: - ASSERT( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1 ); - m_iStartPlayingAt = m_NoteFieldEdit.m_iBeginMarker; - m_iStopPlayingAt = m_NoteFieldEdit.m_iEndMarker; - TransitionEditState( STATE_RECORDING ); - break; case insert_and_shift: NoteDataUtil::InsertRows( m_NoteDataEdit, BeatToNoteRow( GetBeat() ), BeatToNoteRow(1) ); break; @@ -3724,107 +4310,145 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns case shift_pauses_backward: GetAppropriateTiming().DeleteRows( GetRow() + 1, BeatToNoteRow(1) ); break; - case convert_to_pause: - { - ASSERT_M( m_NoteFieldEdit.m_iBeginMarker!=-1 && m_NoteFieldEdit.m_iEndMarker!=-1, "Attempted to convert beats outside the notefield to pauses!" ); - float fMarkerStart = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker) ); - float fMarkerEnd = GetAppropriateTiming().GetElapsedTimeFromBeat( NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker) ); - // The length of the stop segment we're going to create. This includes time spent in any - // stops in the selection, which will be deleted and subsumed into the new stop. - float fStopLength = fMarkerEnd - fMarkerStart; - - // be sure not to clobber the row at the start - a row at the end - // can be dropped safely, though - NoteDataUtil::DeleteRows( m_NoteDataEdit, - m_NoteFieldEdit.m_iBeginMarker + 1, - m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker - ); - GetAppropriateTiming().DeleteRows( m_NoteFieldEdit.m_iBeginMarker + 1, - m_NoteFieldEdit.m_iEndMarker-m_NoteFieldEdit.m_iBeginMarker ); - GetAppropriateTiming().SetStopAtRow( m_NoteFieldEdit.m_iBeginMarker, fStopLength ); - m_NoteFieldEdit.m_iBeginMarker = -1; - m_NoteFieldEdit.m_iEndMarker = -1; - break; - } case convert_pause_to_beat: - { - // TODO: Convert both Delays and Stops at once. - float fStopSeconds = GetAppropriateTiming().GetStopAtRow( BeatToNoteRow( GetBeat() ) ); - GetAppropriateTiming().SetStopAtBeat( GetBeat() , 0 ); + { + float fStopSeconds = GetAppropriateTiming().GetStopAtRow(GetRow()); + GetAppropriateTiming().SetStopAtBeat( GetBeat() , 0 ); - float fStopBeats = fStopSeconds * GetAppropriateTiming().GetBPMAtBeat( GetBeat() ) / 60; + float fStopBeats = fStopSeconds * GetAppropriateTiming().GetBPMAtBeat( GetBeat() ) / 60; - // don't move the step from where it is, just move everything later - NoteDataUtil::InsertRows( m_NoteDataEdit, BeatToNoteRow( GetBeat() ) + 1, BeatToNoteRow(fStopBeats) ); - GetAppropriateTiming().InsertRows( BeatToNoteRow( GetBeat() ) + 1, BeatToNoteRow(fStopBeats) ); - } + // don't move the step from where it is, just move everything later + NoteDataUtil::InsertRows( m_NoteDataEdit, GetRow() + 1, BeatToNoteRow(fStopBeats) ); + GetAppropriateTiming().InsertRows( GetRow() + 1, BeatToNoteRow(fStopBeats) ); + } + break; + case convert_delay_to_beat: + { + TimingData &timing = GetAppropriateTiming(); + float pause = timing.GetDelayAtRow(GetRow()); + timing.SetDelayAtRow(GetRow(), 0); + + float pauseBeats = pause * timing.GetBPMAtBeat(GetBeat()) / 60; + + NoteDataUtil::InsertRows(m_NoteDataEdit, GetRow(), BeatToNoteRow(pauseBeats)); + timing.InsertRows(GetRow(), BeatToNoteRow(pauseBeats)); break; + } + case last_second_at_beat: + { + TimingData &timing = GetAppropriateTiming(); + Song &s = *GAMESTATE->m_pCurSong; + s.SetSpecifiedLastSecond(timing.GetElapsedTimeFromBeat(GetBeat())); + break; + } case undo: Undo(); break; + case clear_clipboard: + { + m_Clipboard.ClearAll(); + break; + } }; if( bSaveUndo ) CheckNumberOfNotesAndUndo(); } +void ScreenEdit::HandleStepsDataChoice( StepsDataChoice c, const vector &iAnswers ) +{ + return; // nothing is done with the choices. Yet. +} + static LocalizedString ENTER_NEW_DESCRIPTION( "ScreenEdit", "Enter a new description." ); +static LocalizedString ENTER_NEW_CHART_NAME("ScreenEdit", "Enter a new chart name."); static LocalizedString ENTER_NEW_CHART_STYLE( "ScreenEdit", "Enter a new chart style." ); static LocalizedString ENTER_NEW_STEP_AUTHOR( "ScreenEdit", "Enter the author who made this step pattern." ); static LocalizedString ENTER_NEW_METER( "ScreenEdit", "Enter a new meter." ); +static LocalizedString ENTER_MIN_BPM ("ScreenEdit","Enter a new min BPM."); +static LocalizedString ENTER_MAX_BPM ("ScreenEdit","Enter a new max BPM."); void ScreenEdit::HandleStepsInformationChoice( StepsInformationChoice c, const vector &iAnswers ) { Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; Difficulty dc = (Difficulty)iAnswers[difficulty]; pSteps->SetDifficulty( dc ); + pSteps->SetDisplayBPM(static_cast(iAnswers[step_display_bpm])); switch( c ) { - case description: - ScreenTextEntry::TextEntry( - SM_None, - ENTER_NEW_DESCRIPTION, - m_pSteps->GetDescription(), - (dc == Difficulty_Edit) ? MAX_EDIT_STEPS_DESCRIPTION_LENGTH : 255, - SongUtil::ValidateCurrentStepsDescription, - ChangeDescription, - NULL - ); - break; - case chartstyle: - ScreenTextEntry::TextEntry( - SM_None, - ENTER_NEW_CHART_STYLE, - m_pSteps->GetChartStyle(), - 255, - NULL, - ChangeChartStyle, - NULL - ); - break; - case step_credit: - ScreenTextEntry::TextEntry( - SM_None, - ENTER_NEW_STEP_AUTHOR, - m_pSteps->GetCredit(), - 255, - SongUtil::ValidateCurrentStepsCredit, - ChangeStepCredit, - NULL - ); - break; - case meter: - ScreenTextEntry::TextEntry( - SM_BackFromDifficultyMeterChange, - ENTER_NEW_METER, - ssprintf("%d", m_pSteps->GetMeter()), - 4 - ); - break; + case chartname: + { + ScreenTextEntry::TextEntry(SM_None, + ENTER_NEW_CHART_NAME, + m_pSteps->GetChartName(), + MAX_STEPS_DESCRIPTION_LENGTH, + SongUtil::ValidateCurrentStepsChartName, + ChangeChartName, + NULL); + break; + } + case description: + { + ScreenTextEntry::TextEntry(SM_None, + ENTER_NEW_DESCRIPTION, + m_pSteps->GetDescription(), + MAX_STEPS_DESCRIPTION_LENGTH, + SongUtil::ValidateCurrentStepsDescription, + ChangeDescription, + NULL); + break; + } + case chartstyle: + { + ScreenTextEntry::TextEntry(SM_None, + ENTER_NEW_CHART_STYLE, + m_pSteps->GetChartStyle(), + 255, + NULL, + ChangeChartStyle, + NULL); + break; + } + case step_credit: + { + ScreenTextEntry::TextEntry(SM_None, + ENTER_NEW_STEP_AUTHOR, + m_pSteps->GetCredit(), + 255, + SongUtil::ValidateCurrentStepsCredit, + ChangeStepCredit, + NULL); + break; + } + case meter: + { + ScreenTextEntry::TextEntry(SM_BackFromDifficultyMeterChange, + ENTER_NEW_METER, + ssprintf("%d", m_pSteps->GetMeter()), + 4); + break; + } + case step_min_bpm: + { + ScreenTextEntry::TextEntry(SM_None, ENTER_MIN_BPM, + ssprintf("%.6f", pSteps->GetMinBPM()), 20, + ScreenTextEntry::FloatValidate, + ChangeStepsMinBPM, NULL); + break; + } + case step_max_bpm: + { + ScreenTextEntry::TextEntry(SM_None, ENTER_MAX_BPM, + ssprintf("%.6f", pSteps->GetMaxBPM()), 20, + ScreenTextEntry::FloatValidate, + ChangeStepsMaxBPM, NULL); + break; + } default: break; } + SetDirty(true); } static LocalizedString ENTER_MAIN_TITLE ("ScreenEdit","Enter a new main title."); @@ -3835,11 +4459,9 @@ static LocalizedString ENTER_CREDIT ("ScreenEdit","Enter a new credit."); static LocalizedString ENTER_MAIN_TITLE_TRANSLIT ("ScreenEdit","Enter a new main title transliteration."); static LocalizedString ENTER_SUB_TITLE_TRANSLIT ("ScreenEdit","Enter a new sub title transliteration."); static LocalizedString ENTER_ARTIST_TRANSLIT ("ScreenEdit","Enter a new artist transliteration."); -static LocalizedString ENTER_LAST_BEAT_HINT ("ScreenEdit","Enter a new last beat hint."); +static LocalizedString ENTER_LAST_SECOND_HINT ("ScreenEdit","Enter a new last second hint."); static LocalizedString ENTER_PREVIEW_START ("ScreenEdit","Enter a new preview start."); static LocalizedString ENTER_PREVIEW_LENGTH ("ScreenEdit","Enter a new preview length."); -static LocalizedString ENTER_MIN_BPM ("ScreenEdit","Enter a new min BPM."); -static LocalizedString ENTER_MAX_BPM ("ScreenEdit","Enter a new max BPM."); void ScreenEdit::HandleSongInformationChoice( SongInformationChoice c, const vector &iAnswers ) { Song* pSong = GAMESTATE->m_pCurSong; @@ -3871,33 +4493,34 @@ void ScreenEdit::HandleSongInformationChoice( SongInformationChoice c, const vec case artist_transliteration: ScreenTextEntry::TextEntry( SM_None, ENTER_ARTIST_TRANSLIT, pSong->m_sArtistTranslit, 100, NULL, ChangeArtistTranslit, NULL ); break; - case last_beat_hint: - ScreenTextEntry::TextEntry( SM_None, ENTER_LAST_BEAT_HINT, - ssprintf("%.5f", pSong->m_fSpecifiedLastBeat), 20, - ScreenTextEntry::FloatValidate, ChangeLastBeatHint, NULL ); + case last_second_hint: + ScreenTextEntry::TextEntry( SM_None, ENTER_LAST_SECOND_HINT, + ssprintf("%.6f", pSong->GetSpecifiedLastSecond()), 20, + ScreenTextEntry::FloatValidate, ChangeLastSecondHint, NULL ); break; case preview_start: ScreenTextEntry::TextEntry( SM_None, ENTER_PREVIEW_START, - ssprintf("%.5f", pSong->m_fMusicSampleStartSeconds), 20, + ssprintf("%.6f", pSong->m_fMusicSampleStartSeconds), 20, ScreenTextEntry::FloatValidate, ChangePreviewStart, NULL ); break; case preview_length: ScreenTextEntry::TextEntry( SM_None, ENTER_PREVIEW_LENGTH, - ssprintf("%.5f", pSong->m_fMusicSampleLengthSeconds), 20, + ssprintf("%.6f", pSong->m_fMusicSampleLengthSeconds), 20, ScreenTextEntry::FloatValidate, ChangePreviewLength, NULL ); break; case min_bpm: ScreenTextEntry::TextEntry( SM_None, ENTER_MIN_BPM, - ssprintf("%.5f", pSong->m_fSpecifiedBPMMin), 20, + ssprintf("%.6f", pSong->m_fSpecifiedBPMMin), 20, ScreenTextEntry::FloatValidate, ChangeMinBPM, NULL ); break; case max_bpm: ScreenTextEntry::TextEntry( SM_None, ENTER_MAX_BPM, - ssprintf("%.5f", pSong->m_fSpecifiedBPMMax), 20, + ssprintf("%.6f", pSong->m_fSpecifiedBPMMax), 20, ScreenTextEntry::FloatValidate, ChangeMaxBPM, NULL ); break; default: break; }; + SetDirty(true); } @@ -3923,7 +4546,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice DEFAULT_FAIL( c ); case beat_0_offset: ScreenTextEntry::TextEntry( SM_None, ENTER_BEAT_0_OFFSET, - ssprintf("%.5f", GetAppropriateTiming().m_fBeat0OffsetInSeconds), 20, + ssprintf("%.6f", GetAppropriateTiming().m_fBeat0OffsetInSeconds), 20, ScreenTextEntry::FloatValidate, ChangeBeat0Offset, NULL ); break; case bpm: @@ -3952,11 +4575,11 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice break; case time_signature: { - TimeSignatureSegment &ts = GetAppropriateTiming().GetTimeSignatureSegmentAtBeat( GetBeat() ); + TimeSignatureSegment * ts = GetAppropriateTiming().GetTimeSignatureSegmentAtBeat( GetBeat() ); ScreenTextEntry::TextEntry( SM_BackFromTimeSignatureChange, ENTER_TIME_SIGNATURE_VALUE, - ssprintf( "%d/%d", ts.GetNum(), ts.GetDen() ), + ssprintf( "%d/%d", ts->GetNum(), ts->GetDen() ), 8 ); break; @@ -3970,13 +4593,16 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ); break; case combo: - ScreenTextEntry::TextEntry( - SM_BackFromComboChange, - ENTER_COMBO_VALUE, - ssprintf( "%d", GetAppropriateTiming().GetComboAtBeat( GetBeat() ) ), - 4 - ); - break; + { + ComboSegment *cs = GetAppropriateTiming().GetComboSegmentAtBeat(GetBeat()); + ScreenTextEntry::TextEntry(SM_BackFromComboChange, + ENTER_COMBO_VALUE, + ssprintf( "%d/%d", + cs->GetCombo(), + cs->GetMissCombo()), + 7); + break; + } case label: ScreenTextEntry::TextEntry( SM_BackFromLabelChange, @@ -3989,7 +4615,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromWarpChange, ENTER_WARP_VALUE, - ssprintf( "%.4f", GetAppropriateTiming().GetWarpAtBeat( GetBeat() ) ), + ssprintf( "%.6f", GetAppropriateTiming().GetWarpAtBeat( GetBeat() ) ), 10 ); break; @@ -3997,7 +4623,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromSpeedPercentChange, ENTER_SPEED_PERCENT_VALUE, - ssprintf( "%.5f", GetAppropriateTiming().GetSpeedSegmentAtBeat( GetBeat() ).GetRatio() ), + ssprintf( "%.6f", GetAppropriateTiming().GetSpeedSegmentAtBeat( GetBeat() )->GetRatio() ), 10 ); break; @@ -4005,7 +4631,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromScrollChange, ENTER_SCROLL_VALUE, - ssprintf( "%.5f", GetAppropriateTiming().GetScrollSegmentAtBeat( GetBeat() ).GetRatio() ), + ssprintf( "%.6f", GetAppropriateTiming().GetScrollSegmentAtBeat( GetBeat() )->GetRatio() ), 10 ); break; @@ -4013,7 +4639,7 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromSpeedWaitChange, ENTER_SPEED_WAIT_VALUE, - ssprintf( "%.5f", GetAppropriateTiming().GetSpeedSegmentAtBeat( GetBeat() ).GetLength() ), + ssprintf( "%.6f", GetAppropriateTiming().GetSpeedSegmentAtBeat( GetBeat() )->GetLength() ), 10 ); break; @@ -4033,11 +4659,29 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice ScreenTextEntry::TextEntry( SM_BackFromFakeChange, ENTER_FAKE_VALUE, - ssprintf("%.5f", GetAppropriateTiming().GetFakeAtBeat( GetBeat() ) ), + ssprintf("%.6f", GetAppropriateTiming().GetFakeAtBeat( GetBeat() ) ), 10 ); break; } + case copy_timing: + { + clipboardTiming = GetAppropriateTiming(); + break; + } + case paste_timing: + { + if (GAMESTATE->m_bIsUsingStepTiming) + { + GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing = clipboardTiming; + } + else + { + GAMESTATE->m_pCurSong->m_SongTiming = clipboardTiming; + } + SetDirty(true); + break; + } case erase_step_timing: ScreenPrompt::Prompt( SM_DoEraseStepTiming, CONFIRM_TIMING_ERASE , PROMPT_YES_NO, ANSWER_NO ); break; @@ -4153,6 +4797,27 @@ void ScreenEdit::SetupCourseAttacks() FOREACH( Attack, Attacks, attack ) GAMESTATE->m_pPlayerState[PLAYER_1]->LaunchAttack( *attack ); } + else + { + const PlayerOptions &p = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.GetCurrent(); + if (GAMESTATE->m_pCurSong && p.m_fNoAttack == 0 && p.m_fRandAttack == 0 ) + { + AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ? + GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks : + GAMESTATE->m_pCurSong->m_Attacks; + + if (attacks.size() > 0) + { + FOREACH(Attack, attacks, attack) + { + float fBeat = GetAppropriateTiming().GetBeatFromElapsedTime(attack->fStartSecond); + if (fBeat >= GetBeat()) + GAMESTATE->m_pPlayerState[PLAYER_1]->LaunchAttack( *attack ); + } + } + } + } + GAMESTATE->m_pPlayerState[PLAYER_1]->RebuildPlayerOptionsFromActiveAttacks(); } @@ -4245,8 +4910,8 @@ void ScreenEdit::CheckNumberOfNotesAndUndo() if( EDIT_MODE.GetValue() != EditMode_Home ) return; - TimeSignatureSegment &curTime = GAMESTATE->m_pCurSong->m_SongTiming.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat ); - int rowsPerMeasure = curTime.GetDen() * curTime.GetNum(); + TimeSignatureSegment * curTime = GAMESTATE->m_pCurSong->m_SongTiming.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_pPlayerState[PLAYER_1]->m_Position.m_fSongBeat ); + int rowsPerMeasure = curTime->GetDen() * curTime->GetNum(); for( int row=0; row<=m_NoteDataEdit.GetLastRow(); row+=rowsPerMeasure ) { @@ -4292,14 +4957,15 @@ float ScreenEdit::GetMaximumBeatForNewNote() const case EditMode_CourseMods: case EditMode_Home: { - float fEndBeat = GAMESTATE->m_pCurSong->m_fLastBeat; + Song &s = *GAMESTATE->m_pCurSong; + float fEndBeat = s.GetLastBeat(); /* 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. */ - TimingData &songTiming = GAMESTATE->m_pCurSong->m_SongTiming; + TimingData &timing = s.m_SongTiming; float playerBeat = GetAppropriatePosition().m_fSongBeat; - int beatsPerMeasure = songTiming.GetTimeSignatureSegmentAtBeat( playerBeat ).GetNum(); + int beatsPerMeasure = timing.GetTimeSignatureSegmentAtBeat( playerBeat )->GetNum(); fEndBeat += beatsPerMeasure; fEndBeat = ftruncf( fEndBeat, (float)beatsPerMeasure ); @@ -4314,7 +4980,7 @@ float ScreenEdit::GetMaximumBeatForMoving() const { float fEndBeat = GetMaximumBeatForNewNote(); - /* Jump to GetLastBeat even if it's past m_pCurSong->m_fLastBeat + /* Jump to GetLastBeat even if it's past the song's last beat * 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. */ @@ -4459,7 +5125,7 @@ void ScreenEdit::DoHelp() RString sDescription = THEME->GetString( "EditHelpDescription", hl.szEnglishDescription ); // TODO: Better way of hiding routine only key on non-routine. - if( sDescription.Left(13) == "Switch player" && m_InputPlayerNumber == PLAYER_INVALID ) + if( hl.veb[0] == EDIT_BUTTON_SWITCH_PLAYERS && m_InputPlayerNumber == PLAYER_INVALID ) { continue; } diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h index 2b92f8bbd5..f2e8c66212 100644 --- a/src/ScreenEdit.h +++ b/src/ScreenEdit.h @@ -60,10 +60,15 @@ enum EditButton EDIT_BUTTON_CYCLE_TAP_LEFT, /**< Rotate the available tap notes once to the "left". */ EDIT_BUTTON_CYCLE_TAP_RIGHT, /**< Rotate the available tap notes once to the "right". */ + EDIT_BUTTON_CYCLE_SEGMENT_LEFT, /**< Select one segment to the left for jumping. */ + EDIT_BUTTON_CYCLE_SEGMENT_RIGHT, /**< Select one segment to the right for jumping. */ + EDIT_BUTTON_SCROLL_UP_LINE, EDIT_BUTTON_SCROLL_UP_PAGE, + EDIT_BUTTON_SCROLL_UP_TS, EDIT_BUTTON_SCROLL_DOWN_LINE, EDIT_BUTTON_SCROLL_DOWN_PAGE, + EDIT_BUTTON_SCROLL_DOWN_TS, EDIT_BUTTON_SCROLL_NEXT_MEASURE, EDIT_BUTTON_SCROLL_PREV_MEASURE, EDIT_BUTTON_SCROLL_HOME, @@ -71,8 +76,8 @@ enum EditButton EDIT_BUTTON_SCROLL_NEXT, EDIT_BUTTON_SCROLL_PREV, - EDIT_BUTTON_LABEL_NEXT, /**< Jump to the start of the next label downward. */ - EDIT_BUTTON_LABEL_PREV, /**< Jump to the start of the previous label upward. */ + EDIT_BUTTON_SEGMENT_NEXT, /**< Jump to the start of the next segment downward. */ + EDIT_BUTTON_SEGMENT_PREV, /**< Jump to the start of the previous segment upward. */ // These are modifiers to EDIT_BUTTON_SCROLL_*. EDIT_BUTTON_SCROLL_SELECT, @@ -87,13 +92,18 @@ enum EditButton EDIT_BUTTON_OPEN_EDIT_MENU, EDIT_BUTTON_OPEN_TIMING_MENU, + EDIT_BUTTON_OPEN_ALTER_MENU, EDIT_BUTTON_OPEN_AREA_MENU, EDIT_BUTTON_OPEN_BGCHANGE_LAYER1_MENU, EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU, EDIT_BUTTON_OPEN_COURSE_MENU, EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU, + + EDIT_BUTTON_OPEN_STEP_ATTACK_MENU, /**< Open up the Step Attacks menu. */ + EDIT_BUTTON_ADD_STEP_MODS, /**< Add a mod attack to the row. */ + EDIT_BUTTON_OPEN_INPUT_HELP, - + EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP, EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP_AND_GENRE, @@ -209,7 +219,12 @@ public: virtual void PushSelf( lua_State *L ); protected: - virtual ScreenType GetScreenType() const { return m_EditState==STATE_PLAYING ? gameplay : ScreenWithMenuElements::GetScreenType(); } + virtual ScreenType GetScreenType() const + { + return m_EditState==STATE_PLAYING ? + gameplay : + ScreenWithMenuElements::GetScreenType(); + } void TransitionEditState( EditState em ); void ScrollTo( float fDestinationBeat ); @@ -251,6 +266,9 @@ protected: BitmapText m_textInputTips; + /** @brief The player options before messing with attacks. */ + ModsGroup originalPlayerOptions; + /** * @brief Keep a backup of the present Step TimingData when * entering a playing or recording state. @@ -258,9 +276,18 @@ protected: * This is mainly to allow playing a chart with Song Timing. */ TimingData backupStepTiming; + /** + * @brief Have a backup of the TimingData of the player's choice. + * + * This will be used for copying and pasting as required. */ + TimingData clipboardTiming; + /** @brief The current TapNote that would be inserted. */ TapNote m_selectedTap; + /** @brief The type of segment users will jump back and forth between. */ + TimingSegmentType currentCycleSegment; + void UpdateTextInfo(); BitmapText m_textInfo; // status information that changes bool m_bTextInfoNeedsUpdate; @@ -268,7 +295,8 @@ protected: BitmapText m_textPlayRecordHelp; // keep track of where we are and what we're doing - float m_fTrailingBeat; // this approaches GAMESTATE->m_fSongBeat, which is the actual beat + float m_fTrailingBeat; + // the above approaches GAMESTATE->m_fSongBeat, which is the actual beat /** * @brief The location we were at when shift was pressed. * @@ -355,6 +383,7 @@ public: options, /**< Modify the PlayerOptions and SongOptions. */ edit_song_info, /**< Edit some general information about the song. */ edit_timing_data, /**< Edit the chart's timing data. */ + view_steps_data, /**< View step statistics. */ play_preview_music, /**< Play the song's preview music. */ exit, save_on_exit, @@ -365,31 +394,61 @@ public: void HandleMainMenuChoice( MainMenuChoice c ) { const vector v; HandleMainMenuChoice( c, v ); } MainMenuChoice m_CurrentAction; + /** @brief How does one alter a selection of NoteData? */ + enum AlterMenuChoice + { + cut, /**< Cut the notes. */ + copy, /**< Copy the notes. */ + clear, /**< Erase the notes, without putting them in the clipboard. */ + quantize, /**< Sync the notes to an exact level. */ + turn, /**< Rotate the notes. */ + transform, /**< Activate a specific mod. */ + alter, /**< Perform other transformations. */ + tempo, /**< Modify the tempo of the notes. */ + play, /**< Play the notes in the range. */ + record, /**< Record new notes in the range. */ + preview_designation, /**< Set the area as the music preview. */ + convert_to_pause, /**< Convert the range into a StopSegment. */ + convert_to_delay, /**< Convert the range into a DelaySegment. */ + convert_to_warp, /**< Convert the range into a WarpSegment. */ + convert_to_fake, /**< Convert the range into a FakeSegment. */ + convert_to_attack, /**< Convert the range into an Attack. */ + routine_invert_notes, /**< Switch which player hits the note. */ + routine_mirror_1_to_2, /**< Mirror Player 1's notes for Player 2. */ + routine_mirror_2_to_1, /**< Mirror Player 2's notes for Player 1. */ + NUM_ALTER_MENU_CHOICES + + }; + enum AreaMenuChoice { - cut, - copy, paste_at_current_beat, paste_at_begin_marker, - clear, - quantize, - turn, - transform, - alter, - tempo, - play, - record, insert_and_shift, delete_and_shift, shift_pauses_forward, shift_pauses_backward, - convert_to_pause, convert_pause_to_beat, + convert_delay_to_beat, + last_second_at_beat, undo, + clear_clipboard, NUM_AREA_MENU_CHOICES }; + void HandleAlterMenuChoice(AlterMenuChoice c, + const vector &iAnswers, + bool bAllowUndo = true); + void HandleAlterMenuChoice(AlterMenuChoice c, + bool bAllowUndo = true) + { + const vector v; HandleAlterMenuChoice(c, v, bAllowUndo); + } + void HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAnswers, bool bAllowUndo = true ); - void HandleAreaMenuChoice( AreaMenuChoice c, bool bAllowUndo = true ) { const vector v; HandleAreaMenuChoice( c, v, bAllowUndo ); } + void HandleAreaMenuChoice( AreaMenuChoice c, bool bAllowUndo = true ) + { + const vector v; HandleAreaMenuChoice( c, v, bAllowUndo ); + } /** @brief How should the selected notes be transformed? */ enum TurnType { @@ -449,26 +508,39 @@ public: enum StepsInformationChoice { - difficulty, - meter, + difficulty, /**< What is the difficulty of this chart? */ + meter, /**< What is the numerical rating of this chart? */ + predict_meter, /**< What does the game think this chart's rating should be? */ + chartname, /**< What is the name of this chart? */ description, /**< What is the description of this chart? */ chartstyle, /**< How is this chart meant to be played? */ step_credit, /**< Who wrote this individual chart? */ - predict_meter, /**< What does the game think this chart's rating should be? */ + step_display_bpm, + step_min_bpm, + step_max_bpm, + NUM_STEPS_INFORMATION_CHOICES + }; + void HandleStepsInformationChoice( StepsInformationChoice c, const vector &iAnswers ); + + enum StepsDataChoice + { tap_notes, jumps, hands, quads, holds, mines, + rolls, + lifts, + fakes, stream, voltage, air, freeze, chaos, - NUM_STEPS_INFORMATION_CHOICES + NUM_STEPS_DATA_CHOICES }; - void HandleStepsInformationChoice( StepsInformationChoice c, const vector &iAnswers ); + void HandleStepsDataChoice(StepsDataChoice c, const vector &answers); enum SongInformationChoice { @@ -480,7 +552,7 @@ public: main_title_transliteration, sub_title_transliteration, artist_transliteration, - last_beat_hint, + last_second_hint, preview_start, preview_length, display_bpm, @@ -507,11 +579,14 @@ public: speed_mode, scroll, fake, + copy_timing, + paste_timing, erase_step_timing, NUM_TIMING_DATA_INFORMATION_CHOICES }; - void HandleTimingDataInformationChoice ( TimingDataInformationChoice c, const vector &iAnswers ); + void HandleTimingDataInformationChoice (TimingDataInformationChoice c, + const vector &iAnswers ); enum BGChangeChoice { @@ -562,6 +637,14 @@ public: remove, NUM_CourseAttackChoice }; + + enum StepAttackChoice + { + sa_duration, + sa_set_mods, + sa_remove, + NUM_StepAttackChoice + }; void InitEditMappings(); EditButton DeviceToEdit( const DeviceInput &DeviceI ) const; @@ -581,7 +664,9 @@ public: MapEditButtonToMenuButton m_RecordPausedMappingsMenuButton; void MakeFilteredMenuDef( const MenuDef* pDef, MenuDef &menu ); - void EditMiniMenu( const MenuDef* pDef, ScreenMessage SM_SendOnOK = SM_None, ScreenMessage SM_SendOnCancel = SM_None ); + void EditMiniMenu(const MenuDef* pDef, + ScreenMessage SM_SendOnOK = SM_None, + ScreenMessage SM_SendOnCancel = SM_None ); private: /** * @brief Retrieve the appropriate TimingData based on GAMESTATE. diff --git a/src/ScreenEditMenu.cpp b/src/ScreenEditMenu.cpp index 1bf4997aea..37aba49e5c 100644 --- a/src/ScreenEditMenu.cpp +++ b/src/ScreenEditMenu.cpp @@ -297,7 +297,7 @@ void ScreenEditMenu::MenuStart( const InputEventPlus &input ) SM_BackFromEditDescription, ENTER_EDIT_DESCRIPTION, GAMESTATE->m_pCurSteps[0]->GetDescription(), - MAX_EDIT_STEPS_DESCRIPTION_LENGTH, + MAX_STEPS_DESCRIPTION_LENGTH, SongUtil::ValidateCurrentStepsDescription, SetCurrentStepsDescription, DeleteCurrentSteps ); diff --git a/src/ScreenEvaluation.cpp b/src/ScreenEvaluation.cpp index 1f87fe4b97..654f1d0bb5 100644 --- a/src/ScreenEvaluation.cpp +++ b/src/ScreenEvaluation.cpp @@ -99,7 +99,7 @@ void ScreenEvaluation::Init() ss.m_Stage = Stage_1st; enum_add( ss.m_Stage, rand()%3 ); ss.m_EarnedExtraStage = (EarnedExtraStage)(rand() % NUM_EarnedExtraStage); - GAMESTATE->m_MasterPlayerNumber = PLAYER_1; + GAMESTATE->SetMasterPlayerNumber(PLAYER_1); GAMESTATE->m_pCurSong.Set( SONGMAN->GetRandomSong() ); ss.m_vpPlayedSongs.push_back( GAMESTATE->m_pCurSong ); ss.m_vpPossibleSongs.push_back( GAMESTATE->m_pCurSong ); @@ -635,7 +635,7 @@ void ScreenEvaluation::Init() { case PLAY_MODE_BATTLE: { - bool bWon = GAMESTATE->GetStageResult(GAMESTATE->m_MasterPlayerNumber) == RESULT_WIN; + bool bWon = GAMESTATE->GetStageResult(GAMESTATE->GetMasterPlayerNumber()) == RESULT_WIN; if( bWon ) SOUND->PlayOnceFromDir( ANNOUNCER->GetPathTo("evaluation win") ); else diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index ef55cd02c7..d0ac5a1cfd 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -393,9 +393,33 @@ void ScreenGameplay::Init() /* Called once per stage (single song or single course). */ GAMESTATE->BeginStage(); + int player = 1; + FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi ) + { + unsigned int count = pi->m_vpStepsQueue.size(); + + for (unsigned int i = 0; i < count; i++) + { + Steps *curSteps = pi->m_vpStepsQueue[i]; + if (curSteps->IsNoteDataEmpty()) + { + if (curSteps->GetNoteDataFromSimfile()) + { + LOG->Trace("Notes should be loaded for player %d", player); + } + else + { + LOG->Trace("Error loading notes for player %d", player); + } + } + } + player++; + } + if(!GAMESTATE->IsCourseMode() && !GAMESTATE->m_bDemonstrationOrJukebox) { // fill in difficulty of CPU players with that of the first human player + // this should not need to worry about step content. FOREACH_PotentialCpuPlayer(p) GAMESTATE->m_pCurSteps[p].Set( GAMESTATE->m_pCurSteps[ GAMESTATE->GetFirstHumanPlayer() ] ); @@ -776,7 +800,7 @@ void ScreenGameplay::InitSongQueues() ASSERT( pCourse ); m_apSongsQueue.clear(); - PlayerNumber pnMaster = GAMESTATE->m_MasterPlayerNumber; + PlayerNumber pnMaster = GAMESTATE->GetMasterPlayerNumber(); Trail *pTrail = GAMESTATE->m_pCurTrail[pnMaster]; ASSERT( pTrail ); FOREACH_CONST( TrailEntry, pTrail->m_vEntries, e ) @@ -820,11 +844,12 @@ void ScreenGameplay::InitSongQueues() { Steps *pSteps = GAMESTATE->m_pCurSteps[ pi->GetStepsAndTrailIndex() ]; pi->m_vpStepsQueue.push_back( pSteps ); - - if( pi->GetPlayerState()->m_PlayerOptions.GetCurrent().m_fSongAttack != 0 && - GAMESTATE->m_pCurSong->m_Attacks.size() > 0 ) + const PlayerOptions &p = pi->GetPlayerState()->m_PlayerOptions.GetCurrent(); + + if (p.m_fNoAttack == 0 && p.m_fRandAttack == 0 && + pSteps->m_Attacks.size() > 0 ) { - pi->m_asModifiersQueue.push_back( GAMESTATE->m_pCurSong->m_Attacks ); + pi->m_asModifiersQueue.push_back( pSteps->m_Attacks ); } else { @@ -1227,7 +1252,7 @@ void ScreenGameplay::LoadNextSong() FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi ) { RageSoundReader *pPlayerSound = m_AutoKeysounds.GetPlayerSound(pi->m_pn); - if( pPlayerSound == NULL && pi->m_pn == GAMESTATE->m_MasterPlayerNumber ) + if( pPlayerSound == NULL && pi->m_pn == GAMESTATE->GetMasterPlayerNumber() ) pPlayerSound = m_AutoKeysounds.GetSharedSound(); pi->m_SoundEffectControl.SetSoundReader( pPlayerSound ); } @@ -1328,8 +1353,7 @@ void ScreenGameplay::StartPlayingSong( float fMinTimeToNotes, float fMinTimeToMu p.StopMode = RageSoundParams::M_CONTINUE; { - const float fFirstBeat = GAMESTATE->m_pCurSong->m_fFirstBeat; - const float fFirstSecond = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( fFirstBeat ); + const float fFirstSecond = GAMESTATE->m_pCurSong->GetFirstSecond(); float fStartDelay = fMinTimeToNotes - fFirstSecond; fStartDelay = max( fStartDelay, fMinTimeToMusic ); p.m_StartSecond = -fStartDelay; @@ -1393,7 +1417,7 @@ void ScreenGameplay::PlayTicks() /* TODO: Allow all players to have ticks. Not as simple as it looks. * If a loop takes place, it could make one player's ticks come later * than intended. Any help here would be appreciated. -Wolfman2000 */ - Player &player = *m_vPlayerInfo[0].m_pPlayer; + Player &player = *m_vPlayerInfo[GAMESTATE->GetMasterPlayerNumber()].m_pPlayer; const NoteData &nd = player.GetNoteData(); m_GameplayAssist.PlayTicks( nd, player.GetPlayerState() ); } @@ -1411,8 +1435,8 @@ void ScreenGameplay::PlayAnnouncer( RString type, float fSeconds ) /* Don't play before the first beat, or after we're finished. */ if( m_DancingState != STATE_DANCING ) return; - if( GAMESTATE->m_pCurSong == NULL || // this will be true on ScreenDemonstration sometimes - GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat ) + if(GAMESTATE->m_pCurSong == NULL || // this will be true on ScreenDemonstration sometimes + GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->GetFirstBeat()) return; if( m_fTimeSinceLastDancingComment < fSeconds ) @@ -1487,7 +1511,7 @@ bool ScreenGameplay::AllAreFailing() void ScreenGameplay::GetMusicEndTiming( float &fSecondsToStartFadingOutMusic, float &fSecondsToStartTransitioningOut ) { - float fLastStepSeconds = GAMESTATE->m_pCurSong->m_SongTiming.GetElapsedTimeFromBeat( GAMESTATE->m_pCurSong->m_fLastBeat ); + float fLastStepSeconds = GAMESTATE->m_pCurSong->GetLastSecond(); fLastStepSeconds += Player::GetMaxStepDistanceSeconds(); float fTransitionLength; @@ -1695,7 +1719,10 @@ void ScreenGameplay::Update( float fDeltaTime ) // update fGameplaySeconds STATSMAN->m_CurStageStats.m_fGameplaySeconds += fUnscaledDeltaTime; - if( GAMESTATE->m_Position.m_fSongBeat >= GAMESTATE->m_pCurSong->m_fFirstBeat && GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fLastBeat ) + float curBeat = GAMESTATE->m_Position.m_fSongBeat; + Song &s = *GAMESTATE->m_pCurSong; + + if( curBeat >= s.GetFirstBeat() && curBeat < s.GetLastBeat() ) { STATSMAN->m_CurStageStats.m_fStepsSeconds += fUnscaledDeltaTime; @@ -1781,7 +1808,22 @@ void ScreenGameplay::Update( float fDeltaTime ) // update give up bool bGiveUpTimerFired = !m_GiveUpTimer.IsZero() && m_GiveUpTimer.Ago() > 2.5f; - bool bAllHumanHaveBigMissCombo = FAIL_ON_MISS_COMBO.GetValue() != -1 && STATSMAN->m_CurStageStats.GetMinimumMissCombo() >= FAIL_ON_MISS_COMBO; + + + bool bAllHumanHaveBigMissCombo = true; + FOREACH_EnabledPlayerNumberInfo( m_vPlayerInfo, pi ) + { + if (pi->GetPlayerState()->m_PlayerOptions.GetCurrent().m_FailType == PlayerOptions::FAIL_OFF || + pi->GetPlayerState()->m_HealthState < HealthState_Dead ) + { + bAllHumanHaveBigMissCombo = false; + break; + } + } + if (bAllHumanHaveBigMissCombo) // possible to get in here. + { + bAllHumanHaveBigMissCombo = FAIL_ON_MISS_COMBO.GetValue() != -1 && STATSMAN->m_CurStageStats.GetMinimumMissCombo() >= FAIL_ON_MISS_COMBO; + } if( bGiveUpTimerFired || bAllHumanHaveBigMissCombo ) { STATSMAN->m_CurStageStats.m_bGaveUp = true; @@ -1976,7 +2018,8 @@ void ScreenGameplay::UpdateLights() } // Before the first beat of the song, all cabinet lights solid on (except for menu buttons). - bool bOverrideCabinetBlink = (GAMESTATE->m_Position.m_fSongBeat < GAMESTATE->m_pCurSong->m_fFirstBeat); + Song &s = *GAMESTATE->m_pCurSong; + bool bOverrideCabinetBlink = (GAMESTATE->m_Position.m_fSongBeat < s.GetFirstBeat()); FOREACH_CabinetLight( cl ) bBlinkCabinetLight[cl] |= bOverrideCabinetBlink; @@ -2294,12 +2337,14 @@ void ScreenGameplay::SaveStats() RadarValues rv; PlayerStageStats &pss = *pi->GetPlayerStageStats(); const NoteData &nd = pi->m_pPlayer->GetNoteData(); + PlayerNumber pn = pi->m_pn; + GAMESTATE->SetProcessedTimingData(&GAMESTATE->m_pCurSteps[pn]->m_Timing); NoteDataUtil::CalculateRadarValues( nd, fMusicLen, rv ); pss.m_radarPossible += rv; - NoteDataWithScoring::GetActualRadarValues( nd, pss, fMusicLen, rv ); pss.m_radarActual += rv; + GAMESTATE->SetProcessedTimingData(NULL); } } diff --git a/src/ScreenGameplayShared.cpp b/src/ScreenGameplayShared.cpp index b7f179f078..21b656648e 100644 --- a/src/ScreenGameplayShared.cpp +++ b/src/ScreenGameplayShared.cpp @@ -11,7 +11,7 @@ REGISTER_SCREEN_CLASS( ScreenGameplayShared ); void ScreenGameplayShared::FillPlayerInfo( vector &vPlayerInfoOut ) { - const PlayerNumber master = GAMESTATE->m_MasterPlayerNumber; + const PlayerNumber master = GAMESTATE->GetMasterPlayerNumber(); const PlayerNumber other = (master == PLAYER_1? PLAYER_2:PLAYER_1); /* The master player is where all of the real work takes place. The other player exists @@ -23,7 +23,7 @@ void ScreenGameplayShared::FillPlayerInfo( vector &vPlayerInfoOut ) PlayerInfo &ScreenGameplayShared::GetPlayerInfoForInput( const InputEventPlus& iep ) { - return m_vPlayerInfo[GAMESTATE->m_MasterPlayerNumber]; + return m_vPlayerInfo[GAMESTATE->GetMasterPlayerNumber()]; } /* diff --git a/src/ScreenGameplaySyncMachine.cpp b/src/ScreenGameplaySyncMachine.cpp index 325b3a2e87..3f72cd1976 100644 --- a/src/ScreenGameplaySyncMachine.cpp +++ b/src/ScreenGameplaySyncMachine.cpp @@ -21,10 +21,12 @@ void ScreenGameplaySyncMachine::Init() RString sFile = THEME->GetPathO("ScreenGameplaySyncMachine","music"); // Allow themers to use either a .ssc or .sm file for this. -aj + SSCLoader loaderSSC; + SMLoader loaderSM; if(sFile.Right(4) == ".ssc") - SSCLoader::LoadFromSSCFile( sFile, m_Song ); + loaderSSC.LoadFromSimfile( sFile, m_Song ); else - SMLoader::LoadFromSMFile( sFile, m_Song ); + loaderSM.LoadFromSimfile( sFile, m_Song ); m_Song.SetSongDir( Dirname(sFile) ); m_Song.TidyUpData(); diff --git a/src/ScreenHighScores.cpp b/src/ScreenHighScores.cpp index 1f5034b134..97ea53f980 100644 --- a/src/ScreenHighScores.cpp +++ b/src/ScreenHighScores.cpp @@ -6,6 +6,9 @@ #include "RageLog.h" #include "UnlockManager.h" +RString COLUMN_DIFFICULTY_NAME( size_t i ); +RString COLUMN_STEPS_TYPE_NAME( size_t i ); + static const char *HighScoresTypeNames[] = { "AllSteps", "NonstopCourses", diff --git a/src/ScreenHowToPlay.cpp b/src/ScreenHowToPlay.cpp index 81e8d73d6b..bb5e021db2 100644 --- a/src/ScreenHowToPlay.cpp +++ b/src/ScreenHowToPlay.cpp @@ -135,10 +135,12 @@ void ScreenHowToPlay::Init() // Allow themers to use either a .ssc or .sm file for this. -aj RString sStepsPath = THEME->GetPathO(m_sName, "steps"); + SSCLoader loaderSSC; + SMLoader loaderSM; if( sStepsPath.Right(4) == ".ssc" ) - SSCLoader::LoadFromSSCFile( sStepsPath, m_Song, false ); + loaderSSC.LoadFromSimfile( sStepsPath, m_Song, false ); else - SMLoader::LoadFromSMFile( sStepsPath, m_Song, false ); + loaderSM.LoadFromSimfile( sStepsPath, m_Song, false ); m_Song.AddAutoGenNotes(); const Style* pStyle = GAMESTATE->GetCurrentStyle(); @@ -172,7 +174,7 @@ void ScreenHowToPlay::Init() // Don't show judgment PO_GROUP_ASSIGN( GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions, ModsLevel_Stage, m_fBlind, 1.0f ); - GAMESTATE->m_MasterPlayerNumber = PLAYER_1; + GAMESTATE->SetMasterPlayerNumber(PLAYER_1); GAMESTATE->m_bDemonstrationOrJukebox = true; } diff --git a/src/ScreenInstallOverlay.cpp b/src/ScreenInstallOverlay.cpp index b1037fce23..6882c1be0c 100644 --- a/src/ScreenInstallOverlay.cpp +++ b/src/ScreenInstallOverlay.cpp @@ -41,6 +41,9 @@ struct PlayAfterLaunchInfo } }; +void InstallSmzipOsArg( const RString &sOsZipFile, PlayAfterLaunchInfo &out ); +PlayAfterLaunchInfo DoInstalls( CommandLineActions::CommandLineArgs args ); + static void Parse( const RString &sDir, PlayAfterLaunchInfo &out ) { vector vsDirParts; @@ -360,7 +363,7 @@ void ScreenInstallOverlay::Update( float fDeltaTime ) } if( playAfterLaunchInfo.bAnySongChanged ) - SONGMAN->Reload( false, NULL ); + SONGMAN->Reload( false ); if( !playAfterLaunchInfo.sSongDir.empty() ) { @@ -375,7 +378,7 @@ void ScreenInstallOverlay::Update( float fDeltaTime ) GAMEMAN->GetStylesForGame( GAMESTATE->m_pCurGame, vpStyle, false ); GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR ); GAMESTATE->m_bSideIsJoined[0] = true; - GAMESTATE->m_MasterPlayerNumber = PLAYER_1; + GAMESTATE->SetMasterPlayerNumber(PLAYER_1); GAMESTATE->m_pCurStyle.Set( vpStyle[0] ); GAMESTATE->m_pCurSong.Set( pSong ); GAMESTATE->m_pPreferredSong = pSong; diff --git a/src/ScreenJukebox.cpp b/src/ScreenJukebox.cpp index 07f293bfe3..5059d2ecf1 100644 --- a/src/ScreenJukebox.cpp +++ b/src/ScreenJukebox.cpp @@ -179,7 +179,7 @@ void ScreenJukebox::Init() // ASSERT( GAMESTATE->m_pCurSong ); - GAMESTATE->m_MasterPlayerNumber = PLAYER_1; + GAMESTATE->SetMasterPlayerNumber(PLAYER_1); // choose some cool options int Benchmark = 0; @@ -194,7 +194,7 @@ void ScreenJukebox::Init() PO_GROUP_CALL( GAMESTATE->m_pPlayerState[p]->m_PlayerOptions, ModsLevel_Stage, Init ); PO_GROUP_ASSIGN( GAMESTATE->m_pPlayerState[p]->m_PlayerOptions, ModsLevel_Stage, m_fScrollSpeed, .25f ); PO_GROUP_ASSIGN( GAMESTATE->m_pPlayerState[p]->m_PlayerOptions, ModsLevel_Stage, m_fPerspectiveTilt, -1.0f ); - PO_GROUP_ASSIGN_N( GAMESTATE->m_pPlayerState[p]->m_PlayerOptions, ModsLevel_Stage, m_fEffects, PlayerOptions::EFFECT_MINI, 1.0f ); + PO_GROUP_ASSIGN_N( GAMESTATE->m_pPlayerState[p]->m_PlayerOptions, ModsLevel_Stage, m_fEffects, PlayerOptions::EFFECT_TINY, 1.0f ); } SO_GROUP_ASSIGN( GAMESTATE->m_SongOptions, ModsLevel_Stage, m_LifeType, SongOptions::LIFE_BATTERY ); } diff --git a/src/ScreenMiniMenu.cpp b/src/ScreenMiniMenu.cpp index da3ff924b0..83be2dd4f0 100644 --- a/src/ScreenMiniMenu.cpp +++ b/src/ScreenMiniMenu.cpp @@ -10,6 +10,9 @@ #include "OptionRowHandler.h" #include "PrefsManager.h" +void PrepareToLoadScreen( const RString &sScreenName ); +void FinishedLoadingScreen(); + AutoScreenMessage( SM_GoToOK ); AutoScreenMessage( SM_GoToCancel ); @@ -107,7 +110,7 @@ void ScreenMiniMenu::AfterChangeValueOrRow( PlayerNumber pn ) OptionRow &optrow = *m_pRows[i]; optrow.GetRowDef().m_vEnabledForPlayers.clear(); if( mr.pfnEnabled() ) - optrow.GetRowDef().m_vEnabledForPlayers.insert( GAMESTATE->m_MasterPlayerNumber ); + optrow.GetRowDef().m_vEnabledForPlayers.insert( GAMESTATE->GetMasterPlayerNumber() ); } m_pRows[i]->UpdateEnabledDisabled(); } diff --git a/src/ScreenNameEntry.cpp b/src/ScreenNameEntry.cpp index b4eeeed4cc..b7faaa4fc1 100644 --- a/src/ScreenNameEntry.cpp +++ b/src/ScreenNameEntry.cpp @@ -118,7 +118,7 @@ ScreenNameEntry::ScreenNameEntry() { GAMESTATE->m_bSideIsJoined[PLAYER_1] = true; GAMESTATE->m_bSideIsJoined[PLAYER_2] = true; - GAMESTATE->m_MasterPlayerNumber = PLAYER_1; + GAMESTATE->SetMasterPlayerNumber(PLAYER_1); GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR ); GAMESTATE->SetCurrentStyle( GAMEMAN->GameAndStringToStyle( GAMEMAN->GetDefaultGame(),"versus") ); StageStats ss; diff --git a/src/ScreenNameEntryTraditional.cpp b/src/ScreenNameEntryTraditional.cpp index 3663641412..c685531180 100644 --- a/src/ScreenNameEntryTraditional.cpp +++ b/src/ScreenNameEntryTraditional.cpp @@ -22,7 +22,7 @@ void ScreenNameEntryTraditional::Init() { GAMESTATE->m_bSideIsJoined[PLAYER_1] = true; GAMESTATE->m_bSideIsJoined[PLAYER_2] = true; - GAMESTATE->m_MasterPlayerNumber = PLAYER_1; + GAMESTATE->SetMasterPlayerNumber(PLAYER_1); GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR ); GAMESTATE->SetCurrentStyle( GAMEMAN->GameAndStringToStyle( GAMEMAN->GetDefaultGame(),"versus") ); for( int z = 0; z < 3; ++z ) diff --git a/src/ScreenNetSelectMusic.cpp b/src/ScreenNetSelectMusic.cpp index c9e4aa3ea8..fe76ec4108 100644 --- a/src/ScreenNetSelectMusic.cpp +++ b/src/ScreenNetSelectMusic.cpp @@ -46,6 +46,7 @@ void ScreenNetSelectMusic::Init() SAMPLE_MUSIC_PREVIEW_MODE.Load( m_sName, "SampleMusicPreviewMode" ); MUSIC_WHEEL_TYPE.Load( m_sName, "MusicWheelType" ); + PLAYER_OPTIONS_SCREEN.Load( m_sName, "PlayerOptionsScreen" ); FOREACH_EnabledPlayer (p) { @@ -53,7 +54,7 @@ void ScreenNetSelectMusic::Init() m_StepsDisplays[p].SetName( ssprintf("StepsDisplayP%d",p+1) ); m_StepsDisplays[p].Load( "StepsDisplayNet", NULL ); - LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_StepsDisplays[p] ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_StepsDisplays[p] ); this->AddChild( &m_StepsDisplays[p] ); } @@ -65,20 +66,13 @@ void ScreenNetSelectMusic::Init() this->AddChild( &m_MusicWheel ); this->MoveToHead( &m_MusicWheel ); - // todo: handle me theme-side -aj - m_BPMDisplay.SetName( "BPMDisplay" ); - m_BPMDisplay.LoadFromFont( THEME->GetPathF("BPMDisplay","bpm") ); - m_BPMDisplay.Load(); - LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_BPMDisplay ); - this->AddChild( &m_BPMDisplay ); - // todo: handle me theme-side -aj FOREACH_EnabledPlayer( p ) { m_ModIconRow[p].SetName( ssprintf("ModIconsP%d",p+1) ); m_ModIconRow[p].Load( "ModIconRowSelectMusic", p ); m_ModIconRow[p].SetFromGameState(); - LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_ModIconRow[p] ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_ModIconRow[p] ); this->AddChild( &m_ModIconRow[p] ); } @@ -331,7 +325,7 @@ void ScreenNetSelectMusic::MenuUp( const InputEventPlus &input ) { NSMAN->ReportNSSOnOff(3); GAMESTATE->m_EditMode = EditMode_Full; - SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptions", SM_BackFromPlayerOptions ); + SCREENMAN->AddNewScreenToTop( PLAYER_OPTIONS_SCREEN, SM_BackFromPlayerOptions ); } void ScreenNetSelectMusic::MenuDown( const InputEventPlus &input ) @@ -434,8 +428,6 @@ void ScreenNetSelectMusic::TweenOffScreen() OFF_COMMAND( m_MusicWheel ); - OFF_COMMAND( m_BPMDisplay ); - FOREACH_EnabledPlayer (pn) { OFF_COMMAND( m_StepsDisplays[pn] ); @@ -494,7 +486,6 @@ void ScreenNetSelectMusic::MusicChanged() { if( GAMESTATE->m_pCurSong == NULL ) { - m_BPMDisplay.NoBPM(); FOREACH_EnabledPlayer (pn) UpdateDifficulties( pn ); @@ -503,7 +494,6 @@ void ScreenNetSelectMusic::MusicChanged() // SOUND->PlayMusic( m_sSectionMusicPath, NULL, true, 0, -1 ); return; } - m_BPMDisplay.SetBpmFromSong( GAMESTATE->m_pCurSong ); FOREACH_EnabledPlayer (pn) { diff --git a/src/ScreenNetSelectMusic.h b/src/ScreenNetSelectMusic.h index 2a0ff5fe1f..ecb89a079f 100644 --- a/src/ScreenNetSelectMusic.h +++ b/src/ScreenNetSelectMusic.h @@ -44,6 +44,7 @@ protected: RString m_sRandomMusicPath; ThemeMetric MUSIC_WHEEL_TYPE; + ThemeMetric PLAYER_OPTIONS_SCREEN; private: MusicWheel m_MusicWheel; diff --git a/src/ScreenOptions.cpp b/src/ScreenOptions.cpp index 4cf574d9b5..1afe97c5ee 100644 --- a/src/ScreenOptions.cpp +++ b/src/ScreenOptions.cpp @@ -531,7 +531,7 @@ void ScreenOptions::HandleScreenMessage( const ScreenMessage SM ) return; // already transitioning // If the selected option sets a screen, honor it. - RString sThisScreen = GetNextScreenForFocusedItem( GAMESTATE->m_MasterPlayerNumber ); + RString sThisScreen = GetNextScreenForFocusedItem( GAMESTATE->GetMasterPlayerNumber() ); if( sThisScreen != "" ) m_sNextScreen = sThisScreen; @@ -808,7 +808,17 @@ void ScreenOptions::MenuStart( const InputEventPlus &input ) void ScreenOptions::ProcessMenuStart( const InputEventPlus &input ) { PlayerNumber pn = input.pn; + int iCurRow = m_iCurrentRow[pn]; + + if( iCurRow < 0 ) + { + // this shouldn't be happening, but it is, so we need to bail out. -aj + SCREENMAN->PlayStartSound(); + this->BeginFadingOut(); + return; + } + OptionRow &row = *m_pRows[iCurRow]; if( m_OptionsNavigation == NAV_THREE_KEY_MENU && row.GetRowType() != OptionRow::RowType_Exit ) diff --git a/src/ScreenOptionsCourseOverview.cpp b/src/ScreenOptionsCourseOverview.cpp index 0003ab7b2a..cefd327d1c 100644 --- a/src/ScreenOptionsCourseOverview.cpp +++ b/src/ScreenOptionsCourseOverview.cpp @@ -119,7 +119,7 @@ void ScreenOptionsCourseOverview::HandleScreenMessage( const ScreenMessage SM ) } else if( SM == SM_GoToNextScreen ) { - int iRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; switch( iRow ) { case CourseOverviewRow_Play: @@ -191,7 +191,7 @@ void ScreenOptionsCourseOverview::ProcessMenuStart( const InputEventPlus &input if( IsTransitioning() ) return; - int iRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; switch( iRow ) { case CourseOverviewRow_Play: diff --git a/src/ScreenOptionsEditCourse.cpp b/src/ScreenOptionsEditCourse.cpp index 6e108856ba..020f328c1d 100644 --- a/src/ScreenOptionsEditCourse.cpp +++ b/src/ScreenOptionsEditCourse.cpp @@ -145,7 +145,7 @@ void ScreenOptionsEditCourse::Init() sc.m_Tutorial = SongCriteria::Tutorial_No; sc.m_Locked = SongCriteria::Locked_Unlocked; - SongUtil::FilterSongs( sc, SONGMAN->GetAllSongs(), m_vpSongs ); + SongUtil::FilterSongs( sc, SONGMAN->GetAllSongs(), m_vpSongs, true ); SongUtil::SortSongPointerArrayByTitle( m_vpSongs ); } @@ -488,7 +488,7 @@ void ScreenOptionsEditCourse::ProcessMenuStart( const InputEventPlus &input ) if( IsTransitioning() ) return; - int iRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; unsigned iSongCount = GAMESTATE->m_pCurCourse->m_vEntries.size(); diff --git a/src/ScreenOptionsExportPackage.cpp b/src/ScreenOptionsExportPackage.cpp index eda77e4ac9..405ba4f786 100644 --- a/src/ScreenOptionsExportPackage.cpp +++ b/src/ScreenOptionsExportPackage.cpp @@ -11,7 +11,9 @@ #include "SpecialFiles.h" #include "SpecialFiles.h" #include "ScreenPrompt.h" +#include "SongManager.h" +// main page (type list) REGISTER_SCREEN_CLASS( ScreenOptionsExportPackage ); void ScreenOptionsExportPackage::Init() @@ -24,51 +26,130 @@ void ScreenOptionsExportPackage::Init() void ScreenOptionsExportPackage::BeginScreen() { - // Fill m_vsPossibleDirsToExport - // todo: Split these out over multiple screens so the scroller - // isn't so overloaded. (See ScreenOptionsToggleSongs) -freem + // Fill m_vsPackageTypes: + m_vsPackageTypes.push_back("Themes"); + m_vsPackageTypes.push_back("NoteSkins"); + m_vsPackageTypes.push_back("Courses"); + m_vsPackageTypes.push_back("Songs"); + // announcers, characters, others? + + vector OptionRowHandlers; + FOREACH_CONST( RString, m_vsPackageTypes, s ) { - // Add themes - { - GetDirListing( SpecialFiles::THEMES_DIR + "*", m_vsPossibleDirsToExport, true, true ); - } + OptionRowHandler *pHand = OptionRowHandlerUtil::MakeNull(); + OptionRowDefinition &def = pHand->m_Def; - // Add NoteSkins - { - vector vs; - GetDirListing( SpecialFiles::NOTESKINS_DIR + "*", vs, true, true ); - FOREACH_CONST( RString, vs, s ) - GetDirListing( *s + "*", m_vsPossibleDirsToExport, true, true ); - } + def.m_sName = *s; + def.m_bAllowExplanation = false; + //def.m_sExplanationName = "# files, # MB, # subdirs"; + def.m_bAllowThemeTitle = false; + def.m_bAllowThemeItems = false; + def.m_layoutType = LAYOUT_SHOW_ALL_IN_ROW; + def.m_bOneChoiceForAllPlayers = true; + def.m_vsChoices.clear(); + def.m_vsChoices.push_back( "" ); + OptionRowHandlers.push_back( pHand ); + } + ScreenOptions::InitMenu( OptionRowHandlers ); + ScreenOptions::BeginScreen(); +} + +void ScreenOptionsExportPackage::ProcessMenuStart( const InputEventPlus &input ) +{ + if( IsTransitioning() ) + return; + + // switch to the subpage with the specified type + //int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; + int iRow = GetCurrentRow(); + if( m_pRows[iRow]->GetRowType() == OptionRow::RowType_Exit ) + { + ScreenOptions::ProcessMenuStart( input ); + return; + } + + ExportPackages::m_sPackageType = m_vsPackageTypes[iRow]; + SCREENMAN->SetNewScreen("ScreenOptionsExportPackageSubPage"); +} + +void ScreenOptionsExportPackage::ImportOptions( int iRow, const vector &vpns ) +{ + +} + +void ScreenOptionsExportPackage::ExportOptions( int iRow, const vector &vpns ) +{ + +} + + +// subpage (has all folders for the specified type) +REGISTER_SCREEN_CLASS( ScreenOptionsExportPackageSubPage ); +void ScreenOptionsExportPackageSubPage::Init() +{ + ScreenOptions::Init(); + + SetNavigation( NAV_THREE_KEY_MENU ); + SetInputMode( INPUTMODE_SHARE_CURSOR ); +} + +void ScreenOptionsExportPackageSubPage::BeginScreen() +{ + // Check type and fill m_vsPossibleDirsToExport + const RString *s_packageType = &ExportPackages::m_sPackageType; + if( *s_packageType == "Themes" ) + { + // add themes + GetDirListing( SpecialFiles::THEMES_DIR + "*", m_vsPossibleDirsToExport, true, true ); + } + else if( *s_packageType == "NoteSkins" ) + { + // add noteskins + vector vs; + GetDirListing( SpecialFiles::NOTESKINS_DIR + "*", vs, true, true ); + FOREACH_CONST( RString, vs, s ) + GetDirListing( *s + "*", m_vsPossibleDirsToExport, true, true ); + } + else if( *s_packageType == "Courses" ) + { // Add courses. Only support courses that are in a group folder. // Support for courses not in a group folder should be phased out. + vector vs; + GetDirListing( SpecialFiles::COURSES_DIR + "*", vs, true, true ); + StripCvsAndSvn( vs ); + StripMacResourceForks( vs ); + FOREACH_CONST( RString, vs, s ) { - vector vs; - GetDirListing( SpecialFiles::COURSES_DIR + "*", vs, true, true ); - StripCvsAndSvn( vs ); - StripMacResourceForks( vs ); - FOREACH_CONST( RString, vs, s ) - { - m_vsPossibleDirsToExport.push_back( *s ); - GetDirListing( *s + "/*", m_vsPossibleDirsToExport, true, true ); - } + m_vsPossibleDirsToExport.push_back( *s ); + GetDirListing( *s + "/*", m_vsPossibleDirsToExport, true, true ); } - - // Add songs - { - vector vs; - GetDirListing( SpecialFiles::SONGS_DIR + "*", vs, true, true ); - FOREACH_CONST( RString, vs, s ) - { - m_vsPossibleDirsToExport.push_back( *s ); - GetDirListing( *s + "/*", m_vsPossibleDirsToExport, true, true ); - } - } - - StripCvsAndSvn( m_vsPossibleDirsToExport ); - StripMacResourceForks( m_vsPossibleDirsToExport ); } + else if( *s_packageType == "Songs" ) + { + // Add song groups + vector asAllGroups; + SONGMAN->GetSongGroupNames(asAllGroups); + FOREACH_CONST( RString, asAllGroups , s ) + { + m_vsPossibleDirsToExport.push_back(*s); + } + } + else if( *s_packageType == "SubGroup" ) + { + //ExportPackages::m_sFolder + /* + vector vs; + GetDirListing( SpecialFiles::SONGS_DIR + "*", vs, true, true ); + FOREACH_CONST( RString, vs, s ) + { + m_vsPossibleDirsToExport.push_back( *s ); + GetDirListing( *s + "/*", m_vsPossibleDirsToExport, true, true ); + } + */ + } + StripCvsAndSvn( m_vsPossibleDirsToExport ); + StripMacResourceForks( m_vsPossibleDirsToExport ); vector OptionRowHandlers; FOREACH_CONST( RString, m_vsPossibleDirsToExport, s ) @@ -142,18 +223,29 @@ static bool ExportPackage( RString sPackageName, RString sDirToExport, RString & return false; } -void ScreenOptionsExportPackage::ProcessMenuStart( const InputEventPlus &input ) +void ScreenOptionsExportPackageSubPage::ProcessMenuStart( const InputEventPlus &input ) { if( IsTransitioning() ) return; - int iCurRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; if( m_pRows[iCurRow]->GetRowType() == OptionRow::RowType_Exit ) { ScreenOptions::ProcessMenuStart( input ); return; } + if( ExportPackages::m_sPackageType == "Courses" + || ExportPackages::m_sPackageType == "NoteSkins" + || ExportPackages::m_sPackageType == "Songs" ) + { + // find folder name + ExportPackages::m_sPackageType = "SubGroup"; + ExportPackages::m_sFolder = m_vsPossibleDirsToExport[iCurRow]; + SCREENMAN->SetNewScreen("ScreenOptionsExportPackageSubPage"); + return; + } + RString sDirToExport = m_vsPossibleDirsToExport[ iCurRow ]; RString sPackageName = ReplaceInvalidFileNameChars( sDirToExport + ".smzip" ); @@ -164,12 +256,12 @@ void ScreenOptionsExportPackage::ProcessMenuStart( const InputEventPlus &input ) ScreenPrompt::Prompt( SM_None, ssprintf("Failed to export package: %s",sError.c_str()) ); } -void ScreenOptionsExportPackage::ImportOptions( int iRow, const vector &vpns ) +void ScreenOptionsExportPackageSubPage::ImportOptions( int iRow, const vector &vpns ) { } -void ScreenOptionsExportPackage::ExportOptions( int iRow, const vector &vpns ) +void ScreenOptionsExportPackageSubPage::ExportOptions( int iRow, const vector &vpns ) { } diff --git a/src/ScreenOptionsExportPackage.h b/src/ScreenOptionsExportPackage.h index 13952e1ff7..80e6c1059c 100644 --- a/src/ScreenOptionsExportPackage.h +++ b/src/ScreenOptionsExportPackage.h @@ -6,6 +6,13 @@ class Course; +// Can this be done any better? -aj +namespace ExportPackages +{ + RString m_sPackageType; + RString m_sFolder; // used for more subpages +} + /** @brief A menu for exporting packages. */ class ScreenOptionsExportPackage : public ScreenOptions { @@ -13,6 +20,21 @@ public: void Init(); virtual void BeginScreen(); +protected: + virtual void ImportOptions( int iRow, const vector &vpns ); + virtual void ExportOptions( int iRow, const vector &vpns ); + + virtual void ProcessMenuStart( const InputEventPlus &input ); + + vector m_vsPackageTypes; +}; + +class ScreenOptionsExportPackageSubPage : public ScreenOptions +{ +public: + void Init(); + virtual void BeginScreen(); + protected: virtual void ImportOptions( int iRow, const vector &vpns ); virtual void ExportOptions( int iRow, const vector &vpns ); diff --git a/src/ScreenOptionsManageCourses.cpp b/src/ScreenOptionsManageCourses.cpp index c3f61721eb..40a0bbcdfa 100644 --- a/src/ScreenOptionsManageCourses.cpp +++ b/src/ScreenOptionsManageCourses.cpp @@ -143,18 +143,18 @@ void ScreenOptionsManageCourses::BeginScreen() if( iter != m_vpCourses.end() ) { iIndex = iter - m_vpCourses.begin(); - this->MoveRowAbsolute( GAMESTATE->m_MasterPlayerNumber, 1 + iIndex ); + this->MoveRowAbsolute( GAMESTATE->GetMasterPlayerNumber(), 1 + iIndex ); } } - AfterChangeRow( GAMESTATE->m_MasterPlayerNumber ); + AfterChangeRow( GAMESTATE->GetMasterPlayerNumber() ); } void ScreenOptionsManageCourses::HandleScreenMessage( const ScreenMessage SM ) { if( SM == SM_GoToNextScreen ) { - int iCurRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; if( iCurRow == 0 ) // "create new" { @@ -218,7 +218,7 @@ void ScreenOptionsManageCourses::ProcessMenuStart( const InputEventPlus &input ) if( IsTransitioning() ) return; - int iCurRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; if( iCurRow == 0 ) // "create new" { @@ -259,7 +259,7 @@ void ScreenOptionsManageCourses::ExportOptions( int iRow, const vectorm_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; if( iCurRow == 0 ) return NULL; else if( m_pRows[iCurRow]->GetRowType() == OptionRow::RowType_Exit ) diff --git a/src/ScreenOptionsManageEditSteps.cpp b/src/ScreenOptionsManageEditSteps.cpp index 6a4e416c9d..b4a48702ee 100644 --- a/src/ScreenOptionsManageEditSteps.cpp +++ b/src/ScreenOptionsManageEditSteps.cpp @@ -125,7 +125,7 @@ void ScreenOptionsManageEditSteps::HandleScreenMessage( const ScreenMessage SM ) { if( SM == SM_GoToNextScreen ) { - int iCurRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; if( iCurRow == 0 ) // "create new" { @@ -203,7 +203,7 @@ void ScreenOptionsManageEditSteps::HandleScreenMessage( const ScreenMessage SM ) SM_BackFromRename, ENTER_NAME_FOR_STEPS, GAMESTATE->m_pCurSteps[PLAYER_1]->GetDescription(), - MAX_EDIT_STEPS_DESCRIPTION_LENGTH, + MAX_STEPS_DESCRIPTION_LENGTH, SongUtil::ValidateCurrentEditStepsDescription ); } break; @@ -245,7 +245,7 @@ void ScreenOptionsManageEditSteps::ProcessMenuStart( const InputEventPlus &input if( IsTransitioning() ) return; - int iCurRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; if( iCurRow == 0 ) // "create new" { @@ -292,7 +292,7 @@ void ScreenOptionsManageEditSteps::ExportOptions( int iRow, const vectorm_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; if( iCurRow == 0 ) return NULL; else if( m_pRows[iCurRow]->GetRowType() == OptionRow::RowType_Exit ) diff --git a/src/ScreenOptionsManageProfiles.cpp b/src/ScreenOptionsManageProfiles.cpp index f3bae8fe78..140177c9c2 100644 --- a/src/ScreenOptionsManageProfiles.cpp +++ b/src/ScreenOptionsManageProfiles.cpp @@ -167,7 +167,7 @@ void ScreenOptionsManageProfiles::HandleScreenMessage( const ScreenMessage SM ) { if( SM == SM_GoToNextScreen ) { - int iCurRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; OptionRow &row = *m_pRows[iCurRow]; if( row.GetRowType() == OptionRow::RowType_Exit ) { @@ -337,7 +337,7 @@ void ScreenOptionsManageProfiles::ProcessMenuStart( const InputEventPlus &input if( IsTransitioning() ) return; - int iCurRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; OptionRow &row = *m_pRows[iCurRow]; if( SHOW_CREATE_NEW && iCurRow == 0 ) // "create new" @@ -405,7 +405,7 @@ void ScreenOptionsManageProfiles::ExportOptions( int iRow, const vectorm_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; OptionRow &row = *m_pRows[iCurRow]; if( SHOW_CREATE_NEW && iCurRow == 0 ) // "create new" diff --git a/src/ScreenOptionsMasterPrefs.cpp b/src/ScreenOptionsMasterPrefs.cpp index 347ecf041d..a3fd2305c8 100644 --- a/src/ScreenOptionsMasterPrefs.cpp +++ b/src/ScreenOptionsMasterPrefs.cpp @@ -489,12 +489,15 @@ static void DefaultFailType( int &sel, bool ToSel, const ConfOption *pConfOption switch( sel ) { - case 0: po.m_FailType = PlayerOptions::FAIL_IMMEDIATE; break; - case 1: po.m_FailType = PlayerOptions::FAIL_IMMEDIATE_CONTINUE; break; - case 2: po.m_FailType = PlayerOptions::FAIL_AT_END; break; - case 3: po.m_FailType = PlayerOptions::FAIL_OFF; break; - default: - ASSERT(0); + case 0: po.m_FailType = PlayerOptions::FAIL_IMMEDIATE; break; + case 1: po.m_FailType = PlayerOptions::FAIL_IMMEDIATE_CONTINUE; break; + case 2: po.m_FailType = PlayerOptions::FAIL_AT_END; break; + case 3: po.m_FailType = PlayerOptions::FAIL_OFF; break; + default: + { + LOG->Warn("Invalid fail type %d! Going to use the default...", sel); + po.m_FailType = PlayerOptions::FAIL_IMMEDIATE; break; + } } SetPrefsDefaultModifiers( po, so ); diff --git a/src/ScreenOptionsMemoryCard.cpp b/src/ScreenOptionsMemoryCard.cpp index 8aab5b16d5..c0bfa6351b 100644 --- a/src/ScreenOptionsMemoryCard.cpp +++ b/src/ScreenOptionsMemoryCard.cpp @@ -111,7 +111,7 @@ void ScreenOptionsMemoryCard::AfterChangeRow( PlayerNumber pn ) } else { - int iRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; m_textOsMountDir.SetText( m_CurrentUsbStorageDevices[iRow].sOsMountDir ); } } @@ -124,7 +124,7 @@ void ScreenOptionsMemoryCard::HandleMessage( const Message &msg ) { /* Remember the old mountpoint. */ const vector &v = m_CurrentUsbStorageDevices; - int iRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; RString sOldMountPoint; if( iRow < int(v.size()) ) { @@ -158,7 +158,7 @@ void ScreenOptionsMemoryCard::ExportOptions( int iRow, const vectorm_MasterPlayerNumber; + PlayerNumber pn = GAMESTATE->GetMasterPlayerNumber(); if( m_iCurrentRow[pn] == iRow ) { const vector &v = m_CurrentUsbStorageDevices; @@ -192,7 +192,7 @@ void ScreenOptionsMemoryCard::ProcessMenuStart( const InputEventPlus &input ) if( IsTransitioning() ) return; - int iCurRow = m_iCurrentRow[GAMESTATE->m_MasterPlayerNumber]; + int iCurRow = m_iCurrentRow[GAMESTATE->GetMasterPlayerNumber()]; const vector &v = m_CurrentUsbStorageDevices; if( iCurRow < int(v.size()) ) // a card diff --git a/src/ScreenOptionsToggleSongs.cpp b/src/ScreenOptionsToggleSongs.cpp index b5d79a4306..f3b42b6aed 100644 --- a/src/ScreenOptionsToggleSongs.cpp +++ b/src/ScreenOptionsToggleSongs.cpp @@ -11,7 +11,6 @@ // main page (group list) REGISTER_SCREEN_CLASS( ScreenOptionsToggleSongs ); -REGISTER_SCREEN_CLASS( ScreenOptionsToggleSongsSubPage ); void ScreenOptionsToggleSongs::BeginScreen() { @@ -49,8 +48,7 @@ void ScreenOptionsToggleSongs::ProcessMenuStart( const InputEventPlus &input ) // switch to the subpage with the specified group int iRow = GetCurrentRow(); - OptionRow &row = *m_pRows[iRow]; - if( row.GetRowType() == OptionRow::RowType_Exit ) + if( m_pRows[iRow]->GetRowType() == OptionRow::RowType_Exit ) { ScreenOptions::ProcessMenuStart( input ); return; @@ -70,6 +68,7 @@ void ScreenOptionsToggleSongs::ExportOptions( int row, const vectorDraw(); - } -}; +#include "InGameLoadingWindow.h" /* This could be cleaned up: show progress, for example. Let's not use * this for the initial load, since we don't want to start up the display @@ -45,39 +15,36 @@ public: * computer while songs load. */ REGISTER_SCREEN_CLASS( ScreenReloadSongs ); +ScreenReloadSongs::ScreenReloadSongs() {} + void ScreenReloadSongs::Init() { Screen::Init(); - m_iUpdates = 0; + loadWin=new InGameLoadingWindow( ); - m_Loading.SetName("LoadingText"); - m_Loading.LoadFromFont( THEME->GetPathF(m_sName, "LoadingText") ); - m_Loading.SetXY( SCREEN_CENTER_X, SCREEN_CENTER_Y ); - this->AddChild( &m_Loading ); + AddChild( loadWin ); - m_LoadingWindow = new ScreenReloadSongsLoadingWindow( m_Loading ); + loadWin->SetXY( SCREEN_CENTER_X, SCREEN_CENTER_Y ); + + pLoadingWindow=loadWin; + + m_loadingThread.SetName("Song reload work thread"); + m_loadingThread.Create(loadingThreadProc,this); } ScreenReloadSongs::~ScreenReloadSongs() { - delete m_LoadingWindow; + m_loadingThread.Wait(); + RemoveChild(loadWin); + delete loadWin; } - -void ScreenReloadSongs::Update( float fDeltaTime ) +int ScreenReloadSongs::loadingThreadProc(void *thisAsVoidPtr) { - Screen::Update( fDeltaTime ); - - /* Start the reload on the second update. On the first (0), SCREENMAN->Draw won't draw. */ - ++m_iUpdates; - if( m_iUpdates != 2 ) - return; - ASSERT( !IsFirstUpdate() ); - - SONGMAN->Reload( false, m_LoadingWindow ); - + SONGMAN->Reload( false ); SCREENMAN->PostMessageToTopScreen( SM_GoToNextScreen, 0 ); + return 0; } /* diff --git a/src/ScreenReloadSongs.h b/src/ScreenReloadSongs.h index 860bdd28f7..39676e8dff 100644 --- a/src/ScreenReloadSongs.h +++ b/src/ScreenReloadSongs.h @@ -2,20 +2,20 @@ #define SCREEN_RELOAD_SONGS_H #include "Screen.h" -#include "BitmapText.h" -class LoadingWindow; +#include "RageThreads.h" + +class InGameLoadingWindow; class ScreenReloadSongs: public Screen { public: + ScreenReloadSongs(); virtual void Init(); ~ScreenReloadSongs(); - void Update( float fDeltaTime ); - private: - int m_iUpdates; - LoadingWindow *m_LoadingWindow; - BitmapText m_Loading; + InGameLoadingWindow *loadWin; + RageThread m_loadingThread; + static int loadingThreadProc(void *thisAsVoidPtr); }; #endif diff --git a/src/ScreenSMOnlineLogin.cpp b/src/ScreenSMOnlineLogin.cpp index 80d0c40b1d..5cf0e61cb1 100644 --- a/src/ScreenSMOnlineLogin.cpp +++ b/src/ScreenSMOnlineLogin.cpp @@ -155,7 +155,7 @@ void ScreenSMOnlineLogin::HandleScreenMessage(const ScreenMessage SM) { LOG->Trace("[ScreenSMOnlineLogin::HandleScreenMessage] GoToNextScreen"); vector v; - v.push_back( GAMESTATE->m_MasterPlayerNumber ); + v.push_back( GAMESTATE->GetMasterPlayerNumber() ); for( unsigned r=0; rm_MasterPlayerNumber != PlayerNumber_Invalid ); - int iMastersIndex = this->GetSelectionIndex( GAMESTATE->m_MasterPlayerNumber ); + ASSERT( GAMESTATE->GetMasterPlayerNumber() != PlayerNumber_Invalid ); + int iMastersIndex = this->GetSelectionIndex( GAMESTATE->GetMasterPlayerNumber() ); bool bAllPlayersChoseTheSame = true; FOREACH_HumanPlayer( p ) { diff --git a/src/ScreenSelectMaster.cpp b/src/ScreenSelectMaster.cpp index 0e50f5ccbf..3c3a80a4b9 100644 --- a/src/ScreenSelectMaster.cpp +++ b/src/ScreenSelectMaster.cpp @@ -294,7 +294,7 @@ void ScreenSelectMaster::HandleScreenMessage( const ScreenMessage SM ) if( SM == SM_PlayPostSwitchPage ) { - int iNewChoice = m_iChoice[ GAMESTATE->m_MasterPlayerNumber ]; + int iNewChoice = m_iChoice[ GAMESTATE->GetMasterPlayerNumber() ]; Page newPage = GetPage( iNewChoice ); Message msg("PostSwitchPage"); @@ -516,7 +516,7 @@ void ScreenSelectMaster::MenuDown( const InputEventPlus &input ) bool ScreenSelectMaster::ChangePage( int iNewChoice ) { - Page oldPage = GetPage( m_iChoice[GAMESTATE->m_MasterPlayerNumber] ); + Page oldPage = GetPage( m_iChoice[GAMESTATE->GetMasterPlayerNumber()] ); Page newPage = GetPage( iNewChoice ); // If anyone has already chosen, don't allow changing of pages @@ -710,8 +710,8 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew PlayerNumber ScreenSelectMaster::GetSharedPlayer() { - if( GAMESTATE->m_MasterPlayerNumber != PLAYER_INVALID ) - return GAMESTATE->m_MasterPlayerNumber; + if( GAMESTATE->GetMasterPlayerNumber() != PLAYER_INVALID ) + return GAMESTATE->GetMasterPlayerNumber(); return PLAYER_1; } diff --git a/src/ScreenSelectMaster.h b/src/ScreenSelectMaster.h index 85fbd34b7a..5a6cc8e08f 100644 --- a/src/ScreenSelectMaster.h +++ b/src/ScreenSelectMaster.h @@ -53,7 +53,6 @@ protected: Page GetPage( int iChoiceIndex ) const; Page GetCurrentPage() const; - ThemeMetric USE_TWO_SCROLLERS; ThemeMetric DO_SWITCH_ANYWAYS; ThemeMetric DOUBLE_PRESS_TO_SELECT; ThemeMetric SHOW_ICON; @@ -68,7 +67,6 @@ protected: ThemeMetric PRE_SWITCH_PAGE_SECONDS; ThemeMetric POST_SWITCH_PAGE_SECONDS; ThemeMetric1D OPTION_ORDER; - ThemeMetric1D OPTION_ORDER2; ThemeMetric WRAP_CURSOR; ThemeMetric WRAP_SCROLLER; ThemeMetric LOOP_SCROLLER; diff --git a/src/ScreenSelectMusic.cpp b/src/ScreenSelectMusic.cpp index 1ee3c116a4..4251ae73ab 100644 --- a/src/ScreenSelectMusic.cpp +++ b/src/ScreenSelectMusic.cpp @@ -68,7 +68,7 @@ void ScreenSelectMusic::Init() GAMESTATE->m_PlayMode.Set( PLAY_MODE_REGULAR ); GAMESTATE->SetCurrentStyle( GAMEMAN->GameAndStringToStyle(GAMEMAN->GetDefaultGame(),"versus") ); GAMESTATE->JoinPlayer( PLAYER_1 ); - GAMESTATE->m_MasterPlayerNumber = PLAYER_1; + GAMESTATE->SetMasterPlayerNumber(PLAYER_1); } SAMPLE_MUSIC_DELAY_INIT.Load( m_sName, "SampleMusicDelayInit" ); @@ -1020,7 +1020,7 @@ void ScreenSelectMusic::HandleMessage( const Message &msg ) // TODO: Invalidate the CurSteps only if they are no longer playable. // That way, after music change will clamp to the nearest in the StepsDisplayList. - GAMESTATE->m_pCurSteps[GAMESTATE->m_MasterPlayerNumber].SetWithoutBroadcast( NULL ); + GAMESTATE->m_pCurSteps[GAMESTATE->GetMasterPlayerNumber()].SetWithoutBroadcast( NULL ); FOREACH_ENUM( PlayerNumber, p ) GAMESTATE->m_pCurSteps[p].SetWithoutBroadcast( NULL ); @@ -1392,7 +1392,7 @@ void ScreenSelectMusic::MenuStart( const InputEventPlus &input ) if( pStyle == NULL ) { StepsType stCurrent; - PlayerNumber pn = GAMESTATE->m_MasterPlayerNumber; + PlayerNumber pn = GAMESTATE->GetMasterPlayerNumber(); if( GAMESTATE->IsCourseMode() ) { ASSERT( GAMESTATE->m_pCurTrail[pn] ); @@ -1615,7 +1615,7 @@ void ScreenSelectMusic::SwitchToPreferredDifficulty() if( GAMESTATE->DifficultiesLocked() ) { FOREACH_HumanPlayer( p ) - m_iSelection[p] = m_iSelection[GAMESTATE->m_MasterPlayerNumber]; + m_iSelection[p] = m_iSelection[GAMESTATE->GetMasterPlayerNumber()]; } } diff --git a/src/ScreenServiceAction.cpp b/src/ScreenServiceAction.cpp index 13e1222260..c28086a72c 100644 --- a/src/ScreenServiceAction.cpp +++ b/src/ScreenServiceAction.cpp @@ -197,7 +197,8 @@ static void CopyEdits( const RString &sFromProfileDir, const RString &sToProfile iNumErrored++; // Test whether the song we need for this edit is present and ignore this edit if not present. - if( !SSCLoader::LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) ) + SSCLoader loaderSSC; + if( !loaderSSC.LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) ) { iNumIgnored++; continue; diff --git a/src/ScreenServiceAction.h b/src/ScreenServiceAction.h index 35011f0106..174d80e57e 100644 --- a/src/ScreenServiceAction.h +++ b/src/ScreenServiceAction.h @@ -5,6 +5,8 @@ #include "ScreenPrompt.h" +RString ClearMachineStats(); + class ScreenServiceAction : public ScreenPrompt { public: diff --git a/src/ScreenSongOptions.cpp b/src/ScreenSongOptions.cpp index 5006b43ac3..2b9287c232 100644 --- a/src/ScreenSongOptions.cpp +++ b/src/ScreenSongOptions.cpp @@ -23,7 +23,7 @@ void ScreenSongOptions::Init() void ScreenSongOptions::ExportOptions( int iRow, const vector &vpns ) { - PlayerNumber pn = GAMESTATE->m_MasterPlayerNumber; + PlayerNumber pn = GAMESTATE->GetMasterPlayerNumber(); PlayerState *pPS = GAMESTATE->m_pPlayerState[pn]; const PlayerOptions::FailType ft = pPS->m_PlayerOptions.GetPreferred().m_FailType; diff --git a/src/ScreenSyncOverlay.cpp b/src/ScreenSyncOverlay.cpp index 3596c91e70..a0d9f6c6a8 100644 --- a/src/ScreenSyncOverlay.cpp +++ b/src/ScreenSyncOverlay.cpp @@ -221,8 +221,8 @@ bool ScreenSyncOverlay::OverlayInput( const InputEventPlus &input ) } if( GAMESTATE->m_pCurSong != NULL ) { - BPMSegment& seg = GAMESTATE->m_pCurSong->m_SongTiming.GetBPMSegmentAtBeat( GAMESTATE->m_Position.m_fSongBeat ); - seg.SetBPS( seg.GetBPS() + fDelta ); + BPMSegment * seg = GAMESTATE->m_pCurSong->m_SongTiming.GetBPMSegmentAtBeat( GAMESTATE->m_Position.m_fSongBeat ); + seg->SetBPS( seg->GetBPS() + fDelta ); } } break; @@ -253,7 +253,14 @@ bool ScreenSyncOverlay::OverlayInput( const InputEventPlus &input ) case ChangeSongOffset: if( GAMESTATE->m_pCurSong != NULL ) + { GAMESTATE->m_pCurSong->m_SongTiming.m_fBeat0OffsetInSeconds += fDelta; + const vector& vpSteps = GAMESTATE->m_pCurSong->GetAllSteps(); + FOREACH( Steps*, const_cast&>(vpSteps), s ) + { + (*s)->m_Timing.m_fBeat0OffsetInSeconds += fDelta; + } + } break; } } diff --git a/src/ScreenTestFonts.cpp b/src/ScreenTestFonts.cpp deleted file mode 100644 index 8d163e22ec..0000000000 --- a/src/ScreenTestFonts.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "global.h" -#include "ScreenTestFonts.h" -#include "FontManager.h" -#include "RageTextureManager.h" -#include "ScreenTextEntry.h" -#include "ScreenDimensions.h" -#include "InputEventPlus.h" -#include "RageUtil.h" - - -static const float LineWidth = 400; -static const float LineHeight = 50; - -/** @brief A quick way of getting a font metric. */ -#define FONT( i ) THEME->GetMetric (m_sName,ssprintf("Font%i",i)) -/** @brief A quick way of getting a particular string. */ -#define TEXT( i ) THEME->GetString (m_sName,ssprintf("Text%i",i)) - -static RString g_sCustomText; - -static void ChangeText( const RString &sText ) -{ - g_sCustomText = sText; -} - -AutoScreenMessage( SM_ChangeText ); - -void ScreenTestFonts::HandleScreenMessage( const ScreenMessage SM ) -{ - if( SM == ScreenMessage(SM_ChangeText) ) - SetText( g_sCustomText ); -} - -REGISTER_SCREEN_CLASS( ScreenTestFonts ); - -void ScreenTestFonts::Init() -{ - Screen::Init(); - - Hline.SetXY(SCREEN_CENTER_X, SCREEN_CENTER_Y); - Hline.SetZoomX(LineWidth); - Hline.SetDiffuse( RageColor(1, 1, 1, 1) ); - this->AddChild(&Hline); - - Vline.SetXY(SCREEN_CENTER_X, SCREEN_CENTER_Y); - Vline.SetZoomY(LineHeight); - Vline.SetDiffuse( RageColor(0, 1, 0, .8f) ); - this->AddChild(&Vline); - - font.SetXY( SCREEN_CENTER_X, SCREEN_CENTER_Y+100 ); - font.LoadFromFont( THEME->GetPathF("Common", "normal") ); - font.SetZoom(.5); - this->AddChild(&font); - - txt.SetName( "Text" ); - SetFont( THEME->GetPathF("", FONT(1)) ); - LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( txt ); - SetText( "Foo" ); -} - -void ScreenTestFonts::SetText( RString sText ) -{ - txt.SetShadowLength( 0 ); - txt.SetText( "" ); /* force it */ - txt.SetText( sText ); - m_sCurText = sText; -} - -void ScreenTestFonts::SetFont( RString sFont ) -{ - m_sFont = sFont; - - txt.LoadFromFont( m_sFont ); - font.SetText( m_sFont ); - /* The font changed, so we need to reset the text or it'll be - * misaligned. */ - SetText( m_sCurText ); -} - -void ScreenTestFonts::DrawPrimitives() -{ - Screen::DrawPrimitives(); - - /* Draw this manually, so we can breakpoint here. */ - txt.Draw(); -} - - -void ScreenTestFonts::Input( const InputEventPlus &input ) -{ - if( input.type != IET_FIRST_PRESS ) - return; - switch( input.DeviceI.button ) - { - case '[': txt.SetVertAlign( align_bottom ); break; - case '\\': txt.SetVertAlign( align_middle ); break; - case ']': txt.SetVertAlign( align_top ); break; - - case ',': txt.SetHorizAlign( align_left ); break; - case '.': txt.SetHorizAlign( align_center ); break; - case '/': txt.SetHorizAlign( align_right ); break; - - case '`': if( m_sCurText != g_sCustomText ) - SetText( g_sCustomText ); - else - ScreenTextEntry::TextEntry( SM_ChangeText, "Edit text.", g_sCustomText, 100, NULL, ChangeText, NULL); - break; - case '1': SetText( TEXT(1) ); break; - case '2': SetText( TEXT(2) ); break; - case '3': SetText( TEXT(3) ); break; - case '4': SetText( TEXT(4) ); break; - case '5': SetText( TEXT(5) ); break; - - case 'q': SetFont( THEME->GetPathF("", FONT(1)) ); break; - case 'w': SetFont( THEME->GetPathF("", FONT(2)) ); break; - case 'e': SetFont( THEME->GetPathF("", FONT(3)) ); break; - case 'r': SetFont( THEME->GetPathF("", FONT(4)) ); break; - case 't': SetFont( THEME->GetPathF("", FONT(5)) ); break; - - case 'a': SetFont( THEME->GetPathF("", FONT(1)) ); break; - - case 'z': FONT->ReloadFonts(); - TEXTUREMAN->ReloadAll(); - SetText( m_sCurText ); - SetFont( m_sFont ); - break; - } -} - -/* - * (c) 2003-2005 Glenn Maynard - * 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. - */ diff --git a/src/ScreenTestFonts.h b/src/ScreenTestFonts.h deleted file mode 100644 index c6cdf7e2cf..0000000000 --- a/src/ScreenTestFonts.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef SCREEN_TEST_FONTS_H -#define SCREEN_TEST_FONTS_H - -#include "Screen.h" -#include "BitmapText.h" -#include "Quad.h" - -/** @brief Display and test fonts. */ -class ScreenTestFonts: public Screen -{ -public: - virtual void Init(); - - void Input( const InputEventPlus &input ); - void DrawPrimitives(); - void HandleScreenMessage( const ScreenMessage SM ); - -private: - void SetText( RString sText ); - void SetFont( RString sFont ); - - /** @brief The current text to display. */ - RString m_sCurText; - /** @brief The current font in use. */ - RString m_sFont; - BitmapText txt, font; - Quad Vline, Hline; -}; - -#endif - -/* - * (c) 2003-2005 Glenn Maynard - * 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. - */ diff --git a/src/ScreenTestSound.cpp b/src/ScreenTestSound.cpp index b27f93a87f..813f5cf6fa 100644 --- a/src/ScreenTestSound.cpp +++ b/src/ScreenTestSound.cpp @@ -17,7 +17,7 @@ void ScreenTestSound::Init() HEEEEEEEEELP.SetXY(450, 400); HEEEEEEEEELP.LoadFromFont( THEME->GetPathF("Common","normal") ); - HEEEEEEEEELP.SetZoom(.5); + HEEEEEEEEELP.SetZoom(.5f); HEEEEEEEEELP.SetText( "p Play\n" "s Stop\n" @@ -29,7 +29,7 @@ void ScreenTestSound::Init() { this->AddChild(&s[i].txt); s[i].txt.LoadFromFont( THEME->GetPathF("Common","normal") ); - s[i].txt.SetZoom(.5); + s[i].txt.SetZoom(.5f); } s[0].txt.SetXY(150, 100); diff --git a/src/ScreenTextEntry.cpp b/src/ScreenTextEntry.cpp index 994e0fc7a8..ee5fa14164 100644 --- a/src/ScreenTextEntry.cpp +++ b/src/ScreenTextEntry.cpp @@ -258,7 +258,8 @@ void ScreenTextEntry::BackspaceInAnswer() void ScreenTextEntry::MenuStart( const InputEventPlus &input ) { - if( input.type==IET_FIRST_PRESS ) + // HACK: Only allow the screen to end on the Enter key.-aj + if( input.DeviceI == DeviceInput(DEVICE_KEYBOARD, KEY_ENTER) && input.type==IET_FIRST_PRESS ) End( false ); } diff --git a/src/ScreenUnlockStatus.cpp b/src/ScreenUnlockStatus.cpp index e06c7dfa95..502e5d76bf 100644 --- a/src/ScreenUnlockStatus.cpp +++ b/src/ScreenUnlockStatus.cpp @@ -127,7 +127,7 @@ void ScreenUnlockStatus::Init() break; default: text->SetText( "" ); - text->SetDiffuse( RageColor(0.5,0,0,1) ); + text->SetDiffuse( RageColor(0.5f,0,0,1) ); break; } diff --git a/src/Song.cpp b/src/Song.cpp index cc57bccd9b..604953e83d 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -41,7 +41,7 @@ * @brief The internal version of the cache for StepMania. * * Increment this value to invalidate the current cache. */ -const int FILE_CACHE_VERSION = 178; +const int FILE_CACHE_VERSION = 196; /** @brief How long does a song sample last by default? */ const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f; @@ -69,9 +69,9 @@ Song::Song() m_fMusicSampleStartSeconds = -1; m_fMusicSampleLengthSeconds = DEFAULT_MUSIC_SAMPLE_LENGTH; m_fMusicLengthSeconds = 0; - m_fFirstBeat = -1; - m_fLastBeat = -1; - m_fSpecifiedLastBeat = -1; + firstSecond = -1; + lastSecond = -1; + specifiedLastSecond = -1; m_SelectionDisplay = SHOW_ALWAYS; m_bEnabled = true; m_DisplayBPMType = DISPLAY_BPM_ACTUAL; @@ -100,6 +100,51 @@ void Song::DetachSteps() m_vpStepsByType[st].clear(); } +float Song::GetFirstSecond() const +{ + return this->firstSecond; +} + +float Song::GetFirstBeat() const +{ + return this->m_SongTiming.GetBeatFromElapsedTime(this->firstSecond); +} + +float Song::GetLastSecond() const +{ + return this->lastSecond; +} + +float Song::GetLastBeat() const +{ + return this->m_SongTiming.GetBeatFromElapsedTime(this->lastSecond); +} + +float Song::GetSpecifiedLastSecond() const +{ + return this->specifiedLastSecond; +} + +float Song::GetSpecifiedLastBeat() const +{ + return this->m_SongTiming.GetBeatFromElapsedTime(this->specifiedLastSecond); +} + +void Song::SetFirstSecond(const float f) +{ + this->firstSecond = f; +} + +void Song::SetLastSecond(const float f) +{ + this->lastSecond = f; +} + +void Song::SetSpecifiedLastSecond(const float f) +{ + this->specifiedLastSecond = f; +} + // Reset to an empty song. void Song::Reset() { @@ -154,7 +199,12 @@ Steps *Song::CreateSteps() void Song::InitSteps(Steps *pSteps) { - pSteps->m_Timing = m_SongTiming; + pSteps->m_Timing = this->m_SongTiming; + pSteps->m_sAttackString = this->m_sAttackString; + pSteps->m_Attacks = this->m_Attacks; + pSteps->SetDisplayBPM(this->m_DisplayBPMType); + pSteps->SetMinBPM(this->m_fSpecifiedBPMMin); + pSteps->SetMaxBPM(this->m_fSpecifiedBPMMax); } void Song::GetDisplayBpms( DisplayBpms &AddTo ) const @@ -190,7 +240,9 @@ RString Song::GetCacheFilePath() const // Get a path to the SM containing data for this song. It might be a cache file. const RString &Song::GetSongFilePath() const { - ASSERT( !m_sSongFileName.empty() ); + ASSERT_M( !m_sSongFileName.empty(), + ssprintf("The song %s has no filename associated with it!", + this->m_sMainTitle.c_str())); return m_sSongFileName; } @@ -206,7 +258,7 @@ static set BlacklistedImages; bool Song::LoadFromSongDir( RString sDir ) { // LOG->Trace( "Song::LoadFromSongDir(%s)", sDir.c_str() ); - ASSERT( sDir != "" ); + ASSERT_M( sDir != "", "Songs can't be loaded from an empty directory!" ); // make sure there is a trailing slash at the end of sDir if( sDir.Right(1) != "/" ) @@ -234,13 +286,19 @@ bool Song::LoadFromSongDir( RString sDir ) if( bUseCache ) { -// LOG->Trace( "Loading '%s' from cache file '%s'.", m_sSongDir.c_str(), GetCacheFilePath().c_str() ); - bool bLoadedFromSSC = SSCLoader::LoadFromSSCFile( sCacheFilePath, *this, true ); + /* + LOG->Trace("Loading '%s' from cache file '%s'.", + m_sSongDir.c_str(), + GetCacheFilePath().c_str()); + */ + SSCLoader loaderSSC; + bool bLoadedFromSSC = loaderSSC.LoadFromSimfile( sCacheFilePath, *this, true ); if( !bLoadedFromSSC ) { // load from .sm - SMLoader::LoadFromSMFile( sCacheFilePath, *this, true ); - SMLoader::TidyUpData( *this, true ); + SMLoader loaderSM; + loaderSM.LoadFromSimfile( sCacheFilePath, *this, true ); + loaderSM.TidyUpData( *this, true ); } } else @@ -263,10 +321,14 @@ bool Song::LoadFromSongDir( RString sDir ) LOG->UserLog( "Song", sDir, "has no music file either. Ignoring this song directory." ); return false; } - + // Make sure we have a future filename figured out. + vector folders; + split(sDir, "/", folders); + RString songName = folders[2] + ".ssc"; + this->m_sSongFileName = sDir + songName; // Continue on with a blank Song so that people can make adjustments using the editor. } - TidyUpData(); + TidyUpData(false, true); // save a cache file so we don't have to parse it all over again next time if( !SaveToCacheFile() ) @@ -275,8 +337,6 @@ bool Song::LoadFromSongDir( RString sDir ) FOREACH( Steps*, m_vpSteps, s ) { - (*s)->SetFilename( sCacheFilePath ); - /* Compress all Steps. During initial caching, this will remove cached * NoteData; during cached loads, this will just remove cached SMData. */ (*s)->Compress(); @@ -328,13 +388,13 @@ bool Song::ReloadFromSongDir( RString sDir ) FOREACH_ENUM( StepsType, i ) m_vpStepsByType[i].clear(); - // Then we copy as many Steps as possible on top of the old pointers. - // The only pointers that change are pointers to Steps that are not in the - // reverted file, which we delete, and pointers to Steps that are in the - // reverted file but not the original *this, which we create new copies of. - // We have to go through these hoops because many places assume the Steps - // pointers don't change - even though there are other ways they can change, - // such as deleting a Steps via the editor. + /* Then we copy as many Steps as possible on top of the old pointers. + * The only pointers that change are pointers to Steps that are not in the + * reverted file, which we delete, and pointers to Steps that are in the + * reverted file but not the original *this, which we create new copies of. + * We have to go through these hoops because many places assume the Steps + * pointers don't change - even though there are other ways they can change, + * such as deleting a Steps via the editor. */ for( vector::const_iterator itOld = vOldSteps.begin(); itOld != vOldSteps.end(); ++itOld ) { StepsID id; @@ -388,7 +448,7 @@ void FixupPath( RString &path, const RString &sSongPath ) } // Songs in BlacklistImages will never be autodetected as song images. -void Song::TidyUpData( bool bFromCache ) +void Song::TidyUpData( bool fromCache, bool duringCache ) { // We need to do this before calling any of HasMusic, HasHasCDTitle, etc. ASSERT_M( m_sSongDir.Left(3) != "../", m_sSongDir ); // meaningless @@ -461,12 +521,18 @@ void Song::TidyUpData( bool bFromCache ) else // ! HasMusic() { m_fMusicLengthSeconds = 100; // guess - LOG->UserLog( "Song", GetSongDir(), "has no music file; guessing at %f seconds", m_fMusicLengthSeconds ); + LOG->UserLog("Song", + GetSongDir(), + "has no music file; guessing at %f seconds", + m_fMusicLengthSeconds); } if( m_fMusicLengthSeconds < 0 ) { - LOG->UserLog( "Sound file", GetMusicPath(), "has a negative length %f.", m_fMusicLengthSeconds ); + LOG->UserLog("Sound file", + GetMusicPath(), + "has a negative length %f.", + m_fMusicLengthSeconds); m_fMusicLengthSeconds = 0; } @@ -479,7 +545,7 @@ void Song::TidyUpData( bool bFromCache ) /* Generate these before we autogen notes, so the new notes can inherit * their source's values. */ - ReCalculateRadarValuesAndLastBeat( bFromCache ); + ReCalculateRadarValuesAndLastSecond( fromCache, true ); Trim( m_sMainTitle ); Trim( m_sSubTitle ); @@ -487,7 +553,8 @@ void Song::TidyUpData( bool bFromCache ) // Fall back on the song directory name. if( m_sMainTitle == "" ) - NotesLoader::GetMainAndSubTitlesFromFullTitle( Basename(this->GetSongDir()), m_sMainTitle, m_sSubTitle ); + NotesLoader::GetMainAndSubTitlesFromFullTitle(Basename(this->GetSongDir()), + m_sMainTitle, m_sSubTitle ); if( m_sArtist == "" ) m_sArtist = "Unknown artist"; @@ -502,7 +569,8 @@ void Song::TidyUpData( bool bFromCache ) if( m_fMusicSampleStartSeconds+m_fMusicSampleLengthSeconds > this->m_fMusicLengthSeconds ) { - int iBeat = lrintf( m_fLastBeat/2 ); + // Attempt to get a reasonable default. + int iBeat = lrintf(this->m_SongTiming.GetBeatFromElapsedTime(this->GetLastSecond())/2); iBeat -= iBeat%4; m_fMusicSampleStartSeconds = timing.GetElapsedTimeFromBeat( (float)iBeat ); } @@ -600,7 +668,8 @@ void Song::TidyUpData( bool bFromCache ) m_sLyricsFile = arrayLyricFiles[0]; } - // Now, For the images we still haven't found, look at the image dimensions of the remaining unclassified images. + /* Now, For the images we still haven't found, + * look at the image dimensions of the remaining unclassified images. */ vector arrayImages; GetImageDirListing( m_sSongDir + "*", arrayImages ); @@ -711,7 +780,12 @@ void Song::TidyUpData( bool bFromCache ) /* Use this->GetBeatFromElapsedTime(0) instead of 0 to start when the * music starts. */ if( arrayPossibleMovies.size() == 1 ) - this->AddBackgroundChange( BACKGROUND_LAYER_1, BackgroundChange(0,arrayPossibleMovies[0],"",1.f,SBE_StretchNoLoop) ); + this->AddBackgroundChange(BACKGROUND_LAYER_1, + BackgroundChange(0, + arrayPossibleMovies[0], + "", + 1.f, + SBE_StretchNoLoop)); } @@ -719,64 +793,6 @@ void Song::TidyUpData( bool bFromCache ) * for edits). We should be able to use difficulty names as unique * identifiers for steps. */ SongUtil::AdjustDuplicateSteps( this ); - - { - /* Generated filename; this doesn't always point to a loadable file, - * but instead points to the file we should write changed files to, - * and will always be a .SSC. - * - * This is a little tricky. We can't always use the song title directly, - * since it might contain characters we can't store in filenames. Two - * easy options: we could manually filter out invalid characters, or we - * could use the name of the directory, which is always a valid filename - * and should always be the same as the song. The former might not catch - * everything--filename restrictions are platform-specific; we might even - * be on an 8.3 filesystem, so let's do the latter. - * - * We can't rely on searching for other data filenames; it works for DWIs, - * but not KSFs and BMSs. - * - * So, let's do this (by priority): - * 1. If there's a .SSC file, use that filename. No reason to use anything - * else; it's the filename in use. - * 2. If there's an .SM, use it with a changed extension. - * 3. If there's a .DWI, use it with a changed extension. - * 4. Otherwise, use the name of the directory, since it's definitely a valid - * filename, and should always be the title of the song (unlike KSFs). */ - m_sSongFileName = m_sSongDir; - vector asFileNames; - do - { - GetDirListing( m_sSongDir+"*.ssc", asFileNames ); - if( !asFileNames.empty() ) - { - m_sSongFileName += asFileNames[0]; - break; - } - - GetDirListing( m_sSongDir+"*.sma", asFileNames ); - if (!asFileNames.empty() ) - { - m_sSongFileName += SetExtension( asFileNames[0], "ssc" ); - break; - } - - GetDirListing( m_sSongDir+"*.sm", asFileNames ); - if( !asFileNames.empty() ) - { - m_sSongFileName += SetExtension( asFileNames[0], "ssc" ); - break; - } - - GetDirListing( m_sSongDir+"*.dwi", asFileNames ); - if( !asFileNames.empty() ) { - m_sSongFileName += SetExtension( asFileNames[0], "ssc" ); - break; - } - m_sSongFileName += Basename(m_sSongDir); - m_sSongFileName += ".ssc"; - } while(0); - } } void Song::TranslateTitles() @@ -784,14 +800,16 @@ void Song::TranslateTitles() static TitleSubst tsub("Songs"); TitleFields title; - title.LoadFromStrings( m_sMainTitle, m_sSubTitle, m_sArtist, m_sMainTitleTranslit, m_sSubTitleTranslit, m_sArtistTranslit ); + title.LoadFromStrings(m_sMainTitle, m_sSubTitle, m_sArtist, + m_sMainTitleTranslit, m_sSubTitleTranslit, m_sArtistTranslit ); tsub.Subst( title ); - title.SaveToStrings( m_sMainTitle, m_sSubTitle, m_sArtist, m_sMainTitleTranslit, m_sSubTitleTranslit, m_sArtistTranslit ); + title.SaveToStrings(m_sMainTitle, m_sSubTitle, m_sArtist, + m_sMainTitleTranslit, m_sSubTitleTranslit, m_sArtistTranslit ); } -void Song::ReCalculateRadarValuesAndLastBeat( bool bFromCache ) +void Song::ReCalculateRadarValuesAndLastSecond(bool fromCache, bool duringCache) { - if( bFromCache && m_fFirstBeat >= 0 && m_fLastBeat > 0 ) + if( fromCache && this->GetFirstSecond() >= 0 && this->GetLastSecond() > 0 ) { // this is loaded from cache, then we just have to calculate the radar values. for( unsigned i=0; ispecifiedLastSecond; for( unsigned i=0; iCalculateRadarValues( m_fMusicLengthSeconds ); - // calculate lastBeat + // Must initialize before the gotos. + NoteData tempNoteData; + pSteps->GetNoteData( tempNoteData ); + + // calculate lastSecond // If it's autogen, then first/last beat will come from the parent. if( pSteps->IsAutogen() ) - continue; + goto wipe_notedata; /* Don't calculate with edits unless the song only contains an edit * chart, like those in Mungyodance 3. Otherwise, edits installed on * the machine could extend the length of the song. */ if( pSteps->IsAnEdit() && m_vpSteps.size() > 1 ) - continue; + goto wipe_notedata; // Don't set first/last beat based on lights. They often start very // early and end very late. if( pSteps->m_StepsType == StepsType_lights_cabinet ) - continue; - - NoteData tempNoteData; - pSteps->GetNoteData( tempNoteData ); + continue; // no need to wipe this. /* Many songs have stray, empty song patterns. Ignore them, so they * don't force the first beat of the whole song to 0. */ - if( tempNoteData.GetLastRow() == 0 ) - continue; - - fFirstBeat = min( fFirstBeat, m_SongTiming.GetBeatFromElapsedTime(pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetFirstBeat())) ); - fLastBeat = max( fLastBeat, m_SongTiming.GetBeatFromElapsedTime(pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetLastBeat())) ); + if( tempNoteData.GetLastRow() != 0 ) + { + localFirst = min(localFirst, + pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetFirstBeat())); + localLast = max(localLast, + pSteps->m_Timing.GetElapsedTimeFromBeat(tempNoteData.GetLastBeat())); + } + wipe_notedata: + if (duringCache) + { + NoteData dummy; + dummy.SetNumTracks(tempNoteData.GetNumTracks()); + pSteps->SetNoteData(dummy); + } } - m_fFirstBeat = fFirstBeat; - m_fLastBeat = fLastBeat; + // Yes, for some reason we can have freaky stuff take place here. + this->firstSecond = (localFirst < localLast) ? localFirst : 0; + this->lastSecond = localLast; } // Return whether the song is playable in the given style. @@ -861,7 +891,7 @@ void Song::Save() { LOG->Trace( "Song::SaveToSongFile()" ); - ReCalculateRadarValuesAndLastBeat(); + ReCalculateRadarValuesAndLastSecond(); TranslateTitles(); // TODO: Figure out a better way to save to Song's timing data. @@ -928,11 +958,15 @@ bool Song::SaveToSMFile() bool Song::SaveToSSCFile( RString sPath, bool bSavingCache ) { - LOG->Trace( "Song::SaveToSSCFile('%s')", sPath.c_str() ); + RString path = sPath; + if (!bSavingCache) + path = SetExtension(sPath, "ssc"); + + LOG->Trace( "Song::SaveToSSCFile('%s')", path.c_str() ); // If the file exists, make a backup. - if( !bSavingCache && IsAFile(sPath) ) - FileCopy( sPath, sPath + ".old" ); + if( !bSavingCache && IsAFile(path) ) + FileCopy( path, path + ".old" ); vector vpStepsToSave; FOREACH_CONST( Steps*, m_vpSteps, s ) @@ -945,16 +979,23 @@ bool Song::SaveToSSCFile( RString sPath, bool bSavingCache ) if( pSteps->WasLoadedFromProfile() ) continue; + if (!bSavingCache) + pSteps->SetFilename(path); vpStepsToSave.push_back( pSteps ); } + + if (bSavingCache) + { + return NotesWriterSSC::Write(path, *this, vpStepsToSave, bSavingCache); + } - if( !NotesWriterSSC::Write(sPath, *this, vpStepsToSave, bSavingCache) ) + if( !NotesWriterSSC::Write(path, *this, vpStepsToSave, bSavingCache) ) return false; - if( !bSavingCache && g_BackUpAllSongSaves.Get() ) + if( g_BackUpAllSongSaves.Get() ) { - RString sExt = GetExtension( sPath ); - RString sBackupFile = SetExtension( sPath, "" ); + RString sExt = GetExtension( path ); + RString sBackupFile = SetExtension( path, "" ); time_t cur_time; time( &cur_time ); @@ -966,18 +1007,15 @@ bool Song::SaveToSSCFile( RString sPath, bool bSavingCache ) sBackupFile = SetExtension( sBackupFile, sExt ); sBackupFile += ssprintf( ".old" ); - if( FileCopy(sPath, sBackupFile) ) - LOG->Trace( "Backed up %s to %s", sPath.c_str(), sBackupFile.c_str() ); + if( FileCopy(path, sBackupFile) ) + LOG->Trace( "Backed up %s to %s", path.c_str(), sBackupFile.c_str() ); else - LOG->Trace( "Failed to back up %s to %s", sPath.c_str(), sBackupFile.c_str() ); + LOG->Trace( "Failed to back up %s to %s", path.c_str(), sBackupFile.c_str() ); } - if( !bSavingCache ) - { - // Mark these steps saved to disk. - FOREACH( Steps*, vpStepsToSave, s ) - (*s)->SetSavedToDisk( true ); - } + // Mark these steps saved to disk. + FOREACH( Steps*, vpStepsToSave, s ) + (*s)->SetSavedToDisk( true ); return true; } @@ -986,13 +1024,7 @@ bool Song::SaveToCacheFile() { SONGINDEX->AddCacheIndex(m_sSongDir, GetHashForDirectory(m_sSongDir)); const RString sPath = GetCacheFilePath(); - if( !SaveToSSCFile(sPath, true) ) - return false; - - FOREACH( Steps*, m_vpSteps, pSteps ) - (*pSteps)->SetFilename( sPath ); - - return true; + return SaveToSSCFile(sPath, true); } bool Song::SaveToDWIFile() @@ -1168,14 +1200,26 @@ bool Song::HasMusic() const return m_sMusicFile != "" && IsAFile(GetMusicPath()); } -bool Song::HasBanner() const {return m_sBannerFile != "" && IsAFile(GetBannerPath()); } +bool Song::HasBanner() const +{ + return m_sBannerFile != "" && IsAFile(GetBannerPath()); +} bool Song::HasInstrumentTrack( InstrumentTrack it ) const { - return m_sInstrumentTrackFile[it] != "" && IsAFile(GetInstrumentTrackPath(it)); + return m_sInstrumentTrackFile[it] != "" && IsAFile(GetInstrumentTrackPath(it)); +} +bool Song::HasLyrics() const +{ + return m_sLyricsFile != "" && IsAFile(GetLyricsPath()); +} +bool Song::HasBackground() const +{ + return m_sBackgroundFile != "" && IsAFile(GetBackgroundPath()); +} +bool Song::HasCDTitle() const +{ + return m_sCDTitleFile != "" && IsAFile(GetCDTitlePath()); } -bool Song::HasLyrics() const {return m_sLyricsFile != "" && IsAFile(GetLyricsPath()); } -bool Song::HasBackground() const {return m_sBackgroundFile != "" && IsAFile(GetBackgroundPath()); } -bool Song::HasCDTitle() const {return m_sCDTitleFile != "" && IsAFile(GetCDTitlePath()); } bool Song::HasBGChanges() const { FOREACH_BackgroundLayer( i ) @@ -1206,6 +1250,45 @@ vector &Song::GetForegroundChanges() return *m_ForegroundChanges.Get(); } +vector Song::GetChangesToVectorString(const vector & changes) const +{ + vector ret; + FOREACH_CONST( BackgroundChange, changes, bgc ) + { + ret.push_back((*bgc).ToString()); + } + return ret; +} + +vector Song::GetBGChanges1ToVectorString() const +{ + return this->GetChangesToVectorString(this->GetBackgroundChanges(BACKGROUND_LAYER_1)); +} + +vector Song::GetBGChanges2ToVectorString() const +{ + return this->GetChangesToVectorString(this->GetBackgroundChanges(BACKGROUND_LAYER_2)); +} + +vector Song::GetFGChanges1ToVectorString() const +{ + return this->GetChangesToVectorString(this->GetForegroundChanges()); +} + +vector Song::GetInstrumentTracksToVectorString() const +{ + vector ret; + FOREACH_ENUM(InstrumentTrack, it) + { + if (this->HasInstrumentTrack(it)) + { + ret.push_back(InstrumentTrackToString(it) + + "=" + + this->m_sInstrumentTrackFile[it]); + } + } + return ret; +} RString GetSongAssetPath( RString sPath, const RString &sSongPath ) { @@ -1452,8 +1535,7 @@ bool Song::HasSignificantBpmChangesOrStops() const float Song::GetStepsSeconds() const { - const TimingData &timing = this->m_SongTiming; - return timing.GetElapsedTimeFromBeat( m_fLastBeat ) - timing.GetElapsedTimeFromBeat( m_fFirstBeat ); + return this->GetLastSecond() - this->GetFirstSecond(); } bool Song::IsLong() const @@ -1473,16 +1555,46 @@ bool Song::IsMarathon() const class LunaSong: public Luna { public: - static int GetDisplayFullTitle( T* p, lua_State *L ) { lua_pushstring(L, p->GetDisplayFullTitle() ); return 1; } - static int GetTranslitFullTitle( T* p, lua_State *L ) { lua_pushstring(L, p->GetTranslitFullTitle() ); return 1; } - static int GetDisplayMainTitle( T* p, lua_State *L ) { lua_pushstring(L, p->GetDisplayMainTitle() ); return 1; } - static int GetTranslitMainTitle( T* p, lua_State *L ) { lua_pushstring(L, p->GetTranslitMainTitle() ); return 1; } - static int GetDisplaySubTitle( T* p, lua_State *L ) { lua_pushstring(L, p->GetDisplaySubTitle() ); return 1; } - static int GetTranslitSubTitle( T* p, lua_State *L ) { lua_pushstring(L, p->GetTranslitSubTitle() ); return 1; } - static int GetDisplayArtist( T* p, lua_State *L ) { lua_pushstring(L, p->GetDisplayArtist() ); return 1; } - static int GetTranslitArtist( T* p, lua_State *L ) { lua_pushstring(L, p->GetTranslitArtist() ); return 1; } - static int GetGenre( T* p, lua_State *L ) { lua_pushstring(L, p->m_sGenre ); return 1; } - static int GetOrigin( T* p, lua_State *L ) { lua_pushstring(L, p->m_sOrigin ); return 1; } + static int GetDisplayFullTitle( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetDisplayFullTitle() ); return 1; + } + static int GetTranslitFullTitle( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetTranslitFullTitle() ); return 1; + } + static int GetDisplayMainTitle( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetDisplayMainTitle() ); return 1; + } + static int GetTranslitMainTitle( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetTranslitMainTitle() ); return 1; + } + static int GetDisplaySubTitle( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetDisplaySubTitle() ); return 1; + } + static int GetTranslitSubTitle( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetTranslitSubTitle() ); return 1; + } + static int GetDisplayArtist( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetDisplayArtist() ); return 1; + } + static int GetTranslitArtist( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetTranslitArtist() ); return 1; + } + static int GetGenre( T* p, lua_State *L ) + { + lua_pushstring(L, p->m_sGenre ); return 1; + } + static int GetOrigin( T* p, lua_State *L ) + { + lua_pushstring(L, p->m_sOrigin ); return 1; + } static int GetAllSteps( T* p, lua_State *L ) { const vector &v = p->GetAllSteps(); @@ -1496,26 +1608,91 @@ public: LuaHelpers::CreateTableFromArray( v, L ); return 1; } - static int GetSongDir( T* p, lua_State *L ) { lua_pushstring(L, p->GetSongDir() ); return 1; } - static int GetMusicPath( T* p, lua_State *L ) { RString s = p->GetMusicPath(); if( s.empty() ) return 0; lua_pushstring(L, s); return 1; } - static int GetBannerPath( T* p, lua_State *L ) { RString s = p->GetBannerPath(); if( s.empty() ) return 0; LuaHelpers::Push(L, s); return 1; } + static int GetSongDir( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetSongDir() ); + return 1; + } + static int GetMusicPath( T* p, lua_State *L ) + { + RString s = p->GetMusicPath(); + if( !s.empty() ) + lua_pushstring(L, s); + else + lua_pushnil(L); + return 1; + } + static int GetBannerPath( T* p, lua_State *L ) + { + RString s = p->GetBannerPath(); + if( !s.empty() ) + lua_pushstring(L, s); + else + lua_pushnil(L); + return 1; + } static int GetBackgroundPath( T* p, lua_State *L ) { RString s = p->GetBackgroundPath(); - if( s.empty() ) - s = ""; - lua_pushstring(L, s); + if( !s.empty() ) + lua_pushstring(L, s); + else + lua_pushnil(L); return 1; } - static int GetCDTitlePath( T* p, lua_State *L ) { RString s = p->GetCDTitlePath(); if( s.empty() ) return 0; LuaHelpers::Push(L, s); return 1; } - static int GetLyricsPath( T* p, lua_State *L ) { RString s = p->GetLyricsPath(); if( s.empty() ) return 0; lua_pushstring(L, s); return 1; } - static int GetSongFilePath( T* p, lua_State *L ) { lua_pushstring(L, p->GetSongFilePath() ); return 1; } - static int IsTutorial( T* p, lua_State *L ) { lua_pushboolean(L, p->IsTutorial()); return 1; } - static int IsEnabled( T* p, lua_State *L ) { lua_pushboolean(L, p->GetEnabled()); return 1; } - static int GetGroupName( T* p, lua_State *L ) { lua_pushstring(L, p->m_sGroupName); return 1; } - static int MusicLengthSeconds( T* p, lua_State *L ) { lua_pushnumber(L, p->m_fMusicLengthSeconds); return 1; } - static int IsLong( T* p, lua_State *L ) { lua_pushboolean(L, p->IsLong()); return 1; } - static int IsMarathon( T* p, lua_State *L ) { lua_pushboolean(L, p->IsMarathon()); return 1; } + static int GetCDTitlePath( T* p, lua_State *L ) + { + RString s = p->GetCDTitlePath(); + if( !s.empty() ) + lua_pushstring(L, s); + else + lua_pushnil(L); + return 1; + } + static int GetLyricsPath( T* p, lua_State *L ) + { + RString s = p->GetLyricsPath(); + if( !s.empty() ) + lua_pushstring(L, s); + else + lua_pushnil(L); + return 1; + } + static int GetSongFilePath( T* p, lua_State *L ) + { + lua_pushstring(L, p->GetSongFilePath() ); + return 1; + } + static int IsTutorial( T* p, lua_State *L ) + { + lua_pushboolean(L, p->IsTutorial()); + return 1; + } + static int IsEnabled( T* p, lua_State *L ) + { + lua_pushboolean(L, p->GetEnabled()); + return 1; + } + static int GetGroupName( T* p, lua_State *L ) + { + lua_pushstring(L, p->m_sGroupName); + return 1; + } + static int MusicLengthSeconds( T* p, lua_State *L ) + { + lua_pushnumber(L, p->m_fMusicLengthSeconds); + return 1; + } + static int IsLong( T* p, lua_State *L ) + { + lua_pushboolean(L, p->IsLong()); + return 1; + } + static int IsMarathon( T* p, lua_State *L ) + { + lua_pushboolean(L, p->IsMarathon()); + return 1; + } static int HasStepsType( T* p, lua_State *L ) { StepsType st = Enum::Check(L, 1); @@ -1529,7 +1706,8 @@ public: lua_pushboolean( L, p->HasStepsTypeAndDifficulty(st, dc) ); return 1; } - // TODO: HasStepsTypeAndDifficulty and GetOneSteps should be in a SongUtil Lua table and a method of Steps. + /* TODO: HasStepsTypeAndDifficulty and GetOneSteps should be in + * a SongUtil Lua table and a method of Steps. */ static int GetOneSteps( T* p, lua_State *L ) { StepsType st = Enum::Check(L, 1); @@ -1547,14 +1725,42 @@ public: return 1; } // has functions - static int HasMusic( T* p, lua_State *L ) { lua_pushboolean(L, p->HasMusic()); return 1; } - static int HasBanner( T* p, lua_State *L ) { lua_pushboolean(L, p->HasBanner()); return 1; } - static int HasBackground( T* p, lua_State *L ) { lua_pushboolean(L, p->HasBackground()); return 1; } - static int HasCDTitle( T* p, lua_State *L ) { lua_pushboolean(L, p->HasCDTitle()); return 1; } - static int HasBGChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasBGChanges()); return 1; } - static int HasLyrics( T* p, lua_State *L ) { lua_pushboolean(L, p->HasLyrics()); return 1; } + static int HasMusic( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasMusic()); + return 1; + } + static int HasBanner( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasBanner()); + return 1; + } + static int HasBackground( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasBackground()); + return 1; + } + static int HasCDTitle( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasCDTitle()); + return 1; + } + static int HasBGChanges( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasBGChanges()); + return 1; + } + static int HasLyrics( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasLyrics()); + return 1; + } // functions that AJ loves - static int HasSignificantBPMChangesOrStops( T* p, lua_State *L ) { lua_pushboolean(L, p->HasSignificantBpmChangesOrStops()); return 1; } + static int HasSignificantBPMChangesOrStops( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasSignificantBpmChangesOrStops()); + return 1; + } static int HasEdits( T* p, lua_State *L ) { StepsType st = Enum::Check(L, 1); @@ -1567,11 +1773,41 @@ public: lua_pushboolean(L, p->IsEasy( st )); return 1; } - static int GetStepsSeconds( T* p, lua_State *L ) { lua_pushnumber(L, p->GetStepsSeconds()); return 1; } - static int NormallyDisplayed( T* p, lua_State *L ){ lua_pushboolean(L, p->NormallyDisplayed()); return 1; } - static int GetFirstBeat( T* p, lua_State *L ) { lua_pushnumber(L, p->m_fFirstBeat); return 1; } - static int GetLastBeat( T* p, lua_State *L ) { lua_pushnumber(L, p->m_fLastBeat); return 1; } - static int HasAttacks( T* p, lua_State *L ) { lua_pushboolean(L, p->HasAttacks()); return 1; } + static int GetStepsSeconds( T* p, lua_State *L ) + { + lua_pushnumber(L, p->GetStepsSeconds()); + return 1; + } + static int NormallyDisplayed( T* p, lua_State *L ) + { + lua_pushboolean(L, p->NormallyDisplayed()); + return 1; + } + static int GetFirstSecond(T* p, lua_State *L) + { + lua_pushnumber(L, p->GetFirstSecond()); + return 1; + } + static int GetLastSecond(T* p, lua_State *L) + { + lua_pushnumber(L, p->GetLastSecond()); + return 1; + } + static int GetFirstBeat( T* p, lua_State *L ) + { + lua_pushnumber(L, p->GetFirstBeat()); + return 1; + } + static int GetLastBeat( T* p, lua_State *L ) + { + lua_pushnumber(L, p->GetLastBeat()); + return 1; + } + static int HasAttacks( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasAttacks()); + return 1; + } static int GetDisplayBpms( T* p, lua_State *L ) { DisplayBpms temp; @@ -1647,7 +1883,9 @@ public: ADD_METHOD( GetStepsSeconds ); ADD_METHOD( NormallyDisplayed ); ADD_METHOD( GetFirstBeat ); + ADD_METHOD( GetFirstSecond ); ADD_METHOD( GetLastBeat ); + ADD_METHOD( GetLastSecond ); ADD_METHOD( HasAttacks ); ADD_METHOD( GetDisplayBpms ); ADD_METHOD( IsDisplayBpmSecret ); diff --git a/src/Song.h b/src/Song.h index cbe6e5ddf4..5f17ad8969 100644 --- a/src/Song.h +++ b/src/Song.h @@ -16,13 +16,16 @@ class StepsID; struct lua_State; struct BackgroundChange; +void FixupPath( RString &path, const RString &sSongPath ); +RString GetSongAssetPath( RString sPath, const RString &sSongPath ); + /** @brief The version of the .ssc file format. */ -const static float STEPFILE_VERSION_NUMBER = 0.7f; +const static float STEPFILE_VERSION_NUMBER = 0.77f; /** @brief How many edits for this song can each profile have? */ -const int MAX_EDITS_PER_SONG_PER_PROFILE = 5; +const int MAX_EDITS_PER_SONG_PER_PROFILE = 15; /** @brief How many edits for this song can be available? */ -const int MAX_EDITS_PER_SONG = 5*NUM_ProfileSlot; +const int MAX_EDITS_PER_SONG = MAX_EDITS_PER_SONG_PER_PROFILE * NUM_ProfileSlot; extern const int FILE_CACHE_VERSION; @@ -36,14 +39,6 @@ enum BackgroundLayer BACKGROUND_LAYER_Invalid }; -/** @brief The different ways of displaying the BPM. */ -enum DisplayBPM -{ - DISPLAY_BPM_ACTUAL, /**< Display the song's actual BPM. */ - DISPLAY_BPM_SPECIFIED, /**< Display a specified value or values. */ - DISPLAY_BPM_RANDOM /**< Display a random selection of BPMs. */ -}; - /** @brief A custom foreach loop for the different background layers. */ #define FOREACH_BackgroundLayer( bl ) FOREACH_ENUM( BackgroundLayer, bl ) @@ -96,14 +91,19 @@ public: // This one takes the effort to reuse Steps pointers as best as it can bool ReloadFromSongDir( RString sDir ); - /** @brief Call this after loading a song to clean up invalid data. */ - void TidyUpData( bool bFromCache = false ); + /** + * @brief Call this after loading a song to clean up invalid data. + * @param fromCache was this data loaded from the cache file? + * @param duringCache was this data loaded during the cache process? */ + void TidyUpData( bool fromCache = false, bool duringCache = false ); /** - * @brief Get the new radar values, and determine the last beat at the same time. + * @brief Get the new radar values, and determine the last second at the same time. * - * This is called by TidyUpData, after saving the Song. */ - void ReCalculateRadarValuesAndLastBeat( bool bFromCache = false ); + * This is called by TidyUpData, after saving the Song. + * @param fromCache was this data loaded from the cache file? + * @param duringCache was this data loaded during the cache process? */ + void ReCalculateRadarValuesAndLastSecond(bool fromCache = false, bool duringCache = false); /** * @brief Translate any titles that aren't in english. * @@ -185,7 +185,6 @@ public: RString GetDisplaySubTitle() const; RString GetDisplayArtist() const; - // Returns the transliterated titles, if any; otherwise returns the main titles. /** * @brief Retrieve the transliterated title, or the main title if there is no translit. * @return the proper title. */ @@ -228,10 +227,8 @@ public: RString m_sMusicFile; RString m_sInstrumentTrackFile[NUM_InstrumentTrack]; + /** @brief The length of the music file. */ float m_fMusicLengthSeconds; - float m_fFirstBeat; // beat of first note - float m_fLastBeat; // beat of last note - float m_fSpecifiedLastBeat; // specified last beat of the song float m_fMusicSampleStartSeconds; float m_fMusicSampleLengthSeconds; DisplayBPM m_DisplayBPMType; @@ -286,9 +283,26 @@ public: /** @brief The Song's TimingData. */ TimingData m_SongTiming; + + float GetFirstBeat() const; + float GetFirstSecond() const; + float GetLastBeat() const; + float GetLastSecond() const; + float GetSpecifiedLastBeat() const; + float GetSpecifiedLastSecond() const; + + void SetFirstSecond(const float f); + void SetLastSecond(const float f); + void SetSpecifiedLastSecond(const float f); typedef vector VBackgroundChange; private: + /** @brief The first second that a note is hit. */ + float firstSecond; + /** @brief The last second that a note is hit. */ + float lastSecond; + /** @brief The last second of the song for playing purposes. */ + float specifiedLastSecond; /** * @brief The background changes (sorted by layer) that are for this Song. * @@ -305,12 +319,20 @@ private: * * This must be sorted before gameplay. */ AutoPtrCopyOnWrite m_ForegroundChanges; + + vector GetChangesToVectorString(const vector & changes) const; public: const vector &GetBackgroundChanges( BackgroundLayer bl ) const; vector &GetBackgroundChanges( BackgroundLayer bl ); const vector &GetForegroundChanges() const; vector &GetForegroundChanges(); + vector GetBGChanges1ToVectorString() const; + vector GetBGChanges2ToVectorString() const; + vector GetFGChanges1ToVectorString() const; + + vector GetInstrumentTracksToVectorString() const; + /** * @brief The list of LyricSegments. * @@ -416,6 +438,11 @@ public: CachedObject m_CachedObject; + RString GetAttackString() const + { + return join(":", this->m_sAttackString); + } + // Lua void PushSelf( lua_State *L ); diff --git a/src/SongManager.cpp b/src/SongManager.cpp index 48a7d3c5eb..9550ae3c75 100644 --- a/src/SongManager.cpp +++ b/src/SongManager.cpp @@ -88,16 +88,19 @@ SongManager::~SongManager() FreeSongs(); } -void SongManager::InitAll( LoadingWindow *ld ) +void SongManager::InitAll() { - InitSongsFromDisk( ld ); - InitCoursesFromDisk( ld ); + InitSongsFromDisk(); + + InitCoursesFromDisk(); InitAutogenCourses(); InitRandomAttacks(); } static LocalizedString RELOADING ( "SongManager", "Reloading..." ); -void SongManager::Reload( bool bAllowFastLoad, LoadingWindow *ld ) +static LocalizedString UNLOADING_SONGS ( "SongManager", "Unloading songs..." ); +static LocalizedString UNLOADING_COURSES ( "SongManager", "Unloading courses..." ); +void SongManager::Reload( bool bAllowFastLoad ) { FILEMAN->FlushDirCache( SpecialFiles::SONGS_DIR ); FILEMAN->FlushDirCache( ADDITIONAL_SONGS_DIR ); @@ -105,20 +108,26 @@ void SongManager::Reload( bool bAllowFastLoad, LoadingWindow *ld ) FILEMAN->FlushDirCache( ADDITIONAL_COURSES_DIR ); FILEMAN->FlushDirCache( EDIT_SUBDIR ); - if( ld ) - ld->SetText( RELOADING ); + if( pLoadingWindow ) + pLoadingWindow->SetText( RELOADING ); // save scores before unloading songs, of the scores will be lost PROFILEMAN->SaveMachineProfile(); + if( pLoadingWindow ) + pLoadingWindow->SetText( UNLOADING_COURSES ); + FreeCourses(); + + if( pLoadingWindow ) + pLoadingWindow->SetText( UNLOADING_SONGS ); FreeSongs(); const bool OldVal = PREFSMAN->m_bFastLoad; if( !bAllowFastLoad ) PREFSMAN->m_bFastLoad.Set( false ); - InitAll( ld ); + InitAll(); // reload scores and unlocks afterward PROFILEMAN->LoadMachineProfile(); @@ -130,14 +139,14 @@ void SongManager::Reload( bool bAllowFastLoad, LoadingWindow *ld ) UpdatePreferredSort(); } -void SongManager::InitSongsFromDisk( LoadingWindow *ld ) +void SongManager::InitSongsFromDisk() { RageTimer tm; - LoadStepManiaSongDir( SpecialFiles::SONGS_DIR, ld ); + LoadStepManiaSongDir( SpecialFiles::SONGS_DIR); const bool bOldVal = PREFSMAN->m_bFastLoad; PREFSMAN->m_bFastLoad.Set( PREFSMAN->m_bFastLoadAdditionalSongs ); - LoadStepManiaSongDir( ADDITIONAL_SONGS_DIR, ld ); + LoadStepManiaSongDir( ADDITIONAL_SONGS_DIR ); PREFSMAN->m_bFastLoad.Set( bOldVal ); LOG->Trace( "Found %d songs in %f seconds.", (int)m_pSongs.size(), tm.GetDeltaTime() ); @@ -224,7 +233,7 @@ void SongManager::AddGroup( RString sDir, RString sGroupDirName ) } static LocalizedString LOADING_SONGS ( "SongManager", "Loading songs..." ); -void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) +void SongManager::LoadStepManiaSongDir( RString sDir ) { // Make sure sDir has a trailing slash. if( sDir.Right(1) != "/" ) @@ -236,11 +245,16 @@ void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) SortRStringArray( arrayGroupDirs ); StripCvsAndSvn( arrayGroupDirs ); StripMacResourceForks( arrayGroupDirs ); - + + vector< vector > arrayGroupSongDirs; + int groupIndex, songCount, songIndex; + + groupIndex = 0; + songCount = 0; FOREACH_CONST( RString, arrayGroupDirs, s ) // foreach dir in /Songs/ { + RString sGroupDirName = *s; - SanityCheckGroupDir(sDir+sGroupDirName); // Find all Song folders in this group directory @@ -249,6 +263,25 @@ void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) StripCvsAndSvn( arraySongDirs ); StripMacResourceForks( arraySongDirs ); SortRStringArray( arraySongDirs ); + + arrayGroupSongDirs.push_back(arraySongDirs); + songCount += arraySongDirs.size(); + + } + + if( songCount==0 ) return; + + if( pLoadingWindow ) { + pLoadingWindow->SetIndeterminate( false ); + pLoadingWindow->SetTotalWork( songCount ); + } + + groupIndex = 0; + songIndex = 0; + FOREACH_CONST( RString, arrayGroupDirs, s ) // foreach dir in /Songs/ + { + RString sGroupDirName = *s; + vector &arraySongDirs = arrayGroupSongDirs[groupIndex++]; LOG->Trace("Attempting to load %i songs from \"%s\"", int(arraySongDirs.size()), (sDir+sGroupDirName).c_str() ); @@ -261,12 +294,12 @@ void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) RString sSongDirName = arraySongDirs[j]; // this is a song directory. Load a new song. - if( ld ) + if( pLoadingWindow ) { - ld->SetText( LOADING_SONGS.GetValue()+ssprintf("\n%s\n%s", + pLoadingWindow->SetProgress(songIndex); + pLoadingWindow->SetText( LOADING_SONGS.GetValue()+ssprintf("\n%s\n%s", Basename(sGroupDirName).c_str(), Basename(sSongDirName).c_str())); - ld->Paint(); } Song* pNewSong = new Song; if( !pNewSong->LoadFromSongDir( sSongDirName ) ) @@ -279,6 +312,7 @@ void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) m_pSongs.push_back( pNewSong ); index_entry.push_back( pNewSong ); loaded++; + songIndex++; } LOG->Trace("Loaded %i songs from \"%s\"", loaded, (sDir+sGroupDirName).c_str() ); @@ -296,6 +330,10 @@ void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) LoadGroupSymLinks(sDir, sGroupDirName); } + if( pLoadingWindow ) { + pLoadingWindow->SetIndeterminate( true ); + } + LoadEnabledSongsFromPref(); } @@ -720,7 +758,7 @@ RString SongManager::ShortenGroupName( RString sLongGroupName ) } static LocalizedString LOADING_COURSES ( "SongManager", "Loading courses..." ); -void SongManager::InitCoursesFromDisk( LoadingWindow *ld ) +void SongManager::InitCoursesFromDisk() { LOG->Trace( "Loading courses." ); @@ -750,12 +788,11 @@ void SongManager::InitCoursesFromDisk( LoadingWindow *ld ) FOREACH_CONST( RString, vsCoursePaths, sCoursePath ) { - if( ld ) + if( pLoadingWindow ) { - ld->SetText( LOADING_COURSES.GetValue()+ssprintf("\n%s\n%s", + pLoadingWindow->SetText( LOADING_COURSES.GetValue()+ssprintf("\n%s\n%s", Basename(*sCourseGroup).c_str(), Basename(*sCoursePath).c_str())); - ld->Paint(); } Course* pCourse = new Course; @@ -962,11 +999,14 @@ void SongManager::Cleanup() for( unsigned i=0; i& vpSteps = pSong->GetAllSteps(); - for( unsigned n=0; nCompress(); + const vector& vpSteps = pSong->GetAllSteps(); + for( unsigned n=0; nCompress(); + } } } } @@ -1655,12 +1695,15 @@ void SongManager::LoadStepEditsFromProfileDir( const RString &sProfileDir, Profi for( int i=0; i &vpSongsInOut, bool b RString foo; foo.reserve(256); - for( int g=Grade_Tier01; g<=Grade_NoData; ++g ) + for( int g=Grade_Tier01; gGetAllSteps(), s ) + { + Steps *pSteps = *s; + + if( pSteps->m_StepsType != st ) + continue; + if( pSteps == pExclude ) + continue; + if( pSteps->GetChartName() == name ) + return false; + } + return true; +} + RString SongUtil::MakeUniqueEditDescription( const Song *pSong, StepsType st, const RString &sPreferredDescription ) { if( IsEditDescriptionUnique( pSong, st, sPreferredDescription, NULL ) ) @@ -760,7 +776,7 @@ RString SongUtil::MakeUniqueEditDescription( const Song *pSong, StepsType st, co { // make name "My Edit" -> "My Edit2" RString sNum = ssprintf("%d", i+1); - sTemp = sPreferredDescription.Left( MAX_EDIT_STEPS_DESCRIPTION_LENGTH - sNum.size() ) + sNum; + sTemp = sPreferredDescription.Left( MAX_STEPS_DESCRIPTION_LENGTH - sNum.size() ) + sNum; if( IsEditDescriptionUnique(pSong, st, sTemp, NULL) ) return sTemp; @@ -772,8 +788,11 @@ RString SongUtil::MakeUniqueEditDescription( const Song *pSong, StepsType st, co } static LocalizedString YOU_MUST_SUPPLY_NAME ( "SongUtil", "You must supply a name for your new edit." ); +static LocalizedString CHART_NAME_CONFLICTS ("SongUtil", "The name you chose conflicts with another chart. Please use a different name."); static LocalizedString EDIT_NAME_CONFLICTS ( "SongUtil", "The name you chose conflicts with another edit. Please use a different name." ); +static LocalizedString CHART_NAME_CANNOT_CONTAIN ("SongUtil", "The chart name cannot contain any of the following characters: %s" ); static LocalizedString EDIT_NAME_CANNOT_CONTAIN ( "SongUtil", "The edit name cannot contain any of the following characters: %s" ); + bool SongUtil::ValidateCurrentEditStepsDescription( const RString &sAnswer, RString &sErrorOut ) { Steps *pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; @@ -833,6 +852,31 @@ bool SongUtil::ValidateCurrentStepsDescription( const RString &sAnswer, RString return true; } +bool SongUtil::ValidateCurrentStepsChartName(const RString &answer, RString &error) +{ + if (answer.empty()) return true; + + static const RString sInvalidChars = "\\/:*?\"<>|"; + if( strpbrk(answer, sInvalidChars) != NULL ) + { + error = ssprintf( CHART_NAME_CANNOT_CONTAIN.GetValue(), sInvalidChars.c_str() ); + return false; + } + + /* Don't allow duplicate title names within the same StepsType. + * We need some way of identifying the unique charts. */ + Steps *pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; + + if (pSteps->GetChartName() == answer) return true; + + // TODO next commit: borrow code from EditStepsDescription. + bool result = SongUtil::IsChartNameUnique(GAMESTATE->m_pCurSong, pSteps->m_StepsType, + answer, pSteps); + if (!result) + error = CHART_NAME_CONFLICTS; + return result; +} + static LocalizedString AUTHOR_NAME_CANNOT_CONTAIN( "SongUtil", "The step author's name cannot contain any of the following characters: %s" ); bool SongUtil::ValidateCurrentStepsCredit( const RString &sAnswer, RString &sErrorOut ) @@ -871,13 +915,15 @@ void SongUtil::GetAllSongGenres( vector &vsOut ) } } -void SongUtil::FilterSongs( const SongCriteria &sc, const vector &in, vector &out ) +void SongUtil::FilterSongs( const SongCriteria &sc, const vector &in, + vector &out, bool doCareAboutGame ) { out.reserve( in.size() ); FOREACH_CONST( Song*, in, s ) { - if( sc.Matches( *s ) ) + if( sc.Matches( *s ) && (!doCareAboutGame || IsSongPlayable(*s) ) ) { + out.push_back( *s ); } } @@ -927,7 +973,9 @@ void SongUtil::GetPlayableStepsTypes( const Song *pSong, set &vOut ) iNumPlayers = max( iNumPlayers, 1 ); const Style *pStyle = GAMEMAN->GetFirstCompatibleStyle( GAMESTATE->m_pCurGame, iNumPlayers, *st ); - bool bEnoughStages = GAMESTATE->IsAnExtraStage() || GAMESTATE->GetSmallestNumStagesLeftForAnyHumanPlayer() >= GAMESTATE->GetNumStagesForSongAndStyleType(pSong, pStyle->m_StyleType); + bool bEnoughStages = GAMESTATE->IsAnExtraStage() || + GAMESTATE->GetSmallestNumStagesLeftForAnyHumanPlayer() >= + GAMESTATE->GetNumStagesForSongAndStyleType(pSong, pStyle->m_StyleType); if( bShowThisStepsType && bEnoughStages ) vOut.insert( *st ); @@ -961,6 +1009,21 @@ bool SongUtil::IsStepsPlayable( Song *pSong, Steps *pSteps ) return find( vpSteps.begin(), vpSteps.end(), pSteps ) != vpSteps.end(); } +bool SongUtil::IsSongPlayable( Song *s ) +{ + const vector & steps = s->GetAllSteps(); + // I'm sure there is a foreach loop, but I don't + FOREACH( Steps*, const_cast&>(steps), step ) + { + if (IsStepsPlayable(s, *step)) + { + return true; + } + } + + return false; +} + bool SongUtil::GetStepsTypeAndDifficultyFromSortOrder( SortOrder so, StepsType &stOut, Difficulty &dcOut ) { switch( so ) @@ -1078,6 +1141,14 @@ bool SongID::IsValid() const namespace { + int GetPlayableSteps( lua_State *L ) + { + const Song *pSong = Luna::check( L, 1, true ); + vector vSteps; + SongUtil::GetPlayableSteps(pSong,vSteps); + LuaHelpers::CreateTableFromArray( vSteps, L ); + return 1; + } int IsStepsTypePlayable( lua_State *L ) { Song *pSong = Luna::check( L, 1, true ); @@ -1097,6 +1168,7 @@ namespace const luaL_Reg SongUtilTable[] = { + LIST_METHOD( GetPlayableSteps ), LIST_METHOD( IsStepsTypePlayable ), LIST_METHOD( IsStepsPlayable ), { NULL, NULL } diff --git a/src/SongUtil.h b/src/SongUtil.h index 0c0a18043d..f09bf2ff8c 100644 --- a/src/SongUtil.h +++ b/src/SongUtil.h @@ -13,6 +13,8 @@ class Steps; class Profile; class XNode; +void AppendOctal( int n, int digits, RString &out ); + /** @brief The criteria for dealing with songs. */ class SongCriteria { @@ -157,18 +159,33 @@ namespace SongUtil * @return true if it is unique, false otherwise. */ bool IsEditDescriptionUnique( const Song* pSong, StepsType st, const RString &sPreferredDescription, const Steps *pExclude ); + bool IsChartNameUnique( const Song* pSong, StepsType st, const RString &name, const Steps *pExclude ); RString MakeUniqueEditDescription( const Song* pSong, StepsType st, const RString &sPreferredDescription ); bool ValidateCurrentEditStepsDescription( const RString &sAnswer, RString &sErrorOut ); bool ValidateCurrentStepsDescription( const RString &sAnswer, RString &sErrorOut ); bool ValidateCurrentStepsCredit( const RString &sAnswer, RString &sErrorOut ); + bool ValidateCurrentStepsChartName(const RString &answer, RString &error); void GetAllSongGenres( vector &vsOut ); - void FilterSongs( const SongCriteria &sc, const vector &in, vector &out ); + /** + * @brief Filter the selection of songs to only match certain criteria. + * @param sc the intended song criteria. + * @param in the starting batch of songs. + * @param out the resulting batch. + * @param doCareAboutGame a flag to see if we should only get playable steps. */ + void FilterSongs( const SongCriteria &sc, const vector &in, vector &out, + bool doCareAboutGame = false ); void GetPlayableStepsTypes( const Song *pSong, set &vOut ); void GetPlayableSteps( const Song *pSong, vector &vOut ); bool IsStepsTypePlayable( Song *pSong, StepsType st ); bool IsStepsPlayable( Song *pSong, Steps *pSteps ); + + /** + * @brief Determine if the song has any playable steps in the present game. + * @param s the current song. + * @return true if the song has playable steps, false otherwise. */ + bool IsSongPlayable( Song *s ); bool GetStepsTypeAndDifficultyFromSortOrder( SortOrder so, StepsType &st, Difficulty &dc ); } diff --git a/src/Sprite.h b/src/Sprite.h index 7247171f70..3a941ec28c 100644 --- a/src/Sprite.h +++ b/src/Sprite.h @@ -4,6 +4,8 @@ #include "Actor.h" #include "RageTextureID.h" +void TexCoordArrayFromRect( float fImageCoords[8], const RectF &rect ); + class RageTexture; /** @brief A bitmap Actor that animates and moves around. */ class Sprite: public Actor diff --git a/src/StatsManager.cpp b/src/StatsManager.cpp index 99a95a10c7..ade50e7b5a 100644 --- a/src/StatsManager.cpp +++ b/src/StatsManager.cpp @@ -16,6 +16,8 @@ StatsManager* STATSMAN = NULL; // global object accessable from anywhere in the program +void AddPlayerStatsToProfile( Profile *pProfile, const StageStats &ss, PlayerNumber pn ); +XNode* MakeRecentScoreNode( const StageStats &ss, Trail *pTrail, const PlayerStageStats &pss, MultiPlayer mp ); StatsManager::StatsManager() { @@ -240,10 +242,14 @@ void StatsManager::CommitStatsToProfiles( const StageStats *pSS ) pPlayerProfile->m_iNumTotalSongsPlayed += pSS->m_vpPlayedSongs.size(); } + LOG->Trace("Adding stats to machine profile..."); AddPlayerStatsToProfile( pMachineProfile, *pSS, pn ); if( pPlayerProfile ) + { + LOG->Trace("Adding stats to player profile..."); AddPlayerStatsToProfile( pPlayerProfile, *pSS, pn ); + } CHECKPOINT; } @@ -275,7 +281,7 @@ void StatsManager::CommitStatsToProfiles( const StageStats *pSS ) { if( pSS->m_multiPlayer[mp].m_HighScore.IsEmpty() ) continue; - recent->AppendChild( MakeRecentScoreNode( *pSS, GAMESTATE->m_pCurTrail[GAMESTATE->m_MasterPlayerNumber], pSS->m_multiPlayer[mp], mp ) ); + recent->AppendChild( MakeRecentScoreNode( *pSS, GAMESTATE->m_pCurTrail[GAMESTATE->GetMasterPlayerNumber()], pSS->m_multiPlayer[mp], mp ) ); } } diff --git a/src/StatsManager.h b/src/StatsManager.h index da7e869010..0b9b812e9b 100644 --- a/src/StatsManager.h +++ b/src/StatsManager.h @@ -2,6 +2,7 @@ #define StatsManager_H #include "StageStats.h" + /** @brief Managed non-persisted statistics. */ class StatsManager { diff --git a/src/StepMania-net2008.vcproj b/src/StepMania-net2008.vcproj index bcc20ea4b9..fa58c85a68 100644 --- a/src/StepMania-net2008.vcproj +++ b/src/StepMania-net2008.vcproj @@ -2,7 +2,7 @@ - - - - @@ -484,38 +476,6 @@ RelativePath="ScreenContinue.h" > - - - - - - - - - - - - - - - - @@ -540,14 +500,6 @@ RelativePath="ScreenExit.h" > - - - - @@ -556,14 +508,6 @@ RelativePath="ScreenHowToPlay.h" > - - - - @@ -580,14 +524,6 @@ RelativePath="ScreenJukebox.h" > - - - - @@ -620,46 +556,6 @@ RelativePath="ScreenNameEntryTraditional.h" > - - - - - - - - - - - - - - - - - - - - @@ -676,22 +572,6 @@ RelativePath="ScreenPlayerOptions.h" > - - - - - - - - @@ -700,14 +580,6 @@ RelativePath="ScreenPrompt.h" > - - - - @@ -796,14 +668,6 @@ RelativePath="ScreenSetTime.h" > - - - - @@ -820,22 +684,6 @@ RelativePath="ScreenSplash.h" > - - - - - - - - @@ -844,38 +692,6 @@ RelativePath="ScreenSystemLayer.h" > - - - - - - - - - - - - - - - - @@ -967,6 +783,14 @@ + + + + @@ -1064,6 +888,198 @@ > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + @@ -2810,6 +2832,14 @@ RelativePath="HelpDisplay.h" > + + + + diff --git a/src/StepMania-net2010.vcxproj b/src/StepMania-net2010.vcxproj index c1aef5d7d2..3b712c40e3 100644 --- a/src/StepMania-net2010.vcxproj +++ b/src/StepMania-net2010.vcxproj @@ -19,7 +19,7 @@ - sm-ssc + StepMania {AF209DBD-24BD-4356-8DFE-41751B221195} StepMania MFCProj @@ -67,16 +67,16 @@ <_ProjectFileVersion>10.0.30319.1 - $(TargetDir) - $(SolutionDir)/build-$(SolutionName)/$(ProjectName)/$(Configuration)\ + $(SolutionDir)$(Configuration)\ + $(Configuration)\ true true - $(TargetDir) - $(SolutionDir)/build-$(SolutionName)/$(ProjectName)/$(Configuration)\ + $(SolutionDir)$(Configuration)\ + $(Configuration)\ false - $(TargetDir) - $(SolutionDir)/build-$(SolutionName)/$(ProjectName)/$(Configuration)\ - false + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true true $(SolutionDir)$(Configuration)\ $(Configuration)\ @@ -149,7 +149,7 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) /MACHINE:I386 "$(IntDir)verstub.obj" %(AdditionalOptions) - shell32.lib;gdi32.lib;user32.lib;ole32.lib;advapi32.lib;ffmpeg/modern_working/lib/avcodec.lib;ffmpeg/modern_working/lib/avformat.lib;ffmpeg/modern_working/lib/avutil.lib;ffmpeg/modern_working/lib/swscale.lib;%(AdditionalDependencies) + shell32.lib;gdi32.lib;user32.lib;ole32.lib;advapi32.lib;Comctl32.lib;ffmpeg/modern_working/lib/avcodec.lib;ffmpeg/modern_working/lib/avformat.lib;ffmpeg/modern_working/lib/avutil.lib;ffmpeg/modern_working/lib/swscale.lib;%(AdditionalDependencies) ../Program/StepMania-debug.exe true ..\extern\libpng\lib;ffmpeg\lib;..\extern\libjpeg\;..\extern\zlib\;..\extern\mad-0.15.1b\msvc++\Release\%(AdditionalLibraryDirectories) @@ -216,7 +216,7 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) /MACHINE:I386 "$(IntDir)verstub.obj" %(AdditionalOptions) - shell32.lib;gdi32.lib;user32.lib;ole32.lib;advapi32.lib;ffmpeg/modern_working/lib/avcodec.lib;ffmpeg/modern_working/lib/avformat.lib;ffmpeg/modern_working/lib/avutil.lib;ffmpeg/modern_working/lib/swscale.lib;%(AdditionalDependencies) + shell32.lib;gdi32.lib;user32.lib;ole32.lib;advapi32.lib;Comctl32.lib;ffmpeg/modern_working/lib/avcodec.lib;ffmpeg/modern_working/lib/avformat.lib;ffmpeg/modern_working/lib/avutil.lib;ffmpeg/modern_working/lib/swscale.lib;%(AdditionalDependencies) ../Program/StepMania.exe true ..\extern\libpng\lib;ffmpeg\lib;..\extern\libjpeg\;..\extern\zlib\;..\extern\mad-0.15.1b\msvc++\Release\%(AdditionalLibraryDirectories) @@ -268,7 +268,7 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) true ProgramDatabase 4063;4100;4127;4201;4244;4275;4355;4505;4512;4702;4786;4996;%(DisableSpecificWarnings) - true + false AnySuitable true Speed @@ -280,7 +280,7 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) /MACHINE:I386 "$(IntDir)verstub.obj" %(AdditionalOptions) - shell32.lib;gdi32.lib;user32.lib;ole32.lib;advapi32.lib;avcodec.lib;avformat.lib;avutil.lib;swscale.lib;%(AdditionalDependencies) + shell32.lib;gdi32.lib;user32.lib;ole32.lib;advapi32.lib;Comctl32.lib;avcodec.lib;avformat.lib;avutil.lib;swscale.lib;%(AdditionalDependencies) ../Program/StepMania-fastdebug.exe true ..\extern\libpng\lib;ffmpeg\modern_working\lib;..\extern\libjpeg\;..\extern\zlib\;..\extern\mad-0.15.1b\msvc++\Release\;%(AdditionalLibraryDirectories) @@ -295,7 +295,7 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) SendErrorReport - UseLinkTimeCodeGeneration + Default archutils\Win32\mapconv "$(IntDir)$(TargetName).map" "$(TargetDir)\StepMania-fastdebug.vdi" @@ -349,7 +349,7 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) /MACHINE:I386 "$(IntDir)verstub.obj" %(AdditionalOptions) - shell32.lib;gdi32.lib;user32.lib;ole32.lib;advapi32.lib;ffmpeg/modern_working/lib/avcodec.lib;ffmpeg/modern_working/lib/avformat.lib;ffmpeg/modern_working/lib/avutil.lib;ffmpeg/modern_working/lib/swscale.lib;%(AdditionalDependencies) + shell32.lib;gdi32.lib;user32.lib;ole32.lib;advapi32.lib;Comctl32.lib;ffmpeg/modern_working/lib/avcodec.lib;ffmpeg/modern_working/lib/avformat.lib;ffmpeg/modern_working/lib/avutil.lib;ffmpeg/modern_working/lib/swscale.lib;%(AdditionalDependencies) ..\Program/StepMania-SSE2.exe true ..\extern\libpng\lib;ffmpeg\lib;..\extern\libjpeg\;..\extern\zlib\;..\extern\mad-0.15.1b\msvc++\Release\%(AdditionalLibraryDirectories) @@ -420,7 +420,6 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) - @@ -643,6 +642,7 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) + @@ -1689,6 +1689,7 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) + @@ -1738,7 +1739,6 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) - @@ -2395,4 +2395,4 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir) - + \ No newline at end of file diff --git a/src/StepMania-net2010.vcxproj.filters b/src/StepMania-net2010.vcxproj.filters index 0d28f9a2c7..2a3608a7c2 100644 --- a/src/StepMania-net2010.vcxproj.filters +++ b/src/StepMania-net2010.vcxproj.filters @@ -264,9 +264,6 @@ Screens - - Screens - Screens @@ -1629,6 +1626,9 @@ Data Structures + + Actors used in Menus + @@ -1778,9 +1778,6 @@ Screens - - Screens - Screens @@ -3026,6 +3023,9 @@ Data Structures + + Actors used in Menus + @@ -3154,4 +3154,4 @@ BaseClasses - + \ No newline at end of file diff --git a/src/StepMania.cpp b/src/StepMania.cpp index 97a897820a..6d1c75ea19 100644 --- a/src/StepMania.cpp +++ b/src/StepMania.cpp @@ -72,6 +72,10 @@ #include #endif +void ShutdownGame(); +bool HandleGlobalInputs( const InputEventPlus &input ); +void HandleInputEvents(float fDeltaTime); + static Preference g_bAllowMultipleInstances( "AllowMultipleInstances", false ); void StepMania::GetPreferredVideoModeParams( VideoModeParams ¶msOut ) @@ -1011,7 +1015,7 @@ int main(int argc, char* argv[]) GAMESTATE = new GameState; // This requires PREFSMAN, for PREFSMAN->m_bShowLoadingWindow. - LoadingWindow *pLoadingWindow = LoadingWindow::Create(); + pLoadingWindow = LoadingWindow::Create(); if(pLoadingWindow == NULL) RageException::Throw("%s", COULDNT_OPEN_LOADING_WINDOW.GetValue().c_str()); @@ -1037,57 +1041,75 @@ int main(int argc, char* argv[]) // Switch to the last used game type, and set up the theme and announcer. SwitchToLastPlayedGame(); - CommandLineActions::Handle(pLoadingWindow); + CommandLineActions::Handle(); if( GetCommandlineArgument("dopefish") ) GAMESTATE->m_bDopefish = true; { - /* Now that THEME is loaded, load the icon for the current theme into - * the loading window. */ + /* Now that THEME is loaded, load the icon and splash for the current + * theme into the loading window. */ RString sError; RageSurface *pIcon = RageSurfaceUtils::LoadFile( THEME->GetPathG( "Common", "window icon" ), sError ); if( pIcon ) pLoadingWindow->SetIcon( pIcon ); delete pIcon; + pLoadingWindow->SetSplash( THEME->GetPathG("Common","splash") ); } if( PREFSMAN->m_iSoundWriteAhead ) LOG->Info( "Sound writeahead has been overridden to %i", PREFSMAN->m_iSoundWriteAhead.Get() ); + + pLoadingWindow->SetText("Starting sound subsystem..."); SOUNDMAN = new RageSoundManager; SOUNDMAN->Init(); SOUNDMAN->SetMixVolume(); SOUND = new GameSoundManager; + pLoadingWindow->SetText("Initializing bookkeeper..."); BOOKKEEPER = new Bookkeeper; + pLoadingWindow->SetText("Starting lights subsystem..."); LIGHTSMAN = new LightsManager; INPUTFILTER = new InputFilter; INPUTMAPPER = new InputMapper; + pLoadingWindow->SetText("Loading game type..."); StepMania::ChangeCurrentGame( GAMESTATE->GetCurrentGame() ); INPUTQUEUE = new InputQueue; + pLoadingWindow->SetText("Building song cache index..."); SONGINDEX = new SongCacheIndex; + pLoadingWindow->SetText("Loading banner cache..."); BANNERCACHE = new BannerCache; //BACKGROUNDCACHE = new BackgroundCache; // depends on SONGINDEX: SONGMAN = new SongManager; - SONGMAN->InitAll( pLoadingWindow ); // this takes a long time + SONGMAN->InitAll(); // this takes a long time CRYPTMAN = new CryptManager; // need to do this before ProfileMan if( PREFSMAN->m_bSignProfileData ) CRYPTMAN->GenerateGlobalKeys(); + pLoadingWindow->SetText("Initializing memory card system..."); MEMCARDMAN = new MemoryCardManager; + pLoadingWindow->SetText("Initializing character system..."); CHARMAN = new CharacterManager; + pLoadingWindow->SetText("Initializing profile system..."); PROFILEMAN = new ProfileManager; PROFILEMAN->Init(); // must load after SONGMAN UNLOCKMAN = new UnlockManager; + pLoadingWindow->SetText("Updating popular song list..."); SONGMAN->UpdatePopular(); SONGMAN->UpdatePreferredSort(); NSMAN = new NetworkSyncManager( pLoadingWindow ); + pLoadingWindow->SetText("Initializing message system..."); MESSAGEMAN = new MessageManager; + pLoadingWindow->SetText("Initializing statics manager..."); STATSMAN = new StatsManager; + // Initialize which courses are ranking courses here. + pLoadingWindow->SetText("Updating course rankings..."); + SONGMAN->UpdateRankingCourses(); + SAFE_DELETE( pLoadingWindow ); // destroy this before init'ing Display /* If the user has tried to quit during the loading, do it before creating @@ -1127,9 +1149,6 @@ int main(int argc, char* argv[]) CodeDetector::RefreshCacheItems(); - // Initialize which courses are ranking courses here. - SONGMAN->UpdateRankingCourses(); - if( GetCommandlineArgument("netip") ) NSMAN->DisplayStartupStatus(); // If we're using networking show what happened diff --git a/src/Steps.cpp b/src/Steps.cpp index c1a79064f5..9700de9a1b 100644 --- a/src/Steps.cpp +++ b/src/Steps.cpp @@ -14,6 +14,7 @@ #include "global.h" #include "Steps.h" #include "StepsUtil.h" +#include "GameState.h" #include "Song.h" #include "RageUtil.h" #include "RageLog.h" @@ -23,6 +24,11 @@ #include "NoteDataUtil.h" #include "NotesLoaderSSC.h" #include "NotesLoaderSM.h" +#include "NotesLoaderSMA.h" +#include "NotesLoaderDWI.h" +#include "NotesLoaderKSF.h" +#include "NotesLoaderBMS.h" +#include "NotesLoaderPMS.h" #include @@ -31,13 +37,36 @@ Steps::Steps(): m_StepsType(StepsType_Invalid), m_sNoteDataCompressed(""), m_sFilename(""), m_bSavedToDisk(false), m_LoadedFromProfile(ProfileSlot_Invalid), m_iHash(0), m_sDescription(""), m_sChartStyle(""), - m_Difficulty(Difficulty_Invalid), m_iMeter(0), m_sCredit(""), - m_bAreCachedRadarValuesJustLoaded(false) {} + m_Difficulty(Difficulty_Invalid), m_iMeter(0), + m_bAreCachedRadarValuesJustLoaded(false), + m_sCredit(""), displayBPMType(DISPLAY_BPM_ACTUAL), + specifiedBPMMin(0), specifiedBPMMax(0) {} Steps::~Steps() { } +void Steps::GetDisplayBpms( DisplayBpms &AddTo ) const +{ + if( this->GetDisplayBPM() == DISPLAY_BPM_SPECIFIED ) + { + AddTo.Add( this->GetMinBPM() ); + AddTo.Add( this->GetMaxBPM() ); + } + else + { + float fMinBPM, fMaxBPM; + this->m_Timing.GetActualBPM( fMinBPM, fMaxBPM ); + AddTo.Add( fMinBPM ); + AddTo.Add( fMaxBPM ); + } +} + +bool Steps::HasAttacks() const +{ + return !this->m_Attacks.empty(); +} + unsigned Steps::GetHash() const { if( parent ) @@ -54,6 +83,50 @@ unsigned Steps::GetHash() const return m_iHash; } +bool Steps::IsNoteDataEmpty() const +{ + return this->m_sNoteDataCompressed.empty(); +} + +bool Steps::GetNoteDataFromSimfile() +{ + // Replace the line below with the Steps' cache file. + RString stepFile = this->GetFilename(); + RString extension = GetExtension(stepFile); + if (extension.empty() || extension == "ssc") // remember cache files. + { + SSCLoader loader; + return loader.LoadNoteDataFromSimfile(stepFile, *this); + } + else if (extension == "sm") + { + SMLoader loader; + return loader.LoadNoteDataFromSimfile(stepFile, *this); + } + else if (extension == "sma") + { + SMALoader loader; + return loader.LoadNoteDataFromSimfile(stepFile, *this); + } + else if (extension == "dwi") + { + return DWILoader::LoadNoteDataFromSimfile(stepFile, *this); + } + else if (extension == "ksf") + { + return KSFLoader::LoadNoteDataFromSimfile(stepFile, *this); + } + else if (extension == "bms" || extension == "bml" || extension == "bme") + { + return BMSLoader::LoadNoteDataFromSimfile(stepFile, *this); + } + else if (extension == "pms") + { + return PMSLoader::LoadNoteDataFromSimfile(stepFile, *this); + } + return false; +} + void Steps::SetNoteData( const NoteData& noteDataNew ) { ASSERT( noteDataNew.GetNumTracks() == GAMEMAN->GetStepsTypeInfo(m_StepsType).iNumTracks ); @@ -65,7 +138,6 @@ void Steps::SetNoteData( const NoteData& noteDataNew ) m_sNoteDataCompressed = RString(); m_iHash = 0; - m_sFilename = RString(); // We can no longer read from the file because it has changed in memory. } void Steps::GetNoteData( NoteData& noteDataOut ) const @@ -97,7 +169,6 @@ void Steps::SetSMNoteData( const RString ¬es_comp_ ) m_sNoteDataCompressed = notes_comp_; m_iHash = 0; - m_sFilename = RString(); // We can no longer read from the file because it has changed in memory. } /* XXX: this function should pull data from m_sFilename, like Decompress() */ @@ -192,6 +263,7 @@ void Steps::CalculateRadarValues( float fMusicLengthSeconds ) FOREACH_PlayerNumber( pn ) m_CachedRadarValues[pn].Zero(); + GAMESTATE->SetProcessedTimingData(&this->m_Timing); if( tempNoteData.IsComposite() ) { vector vParts; @@ -200,14 +272,36 @@ void Steps::CalculateRadarValues( float fMusicLengthSeconds ) for( size_t pn = 0; pn < min(vParts.size(), size_t(NUM_PLAYERS)); ++pn ) NoteDataUtil::CalculateRadarValues( vParts[pn], fMusicLengthSeconds, m_CachedRadarValues[pn] ); } + else if (GAMEMAN->GetStepsTypeInfo(this->m_StepsType).m_StepsTypeCategory == StepsTypeCategory_Couple) + { + NoteData p1 = tempNoteData; + // XXX: Assumption that couple will always have an even number of notes. + const int tracks = tempNoteData.GetNumTracks() / 2; + p1.SetNumTracks(tracks); + NoteDataUtil::CalculateRadarValues(p1, + fMusicLengthSeconds, + m_CachedRadarValues[PLAYER_1]); + // at this point, p2 is tempNoteData. + NoteDataUtil::ShiftTracks(tempNoteData, tracks); + tempNoteData.SetNumTracks(tracks); + NoteDataUtil::CalculateRadarValues(tempNoteData, + fMusicLengthSeconds, + m_CachedRadarValues[PLAYER_2]); + } else { NoteDataUtil::CalculateRadarValues( tempNoteData, fMusicLengthSeconds, m_CachedRadarValues[0] ); fill_n( m_CachedRadarValues + 1, NUM_PLAYERS-1, m_CachedRadarValues[0] ); } + GAMESTATE->SetProcessedTimingData(NULL); } void Steps::Decompress() const +{ + const_cast(this)->Decompress(); +} + +void Steps::Decompress() { if( m_bNoteDataIsFilled ) return; // already decompressed @@ -237,36 +331,14 @@ void Steps::Decompress() const if( !m_sFilename.empty() && m_sNoteDataCompressed.empty() ) { - // We have data on disk and not in memory. Load it. - Song s; - bool bLoadedFromSSC = SSCLoader::LoadFromSSCFile(m_sFilename, s, true); - if( !bLoadedFromSSC ) + // We have NoteData on disk and not in memory. Load it. + if (!this->GetNoteDataFromSimfile()) { - // try reading from .sm instead - if( !SMLoader::LoadFromSMFile(m_sFilename, s, true) ) - { - LOG->Warn( "Couldn't load \"%s\"", m_sFilename.c_str() ); - return; - } - } - - /* Find the steps. */ - StepsID ID; - ID.FromSteps( this ); - - /* We're using a StepsID to search in a different copy of a Song than - * the one it was created with. Clear the cache before doing this, - * or search results will come from cache and point to the original - * copy. */ - CachedObject::ClearCacheAll(); - Steps *pSteps = ID.ToSteps( &s, true ); - if( pSteps == NULL ) - { - LOG->Warn( "Couldn't find %s in \"%s\"", ID.ToString().c_str(), m_sFilename.c_str() ); + LOG->Warn("Couldn't load \"%s\"", m_sFilename.c_str()); return; } - pSteps->GetSMNoteData( m_sNoteDataCompressed ); + this->GetSMNoteData( m_sNoteDataCompressed ); } if( m_sNoteDataCompressed.empty() ) @@ -358,6 +430,8 @@ void Steps::CopyFrom( Steps* pSource, StepsType ntTo, float fMusicLengthSeconds noteData.SetNumTracks( GAMEMAN->GetStepsTypeInfo(ntTo).iNumTracks ); parent = NULL; m_Timing = pSource->m_Timing; + this->m_Attacks = pSource->m_Attacks; + this->m_sAttackString = pSource->m_sAttackString; this->SetNoteData( noteData ); this->SetDescription( pSource->GetDescription() ); this->SetDifficulty( pSource->GetDifficulty() ); @@ -396,9 +470,9 @@ void Steps::SetChartStyle( RString sChartStyle ) bool Steps::MakeValidEditDescription( RString &sPreferredDescription ) { - if( int(sPreferredDescription.size()) > MAX_EDIT_STEPS_DESCRIPTION_LENGTH ) + if( int(sPreferredDescription.size()) > MAX_STEPS_DESCRIPTION_LENGTH ) { - sPreferredDescription = sPreferredDescription.Left( MAX_EDIT_STEPS_DESCRIPTION_LENGTH ); + sPreferredDescription = sPreferredDescription.Left( MAX_STEPS_DESCRIPTION_LENGTH ); return true; } return false; @@ -457,7 +531,18 @@ public: DEFINE_METHOD( IsAPlayerEdit, IsAPlayerEdit() ) DEFINE_METHOD( UsesSplitTiming, UsesSplitTiming() ) - static int HasSignificantTimingChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasSignificantTimingChanges()); return 1; } + static int HasSignificantTimingChanges( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasSignificantTimingChanges()); + return 1; + } + + static int HasAttacks( T* p, lua_State *L ) + { + lua_pushboolean(L, p->HasAttacks()); + return 1; + } + static int GetRadarValues( T* p, lua_State *L ) { @@ -483,6 +568,44 @@ public: lua_pushstring( L, out ); return 1; } + + static int GetChartName(T *p, lua_State *L) + { + lua_pushstring(L, p->GetChartName()); + return 1; + } + + static int GetDisplayBpms( T* p, lua_State *L ) + { + DisplayBpms temp; + p->GetDisplayBpms(temp); + float fMin = temp.GetMin(); + float fMax = temp.GetMax(); + vector fBPMs; + fBPMs.push_back( fMin ); + fBPMs.push_back( fMax ); + LuaHelpers::CreateTableFromArray(fBPMs, L); + return 1; + } + static int IsDisplayBpmSecret( T* p, lua_State *L ) + { + DisplayBpms temp; + p->GetDisplayBpms(temp); + lua_pushboolean( L, temp.IsSecret() ); + return 1; + } + static int IsDisplayBpmConstant( T* p, lua_State *L ) + { + DisplayBpms temp; + p->GetDisplayBpms(temp); + lua_pushboolean( L, temp.BpmIsConstant() ); + return 1; + } + static int IsDisplayBpmRandom( T* p, lua_State *L ) + { + lua_pushboolean( L, p->GetDisplayBPM() == DISPLAY_BPM_RANDOM ); + return 1; + } LunaSteps() { @@ -494,14 +617,20 @@ public: ADD_METHOD( GetHash ); ADD_METHOD( GetMeter ); ADD_METHOD( HasSignificantTimingChanges ); + ADD_METHOD( HasAttacks ); ADD_METHOD( GetRadarValues ); ADD_METHOD( GetTimingData ); + ADD_METHOD( GetChartName ); //ADD_METHOD( GetSMNoteData ); ADD_METHOD( GetStepsType ); ADD_METHOD( IsAnEdit ); ADD_METHOD( IsAutogen ); ADD_METHOD( IsAPlayerEdit ); ADD_METHOD( UsesSplitTiming ); + ADD_METHOD( GetDisplayBpms ); + ADD_METHOD( IsDisplayBpmSecret ); + ADD_METHOD( IsDisplayBpmConstant ); + ADD_METHOD( IsDisplayBpmRandom ); } }; diff --git a/src/Steps.h b/src/Steps.h index 8ba508b9d2..f954e39d32 100644 --- a/src/Steps.h +++ b/src/Steps.h @@ -1,6 +1,7 @@ #ifndef STEPS_H #define STEPS_H +#include "Attack.h" #include "GameConstantsAndTypes.h" #include "PlayerNumber.h" #include "Grade.h" @@ -15,11 +16,19 @@ class NoteData; struct lua_State; /** - * @brief Allow only 12 characters for the length of edits. + * @brief Enforce a limit on the number of chars for the description. * - * This is a holdover from In The Groove: this may perhaps be not needed in the future. + * In In The Groove, this limit was 12: we do not need such a limit now. */ -const int MAX_EDIT_STEPS_DESCRIPTION_LENGTH = 12; +const int MAX_STEPS_DESCRIPTION_LENGTH = 255; + +/** @brief The different ways of displaying the BPM. */ +enum DisplayBPM +{ + DISPLAY_BPM_ACTUAL, /**< Display the song's actual BPM. */ + DISPLAY_BPM_SPECIFIED, /**< Display a specified value or values. */ + DISPLAY_BPM_RANDOM /**< Display a random selection of BPMs. */ +}; /** * @brief Holds note information for a Song. @@ -40,6 +49,7 @@ public: void Compress() const; void Decompress() const; + void Decompress(); /** * @brief Determine if these steps were created by the autogenerator. * @return true if they were, false otherwise. @@ -92,6 +102,21 @@ public: */ RString GetCredit() const { return Real()->m_sCredit; } + /** @brief The list of attacks. */ + AttackArray m_Attacks; + /** @brief The stringified list of attacks. */ + vector m_sAttackString; + + RString GetChartName() const + { + return parent ? Real()->GetChartName() : this->chartName; + } + + void SetChartName(const RString name) + { + this->chartName = name; + } + void SetFilename( RString fn ) { m_sFilename = fn; } RString GetFilename() const { return m_sFilename; } void SetSavedToDisk( bool b ) { DeAutogen(); m_bSavedToDisk = b; } @@ -114,6 +139,18 @@ public: void SetNoteData( const NoteData& noteDataNew ); void SetSMNoteData( const RString ¬es_comp ); void GetSMNoteData( RString ¬es_comp_out ) const; + + /** + * @brief Retrieve the NoteData from the original source. + * @return true if successful, false for failure. */ + bool GetNoteDataFromSimfile(); + + /** + * @brief Determine if we are missing any note data. + * + * This takes advantage of the fact that we usually compress our data. + * @return true if our notedata is empty, false otherwise. */ + bool IsNoteDataEmpty() const; void TidyUpData(); void CalculateRadarValues( float fMusicLengthSeconds ); @@ -128,6 +165,11 @@ public: * @brief Determine if the Steps have any major timing changes during gameplay. * @return true if it does, or false otherwise. */ bool HasSignificantTimingChanges() const; + + /** + * @brief Determine if the Steps have any attacks. + * @return true if it does, or false otherwise. */ + bool HasAttacks() const; // Lua void PushSelf( lua_State *L ); @@ -140,6 +182,41 @@ public: * @brief Determine if the Steps use Split Timing by comparing the Song it's in. * @return true if the Step and Song use different timings, false otherwise. */ bool UsesSplitTiming() const; + + void SetDisplayBPM(const DisplayBPM type) + { + this->displayBPMType = type; + } + + DisplayBPM GetDisplayBPM() const + { + return this->displayBPMType; + } + + void SetMinBPM(const float f) + { + this->specifiedBPMMin = f; + } + float GetMinBPM() const + { + return this->specifiedBPMMin; + } + + void SetMaxBPM(const float f) + { + this->specifiedBPMMax = f; + } + float GetMaxBPM() const + { + return this->specifiedBPMMax; + } + + void GetDisplayBpms( DisplayBpms &addTo) const; + + RString GetAttackString() const + { + return join(":", this->m_sAttackString); + } private: inline const Steps *Real() const { return parent ? parent : this; } @@ -183,6 +260,19 @@ private: bool m_bAreCachedRadarValuesJustLoaded; /** @brief The name of the person who created the Steps. */ RString m_sCredit; + + /** @brief The name of the chart. */ + RString chartName; + + /** @brief How is the BPM displayed for this chart? */ + DisplayBPM displayBPMType; + /** @brief What is the minimum specified BPM? */ + float specifiedBPMMin; + /** + * @brief What is the maximum specified BPM? + * + * If this is a range, then min should not be equal to max. */ + float specifiedBPMMax; }; #endif diff --git a/src/ThemeManager.cpp b/src/ThemeManager.cpp index 0b3841869f..0e5764c4a6 100644 --- a/src/ThemeManager.cpp +++ b/src/ThemeManager.cpp @@ -8,6 +8,7 @@ #include "RageTimer.h" #include "FontCharAliases.h" #include "arch/ArchHooks/ArchHooks.h" +#include "arch/LoadingWindow/LoadingWindow.h" #include "arch/Dialog/Dialog.h" #include "RageFile.h" #if !defined(SMPACKAGE) @@ -397,6 +398,8 @@ void ThemeManager::SwitchThemeAndLanguage( const RString &sThemeName_, const RSt if( bNothingChanging && !bForceThemeReload ) return; + if(pLoadingWindow) pLoadingWindow->SetText("Loading theme & language..."); + m_bPseudoLocalize = bPseudoLocalize; // Load theme metrics. If only the language is changing, this is all diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 1e57e455ac..8c3961c0ca 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -8,288 +8,368 @@ #include -TimingData::TimingData() : - m_fBeat0OffsetInSeconds(0), - m_bHasNegativeBpms(false) +TimingData::TimingData(float fOffset) : + m_fBeat0OffsetInSeconds(fOffset) +{ + // allTimingSegments[SEGMENT_BPM] = new vector(); +} + +TimingData::~TimingData() { } -TimingData::TimingData(float fOffset) : - m_fBeat0OffsetInSeconds(fOffset), - m_bHasNegativeBpms(false) -{ -} - -void TimingData::GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut ) const +void TimingData::GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut, float highest ) const { fMinBPMOut = FLT_MAX; fMaxBPMOut = 0; - FOREACH_CONST( BPMSegment, m_BPMSegments, seg ) + const vector &bpms = this->allTimingSegments[SEGMENT_BPM]; + for (unsigned i = 0; i < bpms.size(); i++) { + BPMSegment *seg = static_cast(bpms[i]); const float fBPM = seg->GetBPM(); - fMaxBPMOut = max( fBPM, fMaxBPMOut ); + fMaxBPMOut = clamp(max( fBPM, fMaxBPMOut ), 0, highest); fMinBPMOut = min( fBPM, fMinBPMOut ); } } +struct ts_less : binary_function { + bool operator() (const TimingSegment *x, const TimingSegment *y) const { + return (*x) < (*y); + } +}; -void TimingData::AddBPMSegment( const BPMSegment &seg ) +void TimingData::AddSegment(TimingSegmentType tst, TimingSegment * seg) { - m_BPMSegments.insert( upper_bound(m_BPMSegments.begin(), m_BPMSegments.end(), seg), seg ); + vector &segs = this->allTimingSegments[tst]; + // Unsure if this uses the proper comparison. + segs.insert(upper_bound(segs.begin(), segs.end(), seg, ts_less()), seg); } -void TimingData::AddStopSegment( const StopSegment &seg ) +int TimingData::GetSegmentIndexAtRow(TimingSegmentType tst, + int row, bool isDelay) const { - m_StopSegments.insert( upper_bound(m_StopSegments.begin(), m_StopSegments.end(), seg), seg ); + const vector &segs = this->allTimingSegments[tst]; + unsigned i = 0; + for (; i < segs.size() - 1; i++) + { + TimingSegment *seg = segs[i+1]; + if (seg->GetRow() > row) + { + // put conditions here for individual segments. + if (tst == SEGMENT_STOP_DELAY && + static_cast(seg)->GetDelay() != isDelay) + continue; + break; + } + } + return static_cast(i); } -void TimingData::AddTimeSignatureSegment( const TimeSignatureSegment &seg ) +float TimingData::GetNextSegmentBeatAtRow(TimingSegmentType tst, + int row, bool isDelay) const { - m_vTimeSignatureSegments.insert( upper_bound(m_vTimeSignatureSegments.begin(), m_vTimeSignatureSegments.end(), seg), seg ); + const vector segs = this->allTimingSegments[tst]; + for (unsigned i = 0; i < segs.size(); i++ ) + { + if( segs[i]->GetRow() <= row ) + { + continue; + } + if (tst != SEGMENT_STOP_DELAY || + static_cast(segs[i])->GetDelay() == isDelay) + return segs[i]->GetBeat(); + } + return NoteRowToBeat(row); } -void TimingData::AddWarpSegment( const WarpSegment &seg ) +float TimingData::GetPreviousSegmentBeatAtRow(TimingSegmentType tst, + int row, bool isDelay) const { - m_WarpSegments.insert( upper_bound(m_WarpSegments.begin(), m_WarpSegments.end(), seg), seg ); + float backup = -1; + const vector segs = this->allTimingSegments[tst]; + for (unsigned i = 0; i < segs.size(); i++ ) + { + if( segs[i]->GetRow() >= row ) + { + break; + } + if (tst != SEGMENT_STOP_DELAY || + static_cast(segs[i])->GetDelay() == isDelay) + backup = segs[i]->GetBeat(); + } + return (backup > -1) ? backup : NoteRowToBeat(row); } -void TimingData::AddTickcountSegment( const TickcountSegment &seg ) -{ - m_TickcountSegments.insert( upper_bound(m_TickcountSegments.begin(), m_TickcountSegments.end(), seg), seg ); -} - -void TimingData::AddComboSegment( const ComboSegment &seg ) -{ - m_ComboSegments.insert( upper_bound(m_ComboSegments.begin(), m_ComboSegments.end(), seg), seg ); -} - -void TimingData::AddLabelSegment( const LabelSegment &seg ) -{ - m_LabelSegments.insert( upper_bound(m_LabelSegments.begin(), m_LabelSegments.end(), seg), seg ); -} - -void TimingData::AddSpeedSegment( const SpeedSegment &seg ) -{ - m_SpeedSegments.insert( upper_bound(m_SpeedSegments.begin(), m_SpeedSegments.end(), seg), seg ); -} - -void TimingData::AddScrollSegment( const ScrollSegment &seg ) -{ - m_ScrollSegments.insert( upper_bound(m_ScrollSegments.begin(), m_ScrollSegments.end(), seg), seg ); -} - -void TimingData::AddFakeSegment( const FakeSegment &seg ) -{ - m_FakeSegments.insert( upper_bound(m_FakeSegments.begin(), m_FakeSegments.end(), seg), seg ); -} +// TODO: Find a way to combine all of these SetAtRows to one. /* Change an existing BPM segment, merge identical segments together or insert a new one. */ void TimingData::SetBPMAtRow( int iNoteRow, float fBPM ) { unsigned i; - for( i=0; i= iNoteRow ) + vector &bpms = this->allTimingSegments[SEGMENT_BPM]; + for( i=0; iGetRow() >= iNoteRow ) break; - if( i == m_BPMSegments.size() || m_BPMSegments[i].GetRow() != iNoteRow ) + BPMSegment *bs = static_cast(bpms[i]); + if( i == bpms.size() || bs->GetRow() != iNoteRow ) { // There is no BPMSegment at the specified beat. If the BPM being set differs // from the last BPMSegment's BPM, create a new BPMSegment. - if( i == 0 || fabsf(m_BPMSegments[i-1].GetBPM() - fBPM) > 1e-5f ) - AddBPMSegment( BPMSegment(iNoteRow, fBPM) ); + if (i == 0 || + fabsf(static_cast(bpms[i-1])->GetBPM() - fBPM) > 1e-5f ) + AddSegment( SEGMENT_BPM, new BPMSegment(iNoteRow, fBPM) ); } else // BPMSegment being modified is m_BPMSegments[i] { - if( i > 0 && fabsf(m_BPMSegments[i-1].GetBPM() - fBPM) < 1e-5f ) - m_BPMSegments.erase( m_BPMSegments.begin()+i, m_BPMSegments.begin()+i+1 ); + if (i > 0 && + fabsf(static_cast(bpms[i-1])->GetBPM() - fBPM) < 1e-5f ) + bpms.erase( bpms.begin()+i, bpms.begin()+i+1 ); else - m_BPMSegments[i].SetBPM(fBPM); + bs->SetBPM(fBPM); } } void TimingData::SetStopAtRow( int iRow, float fSeconds, bool bDelay ) { unsigned i; - for( i=0; i &stops = this->allTimingSegments[SEGMENT_STOP_DELAY]; + for( i=0; iGetRow() == iRow && + static_cast(stops[i])->GetDelay() == bDelay ) break; - if( i == m_StopSegments.size() ) // there is no Stop/Delay Segment at the current beat + StopSegment *ss = static_cast(stops[i]); + if( i == stops.size() ) // there is no Stop/Delay Segment at the current beat { // create a new StopSegment if( fSeconds > 0 ) { - AddStopSegment( StopSegment(iRow, fSeconds, bDelay) ); + AddSegment( SEGMENT_STOP_DELAY, new StopSegment(iRow, fSeconds, bDelay) ); } } else // StopSegment being modified is m_StopSegments[i] { if( fSeconds > 0 ) { - m_StopSegments[i].SetPause(fSeconds); + ss->SetPause(fSeconds); } else - m_StopSegments.erase( m_StopSegments.begin()+i, m_StopSegments.begin()+i+1 ); + stops.erase( stops.begin()+i, stops.begin()+i+1 ); } } void TimingData::SetTimeSignatureAtRow( int iRow, int iNumerator, int iDenominator ) { unsigned i; - for( i = 0; i < m_vTimeSignatureSegments.size(); i++ ) + vector &tSigs = this->allTimingSegments[SEGMENT_TIME_SIG]; + for( i = 0; i < tSigs.size(); i++ ) { - if( m_vTimeSignatureSegments[i].GetRow() >= iRow) + if( tSigs[i]->GetRow() >= iRow) break; // We found our segment. } - if ( i == m_vTimeSignatureSegments.size() || m_vTimeSignatureSegments[i].GetRow() != iRow ) + TimeSignatureSegment *ts = static_cast(tSigs[i]); + if ( i == tSigs.size() || ts->GetRow() != iRow ) { - // No specific segmeent here: place one if it differs. - if( i == 0 || - ( m_vTimeSignatureSegments[i-1].GetNum() != iNumerator - || m_vTimeSignatureSegments[i-1].GetDen() != iDenominator ) ) - AddTimeSignatureSegment( TimeSignatureSegment(iRow, iNumerator, iDenominator) ); + // No specific segment here: place one if it differs. + if (i == 0 || + (static_cast(tSigs[i-1])->GetNum() != iNumerator || + static_cast(tSigs[i-1])->GetDen() != iDenominator ) ) + AddSegment( SEGMENT_TIME_SIG, new TimeSignatureSegment(iRow, iNumerator, iDenominator) ); } else // TimeSignatureSegment being modified is m_vTimeSignatureSegments[i] { - if( i > 0 && m_vTimeSignatureSegments[i-1].GetNum() == iNumerator - && m_vTimeSignatureSegments[i-1].GetDen() == iDenominator ) - m_vTimeSignatureSegments.erase( m_vTimeSignatureSegments.begin()+i, - m_vTimeSignatureSegments.begin()+i+1 ); + if (i > 0 && + static_cast(tSigs[i-1])->GetNum() == iNumerator && + static_cast(tSigs[i-1])->GetDen() == iDenominator ) + tSigs.erase( tSigs.begin()+i, tSigs.begin()+i+1 ); else { - m_vTimeSignatureSegments[i].SetNum(iNumerator); - m_vTimeSignatureSegments[i].SetDen(iDenominator); + ts->SetNum(iNumerator); + ts->SetDen(iDenominator); } } } void TimingData::SetTimeSignatureNumeratorAtRow( int iRow, int iNumerator ) { - SetTimeSignatureAtRow( iRow, iNumerator, GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iRow ) ).GetDen() ); + this->SetTimeSignatureAtRow(iRow, + iNumerator, + GetTimeSignatureSegmentAtRow(iRow)->GetDen()); } void TimingData::SetTimeSignatureDenominatorAtRow( int iRow, int iDenominator ) { - SetTimeSignatureAtRow( iRow, GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iRow ) ).GetNum(), iDenominator ); + this->SetTimeSignatureAtRow(iRow, + GetTimeSignatureSegmentAtRow(iRow)->GetNum(), + iDenominator); } void TimingData::SetWarpAtRow( int iRow, float fNew ) { unsigned i; - for( i=0; i &warps = this->allTimingSegments[SEGMENT_WARP]; + for( i=0; iGetRow() == iRow ) break; bool valid = iRow > 0 && fNew > 0; - if( i == m_WarpSegments.size() ) + if( i == warps.size() ) { if( valid ) { - AddWarpSegment( WarpSegment(iRow, fNew) ); + AddSegment( SEGMENT_WARP, new WarpSegment(iRow, fNew) ); } } else { if( valid ) { - m_WarpSegments[i].SetLength(fNew); + static_cast(warps[i])->SetLength(fNew); } else - m_WarpSegments.erase( m_WarpSegments.begin()+i, m_WarpSegments.begin()+i+1 ); + warps.erase( warps.begin()+i, warps.begin()+i+1 ); } } /* Change an existing Tickcount segment, merge identical segments together or insert a new one. */ void TimingData::SetTickcountAtRow( int iRow, int iTicks ) { - unsigned i; - for( i=0; i= iRow ) + LOG->Trace( "TimingData::SetTickcountAtRow( '%i' , '%i' )", iRow, iTicks ); + + unsigned i = 0; + vector &ticks = this->allTimingSegments[SEGMENT_TICKCOUNT]; + for( i=0; iGetRow() >= iRow ) break; - if( i == m_TickcountSegments.size() || m_TickcountSegments[i].GetRow() != iRow ) + // this thing causes an invalid parameter crash + TickcountSegment *ts = static_cast(ticks[i]); + LOG->Trace( "Done with that thing again" ); + + if( i == ticks.size() || ts->GetRow() != iRow ) { + LOG->Trace( "New TickSegment" ); // No TickcountSegment here. Make a new segment if required. - if( i == 0 || m_TickcountSegments[i-1].GetTicks() != iTicks ) - AddTickcountSegment( TickcountSegment(iRow, iTicks ) ); + if (i == 0 || + static_cast(ticks[i-1])->GetTicks() != iTicks ) + AddSegment( SEGMENT_TICKCOUNT, new TickcountSegment(iRow, iTicks ) ); } else // TickcountSegment being modified is m_TickcountSegments[i] { - if( i > 0 && m_TickcountSegments[i-1].GetTicks() == iTicks ) - m_TickcountSegments.erase( m_TickcountSegments.begin()+i, m_TickcountSegments.begin()+i+1 ); + LOG->Trace( "Editing TickSegment" ); + if (i > 0 && + static_cast(ticks[i-1])->GetTicks() == iTicks ) + ticks.erase( ticks.begin()+i, ticks.begin()+i+1 ); else - m_TickcountSegments[i].SetTicks(iTicks); + ts->SetTicks(iTicks); } + + LOG->Trace( "DONE" ); } -void TimingData::SetComboAtRow( int iRow, int iCombo ) +void TimingData::SetComboAtRow( int iRow, int iCombo, int iMiss ) { unsigned i; - for( i=0; i= iRow ) + vector &combos = this->allTimingSegments[SEGMENT_COMBO]; + for( i=0; iGetRow() >= iRow ) break; - if( i == m_ComboSegments.size() || m_ComboSegments[i].GetRow() != iRow ) + ComboSegment *cs = static_cast(combos[i]); + + if( i == combos.size() || cs->GetRow() != iRow ) { - if( i == 0 || m_ComboSegments[i-1].GetCombo() != iCombo ) - AddComboSegment( ComboSegment(iRow, iCombo ) ); + if (i == 0 || + static_cast(combos[i-1])->GetCombo() != iCombo || + static_cast(combos[i-1])->GetMissCombo() != iMiss) + AddSegment( SEGMENT_COMBO, new ComboSegment(iRow, iCombo, iMiss ) ); } else { - if( i > 0 && m_ComboSegments[i-1].GetCombo() == iCombo ) - m_ComboSegments.erase( m_ComboSegments.begin()+i, m_ComboSegments.begin()+i+1 ); + if (i > 0 && + static_cast(combos[i-1])->GetCombo() == iCombo && + static_cast(combos[i-1])->GetMissCombo() == iMiss) + combos.erase( combos.begin()+i, combos.begin()+i+1 ); else - m_ComboSegments[i].SetCombo(iCombo); + { + cs->SetCombo(iCombo); + cs->SetMissCombo(iMiss); + } } } +void TimingData::SetHitComboAtRow(int iRow, int iCombo) +{ + this->SetComboAtRow(iRow, + iCombo, + this->GetComboSegmentAtRow(iRow)->GetMissCombo()); +} + +void TimingData::SetMissComboAtRow(int iRow, int iMiss) +{ + this->SetComboAtRow(iRow, + this->GetComboSegmentAtRow(iRow)->GetCombo(), + iMiss); +} + void TimingData::SetLabelAtRow( int iRow, const RString sLabel ) { unsigned i; - for( i=0; i= iRow ) + vector &labels = this->allTimingSegments[SEGMENT_LABEL]; + for( i=0; iGetRow() >= iRow ) break; - if( i == m_LabelSegments.size() || m_LabelSegments[i].GetRow() != iRow ) + LabelSegment *ls = static_cast(labels[i]); + + if( i == labels.size() || ls->GetRow() != iRow ) { - if( i == 0 || m_LabelSegments[i-1].GetLabel() != sLabel ) - AddLabelSegment( LabelSegment(iRow, sLabel ) ); + if (i == 0 || + static_cast(labels[i-1])->GetLabel() != sLabel ) + AddSegment( SEGMENT_LABEL, new LabelSegment(iRow, sLabel ) ); } else { - if( i > 0 && ( m_LabelSegments[i-1].GetLabel() == sLabel || sLabel == "" ) ) - m_LabelSegments.erase( m_LabelSegments.begin()+i, m_LabelSegments.begin()+i+1 ); + if (i > 0 && + ( static_cast(labels[i-1])->GetLabel() == sLabel || + sLabel == "" ) ) + labels.erase( labels.begin()+i, labels.begin()+i+1 ); else - m_LabelSegments[i].SetLabel(sLabel); + ls->SetLabel(sLabel); } } void TimingData::SetSpeedAtRow( int iRow, float fPercent, float fWait, unsigned short usMode ) { unsigned i; - for( i = 0; i < m_SpeedSegments.size(); i++ ) + vector &speeds = this->allTimingSegments[SEGMENT_SPEED]; + for( i = 0; i < speeds.size(); i++ ) { - if( m_SpeedSegments[i].GetRow() >= iRow) + if( speeds[i]->GetRow() >= iRow) break; } - if ( i == m_SpeedSegments.size() || m_SpeedSegments[i].GetRow() != iRow ) + SpeedSegment *ss = static_cast(speeds[i]); + + if ( i == speeds.size() || ss->GetRow() != iRow ) { // the core mod itself matters the most for comparisons. - if( i == 0 || m_SpeedSegments[i-1].GetRatio() != fPercent ) - AddSpeedSegment( SpeedSegment(iRow, fPercent, fWait, usMode) ); + if (i == 0 || + static_cast(speeds[i-1])->GetRatio() != fPercent ) + AddSegment( SEGMENT_SPEED, new SpeedSegment(iRow, fPercent, fWait, usMode) ); } else { // The others aren't compared: only the mod itself matters. - if( i > 0 && m_SpeedSegments[i-1].GetRatio() == fPercent ) - m_SpeedSegments.erase( m_SpeedSegments.begin()+i, - m_SpeedSegments.begin()+i+1 ); + if (i > 0 && + static_cast(speeds[i-1])->GetRatio() == fPercent ) + speeds.erase( speeds.begin()+i, speeds.begin()+i+1 ); else { - m_SpeedSegments[i].SetRatio(fPercent); - m_SpeedSegments[i].SetLength(fWait); - m_SpeedSegments[i].SetUnit(usMode); + ss->SetRatio(fPercent); + ss->SetLength(fWait); + ss->SetUnit(usMode); } } } @@ -297,27 +377,30 @@ void TimingData::SetSpeedAtRow( int iRow, float fPercent, float fWait, unsigned void TimingData::SetScrollAtRow( int iRow, float fPercent ) { unsigned i; - for( i = 0; i < m_ScrollSegments.size(); i++ ) + vector &scrolls = this->allTimingSegments[SEGMENT_SCROLL]; + for( i = 0; i < scrolls.size(); i++ ) { - if( m_ScrollSegments[i].GetRow() >= iRow) + if( scrolls[i]->GetRow() >= iRow) break; } - if ( i == m_ScrollSegments.size() || m_ScrollSegments[i].GetRow() != iRow ) + ScrollSegment *ss = static_cast(scrolls[i]); + if ( i == scrolls.size() || ss->GetRow() != iRow ) { // the core mod itself matters the most for comparisons. - if( i == 0 || m_ScrollSegments[i-1].GetRatio() != fPercent ) - AddScrollSegment( ScrollSegment(iRow, fPercent) ); + if (i == 0 || + static_cast(scrolls[i-1])->GetRatio() != fPercent ) + AddSegment( SEGMENT_SCROLL, new ScrollSegment(iRow, fPercent) ); } else { // The others aren't compared: only the mod itself matters. - if( i > 0 && m_ScrollSegments[i-1].GetRatio() == fPercent ) - m_ScrollSegments.erase( m_ScrollSegments.begin()+i, - m_ScrollSegments.begin()+i+1 ); + if (i > 0 && + static_cast(scrolls[i-1])->GetRatio() == fPercent ) + scrolls.erase( scrolls.begin()+i, scrolls.begin()+i+1 ); else { - m_ScrollSegments[i].SetRatio(fPercent); + ss->SetRatio(fPercent); } } } @@ -325,25 +408,26 @@ void TimingData::SetScrollAtRow( int iRow, float fPercent ) void TimingData::SetFakeAtRow( int iRow, float fNew ) { unsigned i; - for( i=0; i &fakes = this->allTimingSegments[SEGMENT_FAKE]; + for( i=0; iGetRow() == iRow ) break; bool valid = iRow > 0 && fNew > 0; - if( i == m_FakeSegments.size() ) + if( i == fakes.size() ) { if( valid ) { - AddFakeSegment( FakeSegment(iRow, fNew) ); + AddSegment( SEGMENT_FAKE, new FakeSegment(iRow, fNew) ); } } else { if( valid ) { - m_FakeSegments[i].SetLength(fNew); + static_cast(fakes[i])->SetLength(fNew); } else - m_FakeSegments.erase( m_FakeSegments.begin()+i, m_FakeSegments.begin()+i+1 ); + fakes.erase( fakes.begin()+i, fakes.begin()+i+1 ); } } @@ -351,35 +435,36 @@ void TimingData::SetSpeedPercentAtRow( int iRow, float fPercent ) { SetSpeedAtRow( iRow, fPercent, - GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).GetLength(), - GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).GetUnit()); + GetSpeedSegmentAtRow( iRow )->GetLength(), + GetSpeedSegmentAtRow( iRow )->GetUnit()); } void TimingData::SetSpeedWaitAtRow( int iRow, float fWait ) { SetSpeedAtRow( iRow, - GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).GetRatio(), + GetSpeedSegmentAtRow( iRow )->GetRatio(), fWait, - GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).GetUnit()); + GetSpeedSegmentAtRow( iRow )->GetUnit()); } void TimingData::SetSpeedModeAtRow( int iRow, unsigned short usMode ) { SetSpeedAtRow( iRow, - GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).GetRatio(), - GetSpeedSegmentAtBeat( NoteRowToBeat( iRow ) ).GetLength(), + GetSpeedSegmentAtRow( iRow )->GetRatio(), + GetSpeedSegmentAtRow( iRow )->GetLength(), usMode ); } float TimingData::GetStopAtRow( int iNoteRow, bool bDelay ) const { - for( unsigned i=0; i &stops = this->allTimingSegments[SEGMENT_STOP_DELAY]; + for( unsigned i=0; i(stops[i]); + if( s->GetDelay() == bDelay && s->GetRow() == iNoteRow ) { - return s.GetPause(); + return s->GetPause(); } } return 0; @@ -398,21 +483,33 @@ float TimingData::GetDelayAtRow( int iRow ) const int TimingData::GetComboAtRow( int iNoteRow ) const { - return m_ComboSegments[GetComboSegmentIndexAtRow( iNoteRow )].GetCombo(); + const vector &c = this->allTimingSegments[SEGMENT_COMBO]; + const int index = this->GetSegmentIndexAtRow(SEGMENT_COMBO, iNoteRow); + return static_cast(c[index])->GetCombo(); +} + +int TimingData::GetMissComboAtRow(int iNoteRow) const +{ + const vector &c = this->allTimingSegments[SEGMENT_COMBO]; + const int index = this->GetSegmentIndexAtRow(SEGMENT_COMBO, iNoteRow); + return static_cast(c[index])->GetMissCombo(); } RString TimingData::GetLabelAtRow( int iRow ) const { - return m_LabelSegments[GetLabelSegmentIndexAtRow( iRow )].GetLabel(); + const vector &l = this->allTimingSegments[SEGMENT_LABEL]; + const int index = this->GetSegmentIndexAtRow(SEGMENT_LABEL, iRow); + return static_cast(l[index])->GetLabel(); } float TimingData::GetWarpAtRow( int iWarpRow ) const { - for( unsigned i=0; i &warps = this->allTimingSegments[SEGMENT_WARP]; + for( unsigned i=0; iGetRow() == iWarpRow ) { - return m_WarpSegments[i].GetLength(); + return static_cast(warps[i])->GetLength(); } } return 0; @@ -420,31 +517,32 @@ float TimingData::GetWarpAtRow( int iWarpRow ) const float TimingData::GetSpeedPercentAtRow( int iRow ) { - return GetSpeedSegmentAtRow( iRow ).GetRatio(); + return GetSpeedSegmentAtRow( iRow )->GetRatio(); } float TimingData::GetSpeedWaitAtRow( int iRow ) { - return GetSpeedSegmentAtRow( iRow ).GetLength(); + return GetSpeedSegmentAtRow( iRow )->GetLength(); } unsigned short TimingData::GetSpeedModeAtRow( int iRow ) { - return GetSpeedSegmentAtRow( iRow ).GetUnit(); + return GetSpeedSegmentAtRow( iRow )->GetUnit(); } float TimingData::GetScrollAtRow( int iRow ) { - return GetScrollSegmentAtRow( iRow ).GetRatio(); + return GetScrollSegmentAtRow( iRow )->GetRatio(); } float TimingData::GetFakeAtRow( int iFakeRow ) const { - for( unsigned i=0; i &fakes = this->allTimingSegments[SEGMENT_FAKE]; + for( unsigned i=0; iGetRow() == iFakeRow ) { - return m_FakeSegments[i].GetLength(); + return static_cast(fakes[i])->GetLength(); } } return 0; @@ -454,11 +552,13 @@ float TimingData::GetFakeAtRow( int iFakeRow ) const void TimingData::MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor ) { // Change all other BPM segments in this range. - for( unsigned i=0; i &bpms = this->allTimingSegments[SEGMENT_BPM]; + for( unsigned i=0; i(bpms[i]); + const int iStartIndexThisSegment = bs->GetRow(); + const bool bIsLastBPMSegment = i == bpms.size()-1; + const int iStartIndexNextSegment = bIsLastBPMSegment ? INT_MAX : bpms[i+1]->GetRow(); if( iStartIndexThisSegment <= iStartIndex && iStartIndexNextSegment <= iStartIndex ) continue; @@ -467,9 +567,10 @@ void TimingData::MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float f * split it into two. */ if( iStartIndexThisSegment < iStartIndex && iStartIndexNextSegment > iStartIndex ) { - BPMSegment b = m_BPMSegments[i]; - b.SetRow(iStartIndexNextSegment); - m_BPMSegments.insert( m_BPMSegments.begin()+i+1, b ); + + BPMSegment * b = new BPMSegment(iStartIndexNextSegment, + bs->GetBPS()); + bpms.insert(bpms.begin()+i+1, b); /* Don't apply the BPM change to the first half of the segment we * just split, since it lies outside the range. */ @@ -479,83 +580,40 @@ void TimingData::MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float f // If this BPM segment crosses the end of the range, split it into two. if( iStartIndexThisSegment < iEndIndex && iStartIndexNextSegment > iEndIndex ) { - BPMSegment b = m_BPMSegments[i]; - b.SetRow(iEndIndex); - m_BPMSegments.insert( m_BPMSegments.begin()+i+1, b ); + BPMSegment * b = new BPMSegment(iEndIndex, + bs->GetBPS()); + bpms.insert(bpms.begin()+i+1, b); } else if( iStartIndexNextSegment > iEndIndex ) continue; - m_BPMSegments[i].SetBPM(m_BPMSegments[i].GetBPM() * fFactor); + bs->SetBPM(bs->GetBPM() * fFactor); } } float TimingData::GetBPMAtRow( int iNoteRow ) const { unsigned i; - for( i=0; i iNoteRow ) + const vector &bpms = this->allTimingSegments[SEGMENT_BPM]; + for( i=0; iGetRow() > iNoteRow ) break; - return m_BPMSegments[i].GetBPM(); -} - -int TimingData::GetBPMSegmentIndexAtRow( int iNoteRow ) const -{ - unsigned i; - for( i=0; i iNoteRow ) - break; - return static_cast(i); -} - -int TimingData::GetStopSegmentIndexAtRow( int iNoteRow, bool bDelay ) const -{ - unsigned i; - for( i=0; i iNoteRow && s.GetDelay() == bDelay ) - break; - } - return static_cast(i); -} - -int TimingData::GetWarpSegmentIndexAtRow( int iNoteRow ) const -{ - unsigned i; - for( i=0; i iNoteRow ) - break; - } - return static_cast(i); -} - -int TimingData::GetFakeSegmentIndexAtRow( int iNoteRow ) const -{ - unsigned i; - for( i=0; i iNoteRow ) - break; - } - return static_cast(i); + return static_cast(bpms[i])->GetBPM(); } bool TimingData::IsWarpAtRow( int iNoteRow ) const { - if( m_WarpSegments.empty() ) + const vector &warps = this->allTimingSegments[SEGMENT_WARP]; + if( warps.empty() ) return false; - int i = GetWarpSegmentIndexAtRow( iNoteRow ); - const WarpSegment& s = m_WarpSegments[i]; + int i = GetSegmentIndexAtRow( SEGMENT_WARP, iNoteRow ); + const WarpSegment *s = static_cast(warps[i]); float beatRow = NoteRowToBeat(iNoteRow); - if( s.GetBeat() <= beatRow && beatRow < (s.GetBeat() + s.GetLength() ) ) + if( s->GetBeat() <= beatRow && beatRow < (s->GetBeat() + s->GetLength() ) ) { // Allow stops inside warps to allow things like stop, warp, stop, warp, stop, and so on. - if( m_StopSegments.empty() ) + if( this->allTimingSegments[SEGMENT_STOP_DELAY].empty() ) { return true; } @@ -570,221 +628,144 @@ bool TimingData::IsWarpAtRow( int iNoteRow ) const bool TimingData::IsFakeAtRow( int iNoteRow ) const { - if( m_FakeSegments.empty() ) + const vector &fakes = this->allTimingSegments[SEGMENT_FAKE]; + if( fakes.empty() ) return false; - int i = GetFakeSegmentIndexAtRow( iNoteRow ); - const FakeSegment& s = m_FakeSegments[i]; + int i = GetSegmentIndexAtRow( SEGMENT_FAKE, iNoteRow ); + const FakeSegment *s = static_cast(fakes[i]); float beatRow = NoteRowToBeat(iNoteRow); - if( s.GetBeat() <= beatRow && beatRow < ( s.GetBeat() + s.GetLength() ) ) + if( s->GetBeat() <= beatRow && beatRow < ( s->GetBeat() + s->GetLength() ) ) { return true; } return false; } -int TimingData::GetTimeSignatureSegmentIndexAtRow( int iRow ) const -{ - unsigned i; - for (i=0; i < m_vTimeSignatureSegments.size() - 1; i++ ) - if( m_vTimeSignatureSegments[i+1].GetRow() > iRow ) - break; - return static_cast(i); -} - -int TimingData::GetComboSegmentIndexAtRow( int iRow ) const -{ - unsigned i; - for( i=0; i iRow ) - break; - } - return static_cast(i); -} - -int TimingData::GetLabelSegmentIndexAtRow( int iRow ) const -{ - unsigned i; - for( i=0; i iRow ) - break; - } - return static_cast(i); -} - -int TimingData::GetSpeedSegmentIndexAtRow( int iRow ) const -{ - unsigned i; - for (i=0; i < m_SpeedSegments.size() - 1; i++ ) - if( m_SpeedSegments[i+1].GetRow() > iRow ) - break; - return static_cast(i); -} - -int TimingData::GetScrollSegmentIndexAtRow( int iRow ) const -{ - unsigned i; - for (i=0; i < m_ScrollSegments.size() - 1; i++ ) - if( m_ScrollSegments[i+1].GetRow() > iRow ) - break; - return static_cast(i); -} - -BPMSegment& TimingData::GetBPMSegmentAtRow( int iNoteRow ) +BPMSegment* TimingData::GetBPMSegmentAtRow( int iNoteRow ) { + vector &bpms = this->allTimingSegments[SEGMENT_BPM]; static BPMSegment empty; - if( m_BPMSegments.empty() ) - return empty; + if( bpms.empty() ) + return new BPMSegment(); - int i = GetBPMSegmentIndexAtRow( iNoteRow ); - return m_BPMSegments[i]; + int i = GetSegmentIndexAtRow( SEGMENT_BPM, iNoteRow ); + return static_cast(bpms[i]); } -TimeSignatureSegment& TimingData::GetTimeSignatureSegmentAtRow( int iRow ) +TimeSignatureSegment* TimingData::GetTimeSignatureSegmentAtRow( int iRow ) { unsigned i; - for( i=0; i iRow ) + vector &tSigs = this->allTimingSegments[SEGMENT_TIME_SIG]; + for( i=0; iGetRow() > iRow ) break; - return m_vTimeSignatureSegments[i]; + return static_cast(tSigs[i]); } -SpeedSegment& TimingData::GetSpeedSegmentAtRow( int iRow ) +SpeedSegment* TimingData::GetSpeedSegmentAtRow( int iRow ) { unsigned i; - for( i=0; i iRow ) + vector &speeds = this->allTimingSegments[SEGMENT_SPEED]; + for( i=0; iGetRow() > iRow ) break; - return m_SpeedSegments[i]; + return static_cast(speeds[i]); } -ScrollSegment& TimingData::GetScrollSegmentAtRow( int iRow ) +ScrollSegment* TimingData::GetScrollSegmentAtRow( int iRow ) { unsigned i; - for( i=0; i iRow ) + vector &scrolls = this->allTimingSegments[SEGMENT_SCROLL]; + for( i=0; iGetRow() > iRow ) break; - return m_ScrollSegments[i]; + return static_cast(scrolls[i]); } int TimingData::GetTimeSignatureNumeratorAtRow( int iRow ) { - return GetTimeSignatureSegmentAtRow( iRow ).GetNum(); + return GetTimeSignatureSegmentAtRow( iRow )->GetNum(); } int TimingData::GetTimeSignatureDenominatorAtRow( int iRow ) { - return GetTimeSignatureSegmentAtRow( iRow ).GetDen(); + return GetTimeSignatureSegmentAtRow( iRow )->GetDen(); } -ComboSegment& TimingData::GetComboSegmentAtRow( int iRow ) +ComboSegment* TimingData::GetComboSegmentAtRow( int iRow ) { unsigned i; - for( i=0; i iRow ) + vector &combos = this->allTimingSegments[SEGMENT_COMBO]; + for( i=0; iGetRow() > iRow ) break; - return m_ComboSegments[i]; + return static_cast(combos[i]); } -LabelSegment& TimingData::GetLabelSegmentAtRow( int iRow ) +LabelSegment* TimingData::GetLabelSegmentAtRow( int iRow ) { unsigned i; - for( i=0; i iRow ) + vector &labels = this->allTimingSegments[SEGMENT_LABEL]; + for( i=0; iGetRow() > iRow ) break; - return m_LabelSegments[i]; + return static_cast(labels[i]); } -StopSegment& TimingData::GetStopSegmentAtRow( int iNoteRow, bool bDelay ) +StopSegment* TimingData::GetStopSegmentAtRow( int iNoteRow, bool bDelay ) { - static StopSegment empty; - if( m_StopSegments.empty() ) - return empty; + vector &stops = this->allTimingSegments[SEGMENT_STOP_DELAY]; + if( stops.empty() ) + return new StopSegment(); - int i = GetStopSegmentIndexAtRow( iNoteRow, bDelay ); - return m_StopSegments[i]; + int i = GetSegmentIndexAtRow( SEGMENT_STOP_DELAY, iNoteRow, bDelay ); + return static_cast(stops[i]); } -WarpSegment& TimingData::GetWarpSegmentAtRow( int iRow ) +WarpSegment* TimingData::GetWarpSegmentAtRow( int iRow ) { - static WarpSegment empty; - if( m_WarpSegments.empty() ) - return empty; + vector &warps = this->allTimingSegments[SEGMENT_WARP]; + if( warps.empty() ) + return new WarpSegment(); - int i = GetWarpSegmentIndexAtRow( iRow ); - return m_WarpSegments[i]; + int i = GetSegmentIndexAtRow( SEGMENT_WARP, iRow ); + return static_cast(warps[i]); } -FakeSegment& TimingData::GetFakeSegmentAtRow( int iRow ) +FakeSegment* TimingData::GetFakeSegmentAtRow( int iRow ) { - static FakeSegment empty; - if( m_FakeSegments.empty() ) - return empty; + vector &fakes = this->allTimingSegments[SEGMENT_FAKE]; + if( fakes.empty() ) + return new FakeSegment(); - int i = GetFakeSegmentIndexAtRow( iRow ); - return m_FakeSegments[i]; + int i = GetSegmentIndexAtRow( SEGMENT_FAKE, iRow ); + return static_cast(fakes[i]); } -int TimingData::GetTickcountSegmentIndexAtRow( int iRow ) const +TickcountSegment* TimingData::GetTickcountSegmentAtRow( int iRow ) { - unsigned i; - for (i=0; i < m_TickcountSegments.size() - 1; i++ ) - if( m_TickcountSegments[i+1].GetRow() > iRow ) - break; - return static_cast(i); -} - -TickcountSegment& TimingData::GetTickcountSegmentAtRow( int iRow ) -{ - static TickcountSegment empty; - if( m_TickcountSegments.empty() ) - return empty; + vector &ticks = this->allTimingSegments[SEGMENT_TICKCOUNT]; + if( ticks.empty() ) + return new TickcountSegment(); - int i = GetTickcountSegmentIndexAtBeat( iRow ); - return m_TickcountSegments[i]; + int i = GetSegmentIndexAtRow( SEGMENT_TICKCOUNT, iRow ); + return static_cast(ticks[i]); } int TimingData::GetTickcountAtRow( int iRow ) const { - return m_TickcountSegments[GetTickcountSegmentIndexAtRow( iRow )].GetTicks(); -} - -float TimingData::GetPreviousLabelSegmentBeatAtRow( int iRow ) const -{ - float backup = -1; - for (unsigned i = 0; i < m_LabelSegments.size(); i++ ) - { - if( m_LabelSegments[i].GetRow() >= iRow ) - { - break; - } - backup = m_LabelSegments[i].GetBeat(); - } - return (backup > -1) ? backup : NoteRowToBeat(iRow); -} - -float TimingData::GetNextLabelSegmentBeatAtRow( int iRow ) const -{ - for (unsigned i = 0; i < m_LabelSegments.size(); i++ ) - { - if( m_LabelSegments[i].GetRow() <= iRow ) - { - continue; - } - return m_LabelSegments[i].GetBeat(); - } - return NoteRowToBeat(iRow); + const vector &ticks = this->allTimingSegments[SEGMENT_TICKCOUNT]; + const int index = GetSegmentIndexAtRow( SEGMENT_TICKCOUNT, iRow ); + return static_cast(ticks[index])->GetTicks(); } bool TimingData::DoesLabelExist( RString sLabel ) const { - FOREACH_CONST( LabelSegment, m_LabelSegments, seg ) + const vector &labels = this->allTimingSegments[SEGMENT_LABEL]; + for (unsigned i = 0; i < labels.size(); i++) { - if( seg->GetLabel() == sLabel ) + if (static_cast(labels[i])->GetLabel() == sLabel) return true; } return false; @@ -809,10 +790,10 @@ enum void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &fWarpDestinationOut ) const { - - vector::const_iterator itBPMS = m_BPMSegments.begin(); - vector::const_iterator itWS = m_WarpSegments.begin(); - vector::const_iterator itSS = m_StopSegments.begin(); + const vector * segs = this->allTimingSegments; + vector::const_iterator itBPMS = segs[SEGMENT_BPM].begin(); + vector::const_iterator itWS = segs[SEGMENT_WARP].begin(); + vector::const_iterator itSS = segs[SEGMENT_STOP_DELAY].begin(); bFreezeOut = false; bDelayOut = false; @@ -821,10 +802,10 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float int iLastRow = 0; float fLastTime = -m_fBeat0OffsetInSeconds; - float fBPS = GetBPMAtRow(0) / 60.0; + float fBPS = GetBPMAtRow(0) / 60.0f; float bIsWarping = false; - float fWarpDestination = 0.0; + float fWarpDestination = 0; for( ;; ) { @@ -835,19 +816,22 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float iEventRow = BeatToNoteRow(fWarpDestination); iEventType = FOUND_WARP_DESTINATION; } - if( itBPMS != m_BPMSegments.end() && itBPMS->GetRow() < iEventRow ) + if (itBPMS != segs[SEGMENT_BPM].end() && + (*itBPMS)->GetRow() < iEventRow ) { - iEventRow = itBPMS->GetRow(); + iEventRow = (*itBPMS)->GetRow(); iEventType = FOUND_BPM_CHANGE; } - if( itSS != m_StopSegments.end() && itSS->GetRow() < iEventRow ) + if (itSS != segs[SEGMENT_STOP_DELAY].end() && + (*itSS)->GetRow() < iEventRow ) { - iEventRow = itSS->GetRow(); + iEventRow = (*itSS)->GetRow(); iEventType = FOUND_STOP; } - if( itWS != m_WarpSegments.end() && itWS->GetRow() < iEventRow ) + if (itWS != segs[SEGMENT_WARP].end() && + (*itWS)->GetRow() < iEventRow ) { - iEventRow = itWS->GetRow(); + iEventRow = (*itWS)->GetRow(); iEventType = FOUND_WARP; } if( iEventType == NOT_FOUND ) @@ -867,19 +851,20 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float bIsWarping = false; break; case FOUND_BPM_CHANGE: - fBPS = itBPMS->GetBPS(); + fBPS = static_cast(*itBPMS)->GetBPS(); itBPMS ++; break; case FOUND_STOP: { - fTimeToNextEvent = itSS->GetPause(); + const StopSegment *ss = static_cast(*itSS); + fTimeToNextEvent = ss->GetPause(); fNextEventTime = fLastTime + fTimeToNextEvent; - const bool bIsDelay = itSS->GetDelay(); + const bool bIsDelay = ss->GetDelay(); if ( fElapsedTime < fNextEventTime ) { bFreezeOut = !bIsDelay; bDelayOut = bIsDelay; - fBeatOut = itSS->GetBeat(); + fBeatOut = ss->GetBeat(); fBPSOut = fBPS; return; } @@ -890,7 +875,8 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float case FOUND_WARP: { bIsWarping = true; - float fWarpSum = itWS->GetLength() + itWS->GetBeat(); + const WarpSegment *ws = static_cast(*itWS); + float fWarpSum = ws->GetLength() + ws->GetBeat(); if( fWarpSum > fWarpDestination ) { fWarpDestination = fWarpSum; @@ -916,17 +902,17 @@ float TimingData::GetElapsedTimeFromBeat( float fBeat ) const float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const { - - vector::const_iterator itBPMS = m_BPMSegments.begin(); - vector::const_iterator itWS = m_WarpSegments.begin(); - vector::const_iterator itSS = m_StopSegments.begin(); + const vector * segs = this->allTimingSegments; + vector::const_iterator itBPMS = segs[SEGMENT_BPM].begin(); + vector::const_iterator itWS = segs[SEGMENT_WARP].begin(); + vector::const_iterator itSS = segs[SEGMENT_STOP_DELAY].begin(); int iLastRow = 0; float fLastTime = -m_fBeat0OffsetInSeconds; - float fBPS = GetBPMAtRow(0) / 60.0; + float fBPS = GetBPMAtRow(0) / 60.0f; float bIsWarping = false; - float fWarpDestination = 0.0; + float fWarpDestination = 0; for( ;; ) { @@ -937,14 +923,17 @@ float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const iEventRow = BeatToNoteRow(fWarpDestination); iEventType = FOUND_WARP_DESTINATION; } - if( itBPMS != m_BPMSegments.end() && itBPMS->GetRow() < iEventRow ) + if (itBPMS != segs[SEGMENT_BPM].end() && + (*itBPMS)->GetRow() < iEventRow ) { - iEventRow = itBPMS->GetRow(); + iEventRow = (*itBPMS)->GetRow(); iEventType = FOUND_BPM_CHANGE; } - if( itSS != m_StopSegments.end() && itSS->GetDelay() && itSS->GetRow() < iEventRow ) // delays (come before marker) + if (itSS != segs[SEGMENT_STOP_DELAY].end() && + static_cast(*itSS)->GetDelay() && + (*itSS)->GetRow() < iEventRow ) // delays (come before marker) { - iEventRow = itSS->GetRow(); + iEventRow = (*itSS)->GetRow(); iEventType = FOUND_STOP; } if( BeatToNoteRow(fBeat) < iEventRow ) @@ -952,14 +941,17 @@ float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const iEventRow = BeatToNoteRow(fBeat); iEventType = FOUND_MARKER; } - if( itSS != m_StopSegments.end() && !itSS->GetDelay() && itSS->GetRow() < iEventRow ) // stops (come after marker) + if (itSS != segs[SEGMENT_STOP_DELAY].end() && + !static_cast(*itSS)->GetDelay() && + (*itSS)->GetRow() < iEventRow ) // stops (come after marker) { - iEventRow = itSS->GetRow(); + iEventRow = (*itSS)->GetRow(); iEventType = FOUND_STOP; } - if( itWS != m_WarpSegments.end() && itWS->GetRow() < iEventRow ) + if (itWS != segs[SEGMENT_WARP].end() && + (*itWS)->GetRow() < iEventRow ) { - iEventRow = itWS->GetRow(); + iEventRow = (*itWS)->GetRow(); iEventType = FOUND_WARP; } float fTimeToNextEvent = bIsWarping ? 0 : NoteRowToBeat( iEventRow - iLastRow ) / fBPS; @@ -971,11 +963,11 @@ float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const bIsWarping = false; break; case FOUND_BPM_CHANGE: - fBPS = itBPMS->GetBPS(); + fBPS = static_cast(*itBPMS)->GetBPS(); itBPMS ++; break; case FOUND_STOP: - fTimeToNextEvent = itSS->GetPause(); + fTimeToNextEvent = static_cast(*itSS)->GetPause(); fNextEventTime = fLastTime + fTimeToNextEvent; fLastTime = fNextEventTime; itSS ++; @@ -985,7 +977,8 @@ float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const case FOUND_WARP: { bIsWarping = true; - float fWarpSum = itWS->GetLength() + itWS->GetBeat(); + WarpSegment *ws = static_cast(*itWS); + float fWarpSum = ws->GetLength() + ws->GetBeat(); if( fWarpSum > fWarpDestination ) { fWarpDestination = fWarpSum; @@ -1003,18 +996,26 @@ float TimingData::GetElapsedTimeFromBeatNoOffset( float fBeat ) const float TimingData::GetDisplayedBeat( float fBeat ) const { - vector::const_iterator it = m_ScrollSegments.begin(), end = m_ScrollSegments.end(); - float fOutBeat = 0.0; + const vector &scrolls = this->allTimingSegments[SEGMENT_SCROLL]; + vector::const_iterator it = scrolls.begin(), end = scrolls.end(); + float fOutBeat = 0; + for( it = it + 1; it != end; it++ ) + { + ASSERT((*(it-1))->GetBeat() <= (*it)->GetBeat()); + } + it = scrolls.begin(); for( ; it != end; it++ ) { - if( it+1 == end || fBeat <= (it+1)->GetBeat() ) + if( it+1 == end || fBeat <= (*(it+1))->GetBeat() ) { - fOutBeat += ( fBeat - (it)->GetBeat() ) * (it)->GetRatio(); + fOutBeat += ( fBeat - (*it)->GetBeat() ) * + static_cast(*it)->GetRatio(); break; } else { - fOutBeat += ( (it+1)->GetBeat() - (it)->GetBeat() ) * (it)->GetRatio(); + fOutBeat += ( (*(it+1))->GetBeat() - (*it)->GetBeat() ) * + static_cast(*it)->GetRatio(); } } return fOutBeat; @@ -1026,258 +1027,67 @@ void TimingData::ScaleRegion( float fScale, int iStartIndex, int iEndIndex, bool ASSERT( iStartIndex >= 0 ); ASSERT( iStartIndex < iEndIndex ); - for ( unsigned i = 0; i < m_BPMSegments.size(); i++ ) - { - BPMSegment &b = m_BPMSegments[i]; - const int iSegStart = b.GetRow(); - if( iSegStart < iStartIndex ) - continue; - else if( iSegStart > iEndIndex ) - b.SetRow( b.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) ) ); - else - b.SetRow( lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex ); - } + int length = iEndIndex - iStartIndex; + int newLength = lrintf( fScale * length ); - for( unsigned i = 0; i < m_StopSegments.size(); i++ ) + // TODO: Confirm this works as intended. + for (unsigned i = 0; i < NUM_TimingSegmentType; i++) { - StopSegment &s = m_StopSegments[i]; - const int iSegStartRow = s.GetRow(); - if( iSegStartRow < iStartIndex ) - continue; - else if( iSegStartRow > iEndIndex ) - s.SetRow(s.GetRow() + lrintf((iEndIndex - iStartIndex) * (fScale - 1))); - else - s.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex); - } - - for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ ) - { - TimeSignatureSegment &t = m_vTimeSignatureSegments[i]; - const int iSegStartRow = t.GetRow(); - if( iSegStartRow < iStartIndex ) - continue; - else if( iSegStartRow > iEndIndex ) - t.SetRow(t.GetRow() + lrintf((iEndIndex - iStartIndex) * (fScale - 1))); - else - t.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex); - } - - for( unsigned i = 0; i < m_WarpSegments.size(); i++ ) - { - WarpSegment &w = m_WarpSegments[i]; - const int iSegStartRow = w.GetRow(); - const int iSegEndRow = iSegStartRow + BeatToNoteRow( w.GetLength() ); - if( iSegEndRow >= iStartIndex ) + vector &segs = this->allTimingSegments[i]; + for (unsigned j = 0; j < segs.size(); j++) { - if( iSegEndRow > iEndIndex ) - w.SetLength(w.GetLength() + - NoteRowToBeat(lrintf((iEndIndex - iStartIndex) * (fScale - 1)))); - else - w.SetLength(NoteRowToBeat(lrintf((iSegEndRow - iStartIndex) * fScale))); + segs[i][j].Scale(iStartIndex, length, newLength); } - if( iSegStartRow < iStartIndex ) - continue; - else if( iSegStartRow > iEndIndex ) - w.SetRow(w.GetRow() + lrintf((iEndIndex - iStartIndex) * (fScale - 1))); - else - w.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex); - } - - for ( unsigned i = 0; i < m_TickcountSegments.size(); i++ ) - { - TickcountSegment &t = m_TickcountSegments[i]; - const int iSegStart = t.GetRow(); - if( iSegStart < iStartIndex ) - continue; - else if( iSegStart > iEndIndex ) - t.SetRow(t.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) )); - else - t.SetRow(lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex); - } - - for ( unsigned i = 0; i < m_ComboSegments.size(); i++ ) - { - ComboSegment &c = m_ComboSegments[i]; - const int iSegStart = c.GetRow(); - if( iSegStart < iStartIndex ) - continue; - else if( iSegStart > iEndIndex ) - c.SetRow(c.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) )); - else - c.SetRow(lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex); - } - - for ( unsigned i = 0; i < m_LabelSegments.size(); i++ ) - { - LabelSegment &l = m_LabelSegments[i]; - const int iSegStart = l.GetRow(); - if( iSegStart < iStartIndex ) - continue; - else if( iSegStart > iEndIndex ) - l.SetRow(l.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) )); - else - l.SetRow(lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex); - } - - for ( unsigned i = 0; i < m_SpeedSegments.size(); i++ ) - { - SpeedSegment &s = m_SpeedSegments[i]; - const int iSegStart = s.GetRow(); - if( iSegStart < iStartIndex ) - continue; - else if( iSegStart > iEndIndex ) - s.SetRow(s.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) )); - else - s.SetRow(lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex); - } - - for( unsigned i = 0; i < m_FakeSegments.size(); i++ ) - { - FakeSegment &f = m_FakeSegments[i]; - const int iSegStartRow = f.GetRow(); - const int iSegEndRow = iSegStartRow + BeatToNoteRow( f.GetLength() ); - if( iSegEndRow >= iStartIndex ) - { - if( iSegEndRow > iEndIndex ) - f.SetLength(f.GetLength() - + NoteRowToBeat(lrintf((iEndIndex - iStartIndex) * (fScale - 1)))); - else - f.SetLength(NoteRowToBeat(lrintf((iSegEndRow - iStartIndex) * fScale))); - } - if( iSegStartRow < iStartIndex ) - continue; - else if( iSegStartRow > iEndIndex ) - f.SetRow(f.GetRow() - + lrintf((iEndIndex - iStartIndex) * (fScale - 1))); - else - f.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex); - } - - for( unsigned i = 0; i < m_ScrollSegments.size(); i++ ) - { - ScrollSegment &s = m_ScrollSegments[i]; - const int iSegStartRow = s.GetRow(); - if( iSegStartRow < iStartIndex ) - continue; - else if( iSegStartRow > iEndIndex ) - s.SetRow(s.GetRow() + lrintf((iEndIndex - iStartIndex) * (fScale - 1))); - else - s.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex); } // adjust BPM changes to preserve timing if( bAdjustBPM ) { - int iNewEndIndex = lrintf( (iEndIndex - iStartIndex) * fScale ) + iStartIndex; + int iNewEndIndex = iStartIndex + newLength; float fEndBPMBeforeScaling = GetBPMAtRow(iNewEndIndex); + vector &bpms = this->allTimingSegments[SEGMENT_BPM]; // adjust BPM changes "between" iStartIndex and iNewEndIndex - for ( unsigned i = 0; i < m_BPMSegments.size(); i++ ) + for ( unsigned i = 0; i < bpms.size(); i++ ) { - const int iSegStart = m_BPMSegments[i].GetRow(); + BPMSegment *bpm = static_cast(bpms[i]); + const int iSegStart = bpm->GetRow(); if( iSegStart <= iStartIndex ) continue; else if( iSegStart >= iNewEndIndex ) continue; else - m_BPMSegments[i].SetBPM( m_BPMSegments[i].GetBPM() * fScale ); + bpm->SetBPM( bpm->GetBPM() * fScale ); } // set BPM at iStartIndex and iNewEndIndex. SetBPMAtRow( iStartIndex, GetBPMAtRow(iStartIndex) * fScale ); SetBPMAtRow( iNewEndIndex, fEndBPMBeforeScaling ); - } } void TimingData::InsertRows( int iStartRow, int iRowsToAdd ) { - for( unsigned i = 0; i < m_BPMSegments.size(); i++ ) + for (unsigned i = 0; i < NUM_TimingSegmentType; i++) { - BPMSegment &bpm = m_BPMSegments[i]; - if( bpm.GetRow() < iStartRow ) - continue; - bpm.SetRow( bpm.GetRow() + iRowsToAdd ); - } - - for( unsigned i = 0; i < m_StopSegments.size(); i++ ) - { - StopSegment &stop = m_StopSegments[i]; - if( stop.GetRow() < iStartRow ) - continue; - stop.SetRow(stop.GetRow() + iRowsToAdd); - } - - for( unsigned i = 0; i < m_WarpSegments.size(); i++ ) - { - WarpSegment &warp = m_WarpSegments[i]; - if( warp.GetRow() < iStartRow ) - continue; - warp.SetRow(warp.GetRow() + iRowsToAdd); - } - - for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ ) - { - TimeSignatureSegment &time = m_vTimeSignatureSegments[i]; - if( time.GetRow() < iStartRow ) - continue; - time.SetRow(time.GetRow() + iRowsToAdd); - } - - for( unsigned i = 0; i < m_TickcountSegments.size(); i++ ) - { - TickcountSegment &tick = m_TickcountSegments[i]; - if( tick.GetRow() < iStartRow ) - continue; - tick.SetRow(tick.GetRow() + iRowsToAdd); - } - - for( unsigned i = 0; i < m_ComboSegments.size(); i++ ) - { - ComboSegment &comb = m_ComboSegments[i]; - if( comb.GetRow() < iStartRow ) - continue; - comb.SetRow(comb.GetRow() + iRowsToAdd); - } - for( unsigned i = 0; i < m_LabelSegments.size(); i++ ) - { - LabelSegment &labl = m_LabelSegments[i]; - if( labl.GetRow() < iStartRow ) - continue; - labl.SetRow(labl.GetRow() + iRowsToAdd); - } - - for( unsigned i = 0; i < m_SpeedSegments.size(); i++ ) - { - SpeedSegment &sped = m_SpeedSegments[i]; - if( sped.GetRow() < iStartRow ) - continue; - sped.SetRow(sped.GetRow() + iRowsToAdd); - } - - for( unsigned i = 0; i < m_FakeSegments.size(); i++ ) - { - FakeSegment &fake = m_FakeSegments[i]; - if( fake.GetRow() < iStartRow ) - continue; - fake.SetRow(fake.GetRow() + iRowsToAdd); - } - - for( unsigned i = 0; i < m_ScrollSegments.size(); i++ ) - { - ScrollSegment &scrl = m_ScrollSegments[i]; - if( scrl.GetRow() < iStartRow ) - continue; - scrl.SetRow(scrl.GetRow() + iRowsToAdd); + vector &segs = this->allTimingSegments[i]; + for (unsigned j = 0; j < segs.size(); j++) + { + TimingSegment *seg = segs[j]; + if (seg->GetRow() < iStartRow) + continue; + seg->SetRow(seg->GetRow() + iRowsToAdd); + } } if( iStartRow == 0 ) { /* If we're shifting up at the beginning, we just shifted up the first * BPMSegment. That segment must always begin at 0. */ - ASSERT( m_BPMSegments.size() > 0 ); - m_BPMSegments[0].SetRow(0); + vector &bpms = this->allTimingSegments[SEGMENT_BPM]; + ASSERT_M( bpms.size() > 0, "There must be at least one BPM Segment in the chart!" ); + bpms[0]->SetRow(0); } } @@ -1289,192 +1099,29 @@ void TimingData::DeleteRows( int iStartRow, int iRowsToDelete ) /* We're moving rows up. Delete any BPM changes and stops in the region * being deleted. */ - for( unsigned i = 0; i < m_BPMSegments.size(); i++ ) + for (unsigned i = 0; i < NUM_TimingSegmentType; i++) { - BPMSegment &bpm = m_BPMSegments[i]; - - // Before deleted region: - if( bpm.GetRow() < iStartRow ) - continue; - - // Inside deleted region: - if( bpm.GetRow() < iStartRow+iRowsToDelete ) + vector &segs = this->allTimingSegments[i]; + for (unsigned j = 0; j < segs.size(); j++) { - m_BPMSegments.erase( m_BPMSegments.begin()+i, m_BPMSegments.begin()+i+1 ); - --i; - continue; + TimingSegment *seg = segs[j]; + // Before deleted region: + if (seg->GetRow() < iStartRow) + continue; + + // Inside deleted region: + if (seg->GetRow() < iStartRow + iRowsToDelete) + { + segs.erase(segs.begin()+j, segs.begin()+j+1); + --j; + continue; + } + + // After deleted regions: + seg->SetRow(seg->GetRow() - iRowsToDelete); } - - // After deleted region: - bpm.SetRow( bpm.GetRow() - iRowsToDelete ); - } - - for( unsigned i = 0; i < m_StopSegments.size(); i++ ) - { - StopSegment &stop = m_StopSegments[i]; - int keyRow = stop.GetRow(); - // Before deleted region: - if( keyRow < iStartRow ) - continue; - - // Inside deleted region: - if( keyRow < iStartRow+iRowsToDelete ) - { - m_StopSegments.erase( m_StopSegments.begin()+i, m_StopSegments.begin()+i+1 ); - --i; - continue; - } - - // After deleted region: - stop.SetRow(keyRow - iRowsToDelete); } - for( unsigned i = 0; i < m_WarpSegments.size(); i++ ) - { - WarpSegment &warp = m_WarpSegments[i]; - int keyRow = warp.GetRow(); - if( keyRow < iStartRow ) - continue; - - if( keyRow < iStartRow+iRowsToDelete ) - { - m_WarpSegments.erase( m_WarpSegments.begin()+i, m_WarpSegments.begin()+i+1 ); - --i; - continue; - } - - warp.SetRow(keyRow - iRowsToDelete); - } - - for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ ) - { - TimeSignatureSegment &time = m_vTimeSignatureSegments[i]; - int keyRow = time.GetRow(); - // Before deleted region: - if( keyRow < iStartRow ) - continue; - - // Inside deleted region: - if( keyRow < iStartRow+iRowsToDelete ) - { - m_vTimeSignatureSegments.erase( - m_vTimeSignatureSegments.begin()+i, - m_vTimeSignatureSegments.begin()+i+1 ); - --i; - continue; - } - - // After deleted region: - - - time.SetRow(keyRow - iRowsToDelete); - } - - for( unsigned i = 0; i < m_TickcountSegments.size(); i++ ) - { - TickcountSegment &tick = m_TickcountSegments[i]; - int keyRow = tick.GetRow(); - // Before deleted region: - if( keyRow < iStartRow ) - continue; - - // Inside deleted region: - if( keyRow < iStartRow+iRowsToDelete ) - { - m_TickcountSegments.erase( m_TickcountSegments.begin()+i, m_TickcountSegments.begin()+i+1 ); - --i; - continue; - } - - // After deleted region: - tick.SetRow(keyRow - iRowsToDelete); - } - - for( unsigned i = 0; i < m_ComboSegments.size(); i++ ) - { - ComboSegment &comb = m_ComboSegments[i]; - int keyRow = comb.GetRow(); - // Before deleted region: - if( keyRow < iStartRow ) - continue; - - // Inside deleted region: - if( keyRow < iStartRow+iRowsToDelete ) - { - m_ComboSegments.erase( m_ComboSegments.begin()+i, m_ComboSegments.begin()+i+1 ); - --i; - continue; - } - - // After deleted region: - comb.SetRow(keyRow - iRowsToDelete); - } - - for( unsigned i = 0; i < m_LabelSegments.size(); i++ ) - { - LabelSegment &labl = m_LabelSegments[i]; - int keyRow = labl.GetRow(); - if( keyRow < iStartRow ) - continue; - - if( keyRow < iStartRow+iRowsToDelete ) - { - m_LabelSegments.erase( m_LabelSegments.begin()+i, m_LabelSegments.begin()+i+1 ); - --i; - continue; - } - labl.SetRow(keyRow - iRowsToDelete); - } - - for( unsigned i = 0; i < m_SpeedSegments.size(); i++ ) - { - SpeedSegment &sped = m_SpeedSegments[i]; - int keyRow = sped.GetRow(); - if( keyRow < iStartRow ) - continue; - - if( keyRow < iStartRow+iRowsToDelete ) - { - m_SpeedSegments.erase( m_SpeedSegments.begin()+i, m_SpeedSegments.begin()+i+1 ); - --i; - continue; - } - sped.SetRow(keyRow - iRowsToDelete); - } - - for( unsigned i = 0; i < m_FakeSegments.size(); i++ ) - { - FakeSegment &fake = m_FakeSegments[i]; - int keyRow = fake.GetRow(); - if( keyRow < iStartRow ) - continue; - - if( keyRow < iStartRow+iRowsToDelete ) - { - m_FakeSegments.erase( m_FakeSegments.begin()+i, m_FakeSegments.begin()+i+1 ); - --i; - continue; - } - - fake.SetRow(keyRow - iRowsToDelete); - } - - for( unsigned i = 0; i < m_ScrollSegments.size(); i++ ) - { - ScrollSegment &scrl = m_ScrollSegments[i]; - int keyRow = scrl.GetRow(); - if( keyRow < iStartRow ) - continue; - - if( keyRow < iStartRow+iRowsToDelete ) - { - m_ScrollSegments.erase( m_ScrollSegments.begin()+i, m_ScrollSegments.begin()+i+1 ); - --i; - continue; - } - scrl.SetRow(keyRow - iRowsToDelete); - } - this->SetBPMAtRow( iStartRow, fNewBPM ); } @@ -1485,45 +1132,51 @@ float TimingData::GetDisplayedSpeedPercent( float fSongBeat, float fMusicSeconds * leaving the editor. Still, cover our butts in case this instance * isn't existing. */ if (!this) return 1.0f; - if( m_SpeedSegments.size() == 0 ) + + const vector &speeds = this->allTimingSegments[SEGMENT_SPEED]; + if( speeds.size() == 0 ) return 1.0f; - const int index = GetSpeedSegmentIndexAtBeat( fSongBeat ); + const int index = GetSegmentIndexAtBeat( SEGMENT_SPEED, fSongBeat ); - const SpeedSegment &seg = m_SpeedSegments[index]; - float fStartBeat = seg.GetBeat(); + const SpeedSegment *seg = static_cast(speeds[index]); + float fStartBeat = seg->GetBeat(); float fStartTime = GetElapsedTimeFromBeat( fStartBeat ) - GetDelayAtBeat( fStartBeat ); float fEndTime; float fCurTime = fMusicSeconds; - if( seg.GetUnit() == 1 ) // seconds + if( seg->GetUnit() == 1 ) // seconds { - fEndTime = fStartTime + seg.GetLength(); + fEndTime = fStartTime + seg->GetLength(); } else { - fEndTime = GetElapsedTimeFromBeat( fStartBeat + seg.GetLength() ) - - GetDelayAtBeat( fStartBeat + seg.GetLength() ); + fEndTime = GetElapsedTimeFromBeat( fStartBeat + seg->GetLength() ) + - GetDelayAtBeat( fStartBeat + seg->GetLength() ); } - if( ( index == 0 && m_SpeedSegments[0].GetLength() > 0.0 ) && fCurTime < fStartTime ) + SpeedSegment *first = static_cast(speeds[0]); + + if( ( index == 0 && first->GetLength() > 0.0 ) && fCurTime < fStartTime ) { - return 1.0; + return 1.0f; } - else if( fEndTime >= fCurTime && ( index > 0 || m_SpeedSegments[0].GetLength() > 0.0 ) ) + else if( fEndTime >= fCurTime && ( index > 0 || first->GetLength() > 0.0 ) ) { - const float fPriorSpeed = ( index == 0 ? 1 : m_SpeedSegments[index - 1].GetRatio() ); + const float fPriorSpeed = (index == 0 ? + 1 : + static_cast(speeds[index - 1])->GetRatio() ); float fTimeUsed = fCurTime - fStartTime; float fDuration = fEndTime - fStartTime; float fRatioUsed = fDuration == 0.0 ? 1 : fTimeUsed / fDuration; - float fDistance = fPriorSpeed - seg.GetRatio(); + float fDistance = fPriorSpeed - seg->GetRatio(); float fRatioNeed = fRatioUsed * -fDistance; return (fPriorSpeed + fRatioNeed); } else { - return seg.GetRatio(); + return seg->GetRatio(); } } @@ -1531,59 +1184,54 @@ float TimingData::GetDisplayedSpeedPercent( float fSongBeat, float fMusicSeconds void TimingData::TidyUpData() { // If there are no BPM segments, provide a default. - if( m_BPMSegments.empty() ) + vector *segs = this->allTimingSegments; + if( segs[SEGMENT_BPM].empty() ) { LOG->UserLog( "Song file", m_sFile, "has no BPM segments, default provided." ); - AddBPMSegment( BPMSegment(0, 60) ); + AddSegment( SEGMENT_BPM, new BPMSegment(0, 60) ); } // Make sure the first BPM segment starts at beat 0. - if( m_BPMSegments[0].GetRow() != 0 ) - m_BPMSegments[0].SetRow(0); + if( segs[SEGMENT_BPM][0]->GetRow() != 0 ) + segs[SEGMENT_BPM][0]->SetRow(0); // If no time signature specified, assume 4/4 time for the whole song. - if( m_vTimeSignatureSegments.empty() ) + if( segs[SEGMENT_TIME_SIG].empty() ) { - TimeSignatureSegment seg(0, 4, 4); - m_vTimeSignatureSegments.push_back( seg ); + segs[SEGMENT_TIME_SIG].push_back( new TimeSignatureSegment(0, 4, 4) ); } - // Likewise, if no tickcount signature is specified, assume 2 ticks - //per beat for the entire song. The default of 2 is chosen more - //for compatibility with the Pump Pro series than anything else. - if( m_TickcountSegments.empty() ) + // Likewise, if no tickcount signature is specified, assume 4 ticks + //per beat for the entire song. The default of 4 is chosen more + //for compatibility with the main Pump series than anything else. + if( segs[SEGMENT_TICKCOUNT].empty() ) { - TickcountSegment seg(0, 2); - m_TickcountSegments.push_back( seg ); + segs[SEGMENT_TICKCOUNT].push_back( new TickcountSegment(0, 4) ); } // Have a default combo segment of one just in case. - if( m_ComboSegments.empty() ) + if( segs[SEGMENT_COMBO].empty() ) { - ComboSegment seg(0, 1); - m_ComboSegments.push_back( seg ); + segs[SEGMENT_COMBO].push_back( new ComboSegment(0, 1, 1) ); } // Have a default label segment just in case. - if( m_LabelSegments.empty() ) + if( segs[SEGMENT_LABEL].empty() ) { - LabelSegment seg(0, "Song Start"); - m_LabelSegments.push_back( seg ); + segs[SEGMENT_LABEL].push_back( new LabelSegment(0, "Song Start") ); } // Always be sure there is a starting speed. - if( m_SpeedSegments.empty() ) + if( segs[SEGMENT_SPEED].empty() ) { - SpeedSegment seg(0, 1, 0); - m_SpeedSegments.push_back( seg ); + segs[SEGMENT_SPEED].push_back( new SpeedSegment(0, 1, 0) ); } // Always be sure there is a starting scrolling factor. - if( m_ScrollSegments.empty() ) + if( segs[SEGMENT_SCROLL].empty() ) { - ScrollSegment seg(0, 1); - m_ScrollSegments.push_back( seg ); + segs[SEGMENT_SCROLL].push_back( new ScrollSegment(0, 1) ); } } @@ -1593,50 +1241,53 @@ void TimingData::TidyUpData() bool TimingData::HasBpmChanges() const { - return m_BPMSegments.size()>1; + return this->allTimingSegments[SEGMENT_BPM].size()>1; } bool TimingData::HasStops() const { - return m_StopSegments.size()>0; + return this->allTimingSegments[SEGMENT_STOP_DELAY].size()>0; } bool TimingData::HasWarps() const { - return m_WarpSegments.size()>0; + return this->allTimingSegments[SEGMENT_WARP].size()>0; } bool TimingData::HasFakes() const { - return m_FakeSegments.size()>0; + return this->allTimingSegments[SEGMENT_FAKE].size()>0; } bool TimingData::HasSpeedChanges() const { - return m_SpeedSegments.size()>1 || m_SpeedSegments[0].GetRatio() != 1; + const vector &speeds = this->allTimingSegments[SEGMENT_SPEED]; + return (speeds.size()>1 || + static_cast(speeds[0])->GetRatio() != 1); } bool TimingData::HasScrollChanges() const { - return m_ScrollSegments.size()>1 || m_ScrollSegments[0].GetRatio() != 1; + const vector &scrolls = this->allTimingSegments[SEGMENT_SCROLL]; + return (scrolls.size()>1 || + static_cast(scrolls[0])->GetRatio() != 1); } void TimingData::NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const { iMeasureIndexOut = 0; - - FOREACH_CONST( TimeSignatureSegment, m_vTimeSignatureSegments, iter ) + const vector &tSigs = this->allTimingSegments[SEGMENT_TIME_SIG]; + for (unsigned i = 0; i < tSigs.size(); i++) { - vector::const_iterator next = iter; - next++; - int iSegmentEndRow = (next == m_vTimeSignatureSegments.end()) ? INT_MAX : next->GetRow(); + TimeSignatureSegment *curSig = static_cast(tSigs[i]); + int iSegmentEndRow = (i + 1 == tSigs.size()) ? INT_MAX : curSig->GetRow(); + + int iRowsPerMeasureThisSegment = curSig->GetNoteRowsPerMeasure(); - int iRowsPerMeasureThisSegment = iter->GetNoteRowsPerMeasure(); - - if( iNoteRow >= iter->GetRow() ) + if( iNoteRow >= curSig->GetRow() ) { // iNoteRow lands in this segment - int iNumRowsThisSegment = iNoteRow - iter->GetRow(); + int iNumRowsThisSegment = iNoteRow - curSig->GetRow(); int iNumMeasuresThisSegment = (iNumRowsThisSegment) / iRowsPerMeasureThisSegment; // don't round up iMeasureIndexOut += iNumMeasuresThisSegment; iBeatIndexOut = iNumRowsThisSegment / iRowsPerMeasureThisSegment; @@ -1646,8 +1297,9 @@ void TimingData::NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, i else { // iNoteRow lands after this segment - int iNumRowsThisSegment = iSegmentEndRow - iter->GetRow(); - int iNumMeasuresThisSegment = (iNumRowsThisSegment + iRowsPerMeasureThisSegment - 1) / iRowsPerMeasureThisSegment; // round up + int iNumRowsThisSegment = iSegmentEndRow - curSig->GetRow(); + int iNumMeasuresThisSegment = (iNumRowsThisSegment + iRowsPerMeasureThisSegment - 1) + / iRowsPerMeasureThisSegment; // round up iMeasureIndexOut += iNumMeasuresThisSegment; } } @@ -1656,6 +1308,24 @@ void TimingData::NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, i return; } +vector TimingData::ToVectorString(TimingSegmentType tst, + bool isDelay, int dec) const +{ + const vector segs = this->allTimingSegments[tst]; + vector ret; + + for (unsigned i = 0; i < segs.size(); i++) + { + if (tst == SEGMENT_STOP_DELAY) + { + StopSegment *seg = static_cast(segs[i]); + if (seg->GetDelay() != isDelay) + continue; + } + ret.push_back(segs[i]->ToString(dec)); + } + return ret; +} // lua start #include "LuaBinding.h" @@ -1670,39 +1340,58 @@ public: static int HasFakes( T* p, lua_State *L ) { lua_pushboolean(L, p->HasFakes()); return 1; } static int HasSpeedChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasSpeedChanges()); return 1; } static int HasScrollChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasScrollChanges()); return 1; } + static int GetWarps( T* p, lua_State *L ) + { + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_WARP), L); + return 1; + } + static int GetFakes( T* p, lua_State *L ) + { + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_FAKE), L); + return 1; + } + static int GetScrolls( T* p, lua_State *L ) + { + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_SCROLL), L); + return 1; + } + static int GetSpeeds( T* p, lua_State *L ) + { + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_SPEED), L); + return 1; + } + static int GetTimeSignatures( T* p, lua_State *L ) + { + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_TIME_SIG), L); + return 1; + } + static int GetCombos( T* p, lua_State *L ) + { + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_COMBO), L); + return 1; + } + static int GetTickcounts( T* p, lua_State *L ) + { + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_TICKCOUNT), L); + return 1; + } static int GetStops( T* p, lua_State *L ) { - vector vStops; - FOREACH_CONST( StopSegment, p->m_StopSegments, seg ) - { - const float fStartBeat = seg->GetBeat(); - const float fStopLength = seg->GetPause(); - if(!seg->GetDelay()) - vStops.push_back( ssprintf("%f=%f", fStartBeat, fStopLength) ); - } - - LuaHelpers::CreateTableFromArray(vStops, L); + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_STOP_DELAY, false), L); return 1; } static int GetDelays( T* p, lua_State *L ) { - vector vDelays; - FOREACH_CONST( StopSegment, p->m_StopSegments, seg ) - { - const float fStartBeat = seg->GetBeat(); - const float fStopLength = seg->GetPause(); - if(seg->GetDelay()) - vDelays.push_back( ssprintf("%f=%f", fStartBeat, fStopLength) ); - } - - LuaHelpers::CreateTableFromArray(vDelays, L); + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_STOP_DELAY, true), L); return 1; } static int GetBPMs( T* p, lua_State *L ) { vector vBPMs; - FOREACH_CONST( BPMSegment, p->m_BPMSegments, seg ) + vector &bpms = p->allTimingSegments[SEGMENT_BPM]; + for (unsigned i = 0; i < bpms.size(); i++) { + BPMSegment *seg = static_cast(bpms[i]); const float fBPM = seg->GetBPM(); vBPMs.push_back( fBPM ); } @@ -1712,27 +1401,12 @@ public: } static int GetLabels( T* p, lua_State *L ) { - vector vLabels; - FOREACH_CONST( LabelSegment, p->m_LabelSegments, seg ) - { - const float fStartRow = seg->GetBeat(); - const RString sLabel = seg->GetLabel(); - vLabels.push_back( ssprintf("%f=%s", fStartRow, sLabel.c_str()) ); - } - LuaHelpers::CreateTableFromArray(vLabels, L); + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_LABEL), L); return 1; } static int GetBPMsAndTimes( T* p, lua_State *L ) { - vector vBPMs; - FOREACH_CONST( BPMSegment, p->m_BPMSegments, seg ) - { - const float fStartRow = seg->GetBeat(); - const float fBPM = seg->GetBPM(); - vBPMs.push_back( ssprintf("%f=%f", fStartRow, fBPM) ); - } - - LuaHelpers::CreateTableFromArray(vBPMs, L); + LuaHelpers::CreateTableFromArray(p->ToVectorString(SEGMENT_BPM), L); return 1; } static int GetActualBPM( T* p, lua_State *L ) @@ -1746,7 +1420,7 @@ public: LuaHelpers::CreateTableFromArray(fBPMs, L); return 1; } - static int HasNegativeBPMs( T* p, lua_State *L ) { lua_pushboolean(L, p->m_bHasNegativeBpms); return 1; } + static int HasNegativeBPMs( T* p, lua_State *L ) { lua_pushboolean(L, p->HasWarps()); return 1; } // formerly in Song.cpp in sm-ssc private beta 1.x: static int GetBPMAtBeat( T* p, lua_State *L ) { lua_pushnumber(L, p->GetBPMAtBeat(FArg(1))); return 1; } static int GetBeatFromElapsedTime( T* p, lua_State *L ) { lua_pushnumber(L, p->GetBeatFromElapsedTime(FArg(1))); return 1; } @@ -1763,6 +1437,13 @@ public: ADD_METHOD( GetStops ); ADD_METHOD( GetDelays ); ADD_METHOD( GetBPMs ); + ADD_METHOD( GetWarps ); + ADD_METHOD( GetFakes ); + ADD_METHOD( GetTimeSignatures ); + ADD_METHOD( GetTickcounts ); + ADD_METHOD( GetSpeeds ); + ADD_METHOD( GetScrolls ); + ADD_METHOD( GetCombos ); ADD_METHOD( GetLabels ); ADD_METHOD( GetBPMsAndTimes ); ADD_METHOD( GetActualBPM ); diff --git a/src/TimingData.h b/src/TimingData.h index e81fc078e7..2486ff5701 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -4,6 +4,7 @@ #include "NoteTypes.h" #include "TimingSegments.h" #include "PrefsManager.h" +#include // max float struct lua_State; /** @brief Compare a TimingData segment's properties with one another. */ @@ -15,20 +16,51 @@ struct lua_State; class TimingData { public: - /** - * @brief Sets up initial timing data. - */ - TimingData(); + void AddSegment(TimingSegmentType tst, TimingSegment * seg); + + int GetSegmentIndexAtRow(TimingSegmentType tst, + int row, bool isDelay = false) const; + + int GetSegmentIndexAtBeat(TimingSegmentType tst, + float beat, bool isDelay = false) const + { + return this->GetSegmentIndexAtRow(tst, BeatToNoteRow(beat), isDelay); + } + + float GetNextSegmentBeatAtRow(TimingSegmentType tst, + int row, bool isDelay = false) const; + + float GetNextSegmentBeatAtBeat(TimingSegmentType tst, + float beat, bool isDelay = false) const + { + return this->GetNextSegmentBeatAtRow(tst, BeatToNoteRow(beat), isDelay); + } + + float GetPreviousSegmentBeatAtRow(TimingSegmentType tst, + int row, bool isDelay = false) const; + + float GetPreviousSegmentBeatAtBeat(TimingSegmentType tst, + float beat, bool isDelay = false) const + { + return this->GetPreviousSegmentBeatAtRow(tst, BeatToNoteRow(beat), isDelay); + } + /** * @brief Sets up initial timing data with a defined offset. * @param fOffset the offset from the 0th beat. */ - TimingData(float fOffset); + TimingData(float fOffset = 0); + + ~TimingData(); /** - * @brief Gets the actual BPM of the song. + * @brief Gets the actual BPM of the song, + * while respecting a limit. + * + * The high limit is due to the implementation of mMods. * @param fMinBPMOut the minimium specified BPM. * @param fMaxBPMOut the maximum specified BPM. + * @param highest the highest allowed max BPM. */ - void GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut ) const; + void GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut, float highest = FLT_MAX ) const; /** * @brief Retrieve the BPM at the given row. * @param iNoteRow the row in question. @@ -58,30 +90,13 @@ public: * @param iNoteRow the row that has a BPMSegment. * @return the BPMSegment in question. */ - BPMSegment& GetBPMSegmentAtRow( int iNoteRow ); + BPMSegment* GetBPMSegmentAtRow( int iNoteRow ); /** * @brief Retrieve the BPMSegment at the specified beat. * @param fBeat the beat that has a BPMSegment. * @return the BPMSegment in question. */ - BPMSegment& GetBPMSegmentAtBeat( float fBeat ) { return GetBPMSegmentAtRow( (int)BeatToNoteRow(fBeat)); } - /** - * @brief Retrieve the index of the BPMSegments at the specified row. - * @param iNoteRow the row that has a BPMSegment. - * @return the BPMSegment's index in question. - */ - int GetBPMSegmentIndexAtRow( int iNoteRow ) const; - /** - * @brief Retrieve the index of the BPMSegments at the specified beat. - * @param fBeat the beat that has a BPMSegment. - * @return the BPMSegment's index in question. - */ - int GetBPMSegmentIndexAtBeat( float fBeat ) const { return GetBPMSegmentIndexAtRow( BeatToNoteRow(fBeat)); } - /** - * @brief Add the BPMSegment to the TimingData. - * @param seg the new BPMSegment. - */ - void AddBPMSegment( const BPMSegment &seg ); + BPMSegment* GetBPMSegmentAtBeat( float fBeat ) { return GetBPMSegmentAtRow( (int)BeatToNoteRow(fBeat)); } /** * @brief Retrieve the Stop/Delay at the given row. @@ -172,83 +187,40 @@ public: * @param iNoteRow the row that has a StopSegment. * @return the StopSegment in question. */ - StopSegment& GetStopSegmentAtRow( int iNoteRow ) { return GetStopSegmentAtRow( iNoteRow, false ); } + StopSegment* GetStopSegmentAtRow( int iNoteRow ) { return GetStopSegmentAtRow( iNoteRow, false ); } /** * @brief Retrieve the StopSegment at the specified beat. * @param fBeat the beat that has a StopSegment. * @return the StopSegment in question. */ - StopSegment& GetStopSegmentAtBeat( float fBeat ) { return GetStopSegmentAtRow( BeatToNoteRow(fBeat), false); } + StopSegment* GetStopSegmentAtBeat( float fBeat ) { return GetStopSegmentAtRow( BeatToNoteRow(fBeat), false); } /** * @brief Retrieve the StopSegment at the specified row. * @param iNoteRow the row that has a StopSegment. * @param bDelay If true, this is actually a DelaySegment. * @return the StopSegment in question. */ - StopSegment& GetStopSegmentAtRow( int iNoteRow, bool bDelay ); + StopSegment* GetStopSegmentAtRow( int iNoteRow, bool bDelay ); /** * @brief Retrieve the StopSegment at the specified beat. * @param fBeat the beat that has a StopSegment. * @param bDelay If true, this is actually a DelaySegment. * @return the StopSegment in question. */ - StopSegment& GetStopSegmentAtBeat( float fBeat, bool bDelay ) { return GetStopSegmentAtRow( BeatToNoteRow(fBeat), bDelay ); } + StopSegment* GetStopSegmentAtBeat( float fBeat, bool bDelay ) { return GetStopSegmentAtRow( BeatToNoteRow(fBeat), bDelay ); } /** * @brief Retrieve the DelaySegment at the specified row. * @param iNoteRow the row that has a DelaySegment. * @return the DelaySegment in question. */ - StopSegment& GetDelaySegmentAtRow( int iNoteRow ) { return GetStopSegmentAtRow( iNoteRow, true ); } + StopSegment* GetDelaySegmentAtRow( int iNoteRow ) { return GetStopSegmentAtRow( iNoteRow, true ); } /** * @brief Retrieve the DelaySegment at the specified beat. * @param fBeat the beat that has a DelaySegment. * @return the DelaySegment in question. */ - StopSegment& GetDelaySegmentAtBeat( float fBeat ) { return GetStopSegmentAtRow( BeatToNoteRow(fBeat), true); } - /** - * @brief Retrieve the index of the StopSegments at the specified row. - * @param iNoteRow the row that has a StopSegment. - * @return the StopSegment's index in question. - */ - int GetStopSegmentIndexAtRow( int iNoteRow ) const { return GetStopSegmentIndexAtRow( iNoteRow, false ); } - /** - * @brief Retrieve the index of the StopSegments at the specified beat. - * @param fBeat the beat that has a StopSegment. - * @return the StopSegment's index in question. - */ - int GetStopSegmentIndexAtBeat( float fBeat ) const { return GetStopSegmentIndexAtRow( BeatToNoteRow(fBeat), false ); } - /** - * @brief Retrieve the index of the StopSegments at the specified row. - * @param iNoteRow the row that has a StopSegment. - * @param bDelay If true, it's a Delay Segment. Otherwise, it's a StopSegment. - * @return the StopSegment's index in question. - */ - int GetStopSegmentIndexAtRow( int iNoteRow, bool bDelay ) const; - /** - * @brief Retrieve the index of the StopSegments at the specified beat. - * @param fBeat the beat that has a StopSegment. - * @param bDelay If true, it's a Delay Segment. Otherwise, it's a StopSegment. - * @return the StopSegment's index in question. - */ - int GetStopSegmentIndexAtBeat( float fBeat, bool bDelay ) const { return GetStopSegmentIndexAtRow( BeatToNoteRow(fBeat), bDelay ); } - /** - * @brief Retrieve the index of the Delay Segments at the specified row. - * @param iNoteRow the row that has a Delay Segment. - * @return the StopSegment's index in question. - */ - int GetDelaySegmentIndexAtRow( int iNoteRow ) const { return GetStopSegmentIndexAtRow( iNoteRow, true ); } - /** - * @brief Retrieve the index of the Delay Segments at the specified beat. - * @param fBeat the beat that has a Delay Segment. - * @return the StopSegment's index in question. - */ - int GetDelaySegmentIndexAtBeat( float fBeat ) const { return GetStopSegmentIndexAtRow( BeatToNoteRow(fBeat), true ); } - /** - * @brief Add the StopSegment to the TimingData. - * @param seg the new StopSegment. - */ - void AddStopSegment( const StopSegment &seg ); - + StopSegment* GetDelaySegmentAtBeat( float fBeat ) { return GetStopSegmentAtRow( BeatToNoteRow(fBeat), true); } + /** * @brief Retrieve the Time Signature's numerator at the given row. * @param iNoteRow the row in question. @@ -316,30 +288,14 @@ public: * @param iNoteRow the row that has a TimeSignatureSegment. * @return the TimeSignatureSegment in question. */ - TimeSignatureSegment& GetTimeSignatureSegmentAtRow( int iNoteRow ); + TimeSignatureSegment* GetTimeSignatureSegmentAtRow( int iNoteRow ); /** * @brief Retrieve the TimeSignatureSegment at the specified beat. * @param fBeat the beat that has a TimeSignatureSegment. * @return the TimeSignatureSegment in question. */ - TimeSignatureSegment& GetTimeSignatureSegmentAtBeat( float fBeat ) { return GetTimeSignatureSegmentAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Retrieve the index of the TimeSignatureSegments at the specified row. - * @param iNoteRow the row that has a TimeSignatureSegment. - * @return the TimeSignatureSegment's index in question. - */ - int GetTimeSignatureSegmentIndexAtRow( int iNoteRow ) const; - /** - * @brief Retrieve the index of the TimeSignatureSegments at the specified beat. - * @param fBeat the beat that has a TimeSignatureSegment. - * @return the TimeSignatureSegment's index in question. - */ - int GetTimeSignatureSegmentIndexAtBeat( float fBeat ) const { return GetTimeSignatureSegmentIndexAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Add the TimeSignatureSegment to the TimingData. - * @param seg the new TimeSignatureSegment. - */ - void AddTimeSignatureSegment( const TimeSignatureSegment &seg ); + TimeSignatureSegment* GetTimeSignatureSegmentAtBeat( float fBeat ) { return GetTimeSignatureSegmentAtRow( BeatToNoteRow(fBeat) ); } + /** * @brief Determine the beat to warp to. * @param iRow The row you start on. @@ -369,25 +325,13 @@ public: * @param iRow the row to focus on. * @return the WarpSegment in question. */ - WarpSegment& GetWarpSegmentAtRow( int iRow ); + WarpSegment* GetWarpSegmentAtRow( int iRow ); /** * @brief Retrieve the WarpSegment at the specified beat. * @param fBeat the beat to focus on. * @return the WarpSegment in question. */ - WarpSegment& GetWarpSegmentAtBeat( float fBeat ) { return GetWarpSegmentAtRow( BeatToNoteRow( fBeat ) ); } - /** - * @brief Retrieve the index of the WarpSegment at the specified row. - * @param iRow the row to focus on. - * @return the index in question. - */ - int GetWarpSegmentIndexAtRow( int iRow ) const; - /** - * @brief Retrieve the index of the WarpSegment at the specified beat. - * @param fBeat the beat to focus on. - * @return the index in question. - */ - int GetWarpSegmentIndexAtBeat( float fBeat ) const { return GetWarpSegmentIndexAtRow( BeatToNoteRow( fBeat ) ); } + WarpSegment* GetWarpSegmentAtBeat( float fBeat ) { return GetWarpSegmentAtRow( BeatToNoteRow( fBeat ) ); } /** * @brief Checks if the row is inside a warp. * @param iRow the row to focus on. @@ -400,11 +344,7 @@ public: * @return true if the row is inside a warp, false otherwise. */ bool IsWarpAtBeat( float fBeat ) const { return IsWarpAtRow( BeatToNoteRow( fBeat ) ); } - /** - * @brief Add the WarpSegment to the TimingData. - * @param seg the new WarpSegment. - */ - void AddWarpSegment( const WarpSegment &seg ); + /** * @brief Retrieve the Tickcount at the given row. * @param iNoteRow the row in question. @@ -434,30 +374,13 @@ public: * @param iNoteRow the row that has a TickcountSegment. * @return the TickcountSegment in question. */ - TickcountSegment& GetTickcountSegmentAtRow( int iNoteRow ); + TickcountSegment* GetTickcountSegmentAtRow( int iNoteRow ); /** * @brief Retrieve the TickcountSegment at the specified beat. * @param fBeat the beat that has a TickcountSegment. * @return the TickcountSegment in question. */ - TickcountSegment& GetTickcountSegmentAtBeat( float fBeat ) { return GetTickcountSegmentAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Retrieve the index of the TickcountSegments at the specified row. - * @param iNoteRow the row that has a TickcountSegment. - * @return the TickcountSegment's index in question. - */ - int GetTickcountSegmentIndexAtRow( int iNoteRow ) const; - /** - * @brief Retrieve the index of the TickcountSegments at the specified beat. - * @param fBeat the beat that has a TickcountSegment. - * @return the TickcountSegment's index in question. - */ - int GetTickcountSegmentIndexAtBeat( float fBeat ) const { return GetTickcountSegmentIndexAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Add the TickcountSegment to the TimingData. - * @param seg the new TickcountSegment. - */ - void AddTickcountSegment( const TickcountSegment &seg ); + TickcountSegment* GetTickcountSegmentAtBeat( float fBeat ) { return GetTickcountSegmentAtRow( BeatToNoteRow(fBeat) ); } /** * @brief Retrieve the Combo at the given row. @@ -471,6 +394,18 @@ public: * @return the Combo. */ int GetComboAtBeat( float fBeat ) const { return GetComboAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Retrieve the Miss Combo at the given row. + * @param iNoteRow the row in question. + * @return the Miss Combo. + */ + int GetMissComboAtRow( int iNoteRow ) const; + /** + * @brief Retrieve the Miss Combo at the given beat. + * @param fBeat the beat in question. + * @return the Miss Combo. + */ + int GetMissComboAtBeat( float fBeat ) const { return GetMissComboAtRow( BeatToNoteRow(fBeat) ); } /** * @brief Set the row to have the new Combo. * @param iNoteRow the row to have the new Combo. @@ -483,35 +418,56 @@ public: * @param iCombo the Combo. */ void SetComboAtBeat( float fBeat, int iCombo ) { SetComboAtRow( BeatToNoteRow( fBeat ), iCombo ); } + /** + * @brief Set the row to have the new Combo and Miss Combo. + * @param iNoteRow the row to have the new Combo and Miss Combo. + * @param iCombo the Combo. + * @param iMiss the Miss Combo. + */ + void SetComboAtRow( int iNoteRow, int iCombo, int iMiss ); + /** + * @brief Set the beat to have the new Combo and Miss Combo. + * @param fBeat the beat to have the new Combo and Miss Combo. + * @param iCombo the Combo. + * @param iMiss the Miss Combo. + */ + void SetComboAtBeat( float fBeat, int iCombo, int iMiss ) { SetComboAtRow( BeatToNoteRow( fBeat ), iCombo, iMiss ); } + /** + * @brief Set the row to have the new Combo. + * @param iNoteRow the row to have the new Combo. + * @param iCombo the Combo. + */ + void SetHitComboAtRow( int iNoteRow, int iCombo ); + /** + * @brief Set the beat to have the new Combo. + * @param fBeat the beat to have the new Combo. + * @param iCombo the Combo. + */ + void SetHitComboAtBeat( float fBeat, int iCombo ) { SetHitComboAtRow( BeatToNoteRow( fBeat ), iCombo ); } + /** + * @brief Set the row to have the new Miss Combo. + * @param iNoteRow the row to have the new Miss Combo. + * @param iCombo the Miss Combo. + */ + void SetMissComboAtRow( int iNoteRow, int iCombo ); + /** + * @brief Set the beat to have the new Miss Combo. + * @param fBeat the beat to have the new Miss Combo. + * @param iCombo the Miss Combo. + */ + void SetMissComboAtBeat( float fBeat, int iCombo ) { SetMissComboAtRow( BeatToNoteRow( fBeat ), iCombo ); } /** * @brief Retrieve the ComboSegment at the specified row. * @param iNoteRow the row that has a ComboSegment. * @return the ComboSegment in question. */ - ComboSegment& GetComboSegmentAtRow( int iNoteRow ); + ComboSegment* GetComboSegmentAtRow( int iNoteRow ); /** * @brief Retrieve the ComboSegment at the specified beat. * @param fBeat the beat that has a ComboSegment. * @return the ComboSegment in question. */ - ComboSegment& GetComboSegmentAtBeat( float fBeat ) { return GetComboSegmentAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Retrieve the index of the ComboSegments at the specified row. - * @param iNoteRow the row that has a ComboSegment. - * @return the ComboSegment's index in question. - */ - int GetComboSegmentIndexAtRow( int iNoteRow ) const; - /** - * @brief Retrieve the index of the ComboSegments at the specified beat. - * @param fBeat the beat that has a ComboSegment. - * @return the ComboSegment's index in question. - */ - int GetComboSegmentIndexAtBeat( float fBeat ) const { return GetComboSegmentIndexAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Add the ComboSegment to the TimingData. - * @param seg the new ComboSegment. - */ - void AddComboSegment( const ComboSegment &seg ); + ComboSegment* GetComboSegmentAtBeat( float fBeat ) { return GetComboSegmentAtRow( BeatToNoteRow(fBeat) ); } /** * @brief Retrieve the Label at the given row. @@ -542,64 +498,20 @@ public: * @param iNoteRow the row that has a LabelSegment. * @return the LabelSegment in question. */ - LabelSegment& GetLabelSegmentAtRow( int iNoteRow ); + LabelSegment* GetLabelSegmentAtRow( int iNoteRow ); /** * @brief Retrieve the LabelSegment at the specified beat. * @param fBeat the beat that has a LabelSegment. * @return the LabelSegment in question. */ - LabelSegment& GetLabelSegmentAtBeat( float fBeat ) { return GetLabelSegmentAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Retrieve the index of the LabelSegments at the specified row. - * @param iNoteRow the row that has a LabelSegment. - * @return the LabelSegment's index in question. - */ - int GetLabelSegmentIndexAtRow( int iNoteRow ) const; - /** - * @brief Retrieve the index of the LabelSegments at the specified beat. - * @param fBeat the beat that has a LabelSegment. - * @return the LabelSegment's index in question. - */ - int GetLabelSegmentIndexAtBeat( float fBeat ) const { return GetLabelSegmentIndexAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Add the LabelSegment to the TimingData. - * @param seg the new LabelSegment. - */ - void AddLabelSegment( const LabelSegment &seg ); + LabelSegment* GetLabelSegmentAtBeat( float fBeat ) { return GetLabelSegmentAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Retrieve the previous beat that contains a LabelSegment. - * @param iRow the present row. - * @return the previous beat with a LabelSegment, or fBeat if there is none prior. - */ - float GetPreviousLabelSegmentBeatAtRow( int iRow ) const; - /** - * @brief Retrieve the previous beat that contains a LabelSegment. - * @param fBeat the present beat. - * @return the previous beat with a LabelSegment, or fBeat if there is none prior. - */ - float GetPreviousLabelSegmentBeatAtBeat( float fBeat ) const { return GetPreviousLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) ); } - /** * @brief Determine if the requisite label already exists. * @param sLabel the label to check. * @return true if it exists, false otherwise. */ bool DoesLabelExist( RString sLabel ) const; - /** - * @brief Retrieve the next beat that contains a LabelSegment. - * @param iRow the present row. - * @return the next beat with a LabelSegment, or fBeat if there is none ahead. - */ - float GetNextLabelSegmentBeatAtRow( int iRow ) const; - /** - * @brief Retrieve the previous beat that contains a LabelSegment. - * @param fBeat the present beat. - * @return the next beat with a LabelSegment, or fBeat if there is none ahead. - */ - float GetNextLabelSegmentBeatAtBeat( float fBeat ) const { return GetNextLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) ); } - - /** * @brief Retrieve the Speed's percent at the given row. * @param iNoteRow the row in question. @@ -693,30 +605,13 @@ public: * @param iNoteRow the row that has a SpeedSegment. * @return the SpeedSegment in question. */ - SpeedSegment& GetSpeedSegmentAtRow( int iNoteRow ); + SpeedSegment* GetSpeedSegmentAtRow( int iNoteRow ); /** * @brief Retrieve the SpeedSegment at the specified beat. * @param fBeat the beat that has a SpeedSegment. * @return the SpeedSegment in question. */ - SpeedSegment& GetSpeedSegmentAtBeat( float fBeat ) { return GetSpeedSegmentAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Retrieve the index of the SpeedSegments at the specified row. - * @param iNoteRow the row that has a SpeedSegment. - * @return the SpeedSegment's index in question. - */ - int GetSpeedSegmentIndexAtRow( int iNoteRow ) const; - /** - * @brief Retrieve the index of the SpeedSegments at the specified beat. - * @param fBeat the beat that has a SpeedSegment. - * @return the SpeedSegment's index in question. - */ - int GetSpeedSegmentIndexAtBeat( float fBeat ) const { return GetSpeedSegmentIndexAtRow( BeatToNoteRow(fBeat) ); } - /** - * @brief Add the SpeedSegment to the TimingData. - * @param seg the new SpeedSegment. - */ - void AddSpeedSegment( const SpeedSegment &seg ); + SpeedSegment* GetSpeedSegmentAtBeat( float fBeat ) { return GetSpeedSegmentAtRow( BeatToNoteRow(fBeat) ); } float GetDisplayedSpeedPercent( float fBeat, float fMusicSeconds ) const; @@ -751,33 +646,13 @@ public: * @param iNoteRow the row that has a ScrollSegment. * @return the ScrollSegment in question. */ - ScrollSegment& GetScrollSegmentAtRow( int iNoteRow ); + ScrollSegment* GetScrollSegmentAtRow( int iNoteRow ); /** * @brief Retrieve the ScrollSegment at the specified beat. * @param fBeat the beat that has a ScrollSegment. * @return the ScrollSegment in question. */ - ScrollSegment& GetScrollSegmentAtBeat( float fBeat ) { return GetScrollSegmentAtRow( BeatToNoteRow(fBeat) ); } - - /** - * @brief Retrieve the index of the ScrollSegment at the specified row. - * @param iNoteRow the row that has a ScrollSegment. - * @return the ScrollSegment's index in question. - */ - int GetScrollSegmentIndexAtRow( int iNoteRow ) const; - /** - * @brief Retrieve the index of the ScrollSegment at the specified beat. - * @param fBeat the beat that has a ScrollSegment. - * @return the ScrollSegment's index in question. - */ - int GetScrollSegmentIndexAtBeat( float fBeat ) const { return GetScrollSegmentIndexAtRow( BeatToNoteRow(fBeat) ); } - - /** - * @brief Add the ScrollSegment to the TimingData. - * @param seg the new ScrollSegment. - */ - void AddScrollSegment( const ScrollSegment &seg ); - + ScrollSegment* GetScrollSegmentAtBeat( float fBeat ) { return GetScrollSegmentAtRow( BeatToNoteRow(fBeat) ); } /** * @brief Determine when the fakes end. @@ -808,25 +683,13 @@ public: * @param iRow the row to focus on. * @return the FakeSegment in question. */ - FakeSegment& GetFakeSegmentAtRow( int iRow ); + FakeSegment* GetFakeSegmentAtRow( int iRow ); /** * @brief Retrieve the FakeSegment at the specified beat. * @param fBeat the beat to focus on. * @return the FakeSegment in question. */ - FakeSegment& GetFakeSegmentAtBeat( float fBeat ) { return GetFakeSegmentAtRow( BeatToNoteRow( fBeat ) ); } - /** - * @brief Retrieve the index of the FakeSegment at the specified row. - * @param iRow the row to focus on. - * @return the index in question. - */ - int GetFakeSegmentIndexAtRow( int iRow ) const; - /** - * @brief Retrieve the index of the FakeSegment at the specified beat. - * @param fBeat the beat to focus on. - * @return the index in question. - */ - int GetFakeSegmentIndexAtBeat( float fBeat ) const { return GetFakeSegmentIndexAtRow( BeatToNoteRow( fBeat ) ); } + FakeSegment* GetFakeSegmentAtBeat( float fBeat ) { return GetFakeSegmentAtRow( BeatToNoteRow( fBeat ) ); } /** * @brief Checks if the row is inside a fake. * @param iRow the row to focus on. @@ -839,11 +702,20 @@ public: * @return true if the row is inside a fake, false otherwise. */ bool IsFakeAtBeat( float fBeat ) const { return IsFakeAtRow( BeatToNoteRow( fBeat ) ); } + /** - * @brief Add the FakeSegment to the TimingData. - * @param seg the new FakeSegment. - */ - void AddFakeSegment( const FakeSegment &seg ); + * @brief Determine if this notes on this row can be judged. + * @param row the row to focus on. + * @return true if the row can be judged, false otherwise. */ + bool IsJudgableAtRow( int row ) const + { + return !(IsWarpAtRow(row) || IsFakeAtRow(row)); + } + /** + * @brief Determine if this notes on this beat can be judged. + * @param beat the beat to focus on. + * @return true if the row can be judged, false otherwise. */ + bool IsJudgableAtBeat( float beat ) const { return IsJudgableAtRow( BeatToNoteRow( beat ) ); } @@ -909,36 +781,14 @@ public: */ bool operator==( const TimingData &other ) { - COMPARE( m_BPMSegments.size() ); - for( unsigned i=0; i m_BPMSegments; - /** - * @brief The collection of StopSegments & DelaySegments. - */ - vector m_StopSegments; - /** - * @brief The collection of TimeSignatureSegments. - */ - vector m_vTimeSignatureSegments; - /** - * @brief The collection of WarpSegments. - */ - vector m_WarpSegments; - /** - * @brief The collection of TickcountSegments. - */ - vector m_TickcountSegments; - /** - * @brief The collection of ComboSegments. - */ - vector m_ComboSegments; - /** - * @brief The collection of LabelSegments. - */ - vector m_LabelSegments; - /** @brief The collection of SpeedSegments. */ - vector m_SpeedSegments; - /** @brief The collection of ScrollSegments. */ - vector m_ScrollSegments; - /** @brief The collection of FakeSegments. */ - vector m_FakeSegments; + + + vector allTimingSegments[NUM_TimingSegmentType]; + /** * @brief The initial offset of a song. */ float m_fBeat0OffsetInSeconds; - /** - * @brief A flag to see if negative BPMs are used in this song. - * - * This is only used for Lua bindings in the Song, with the intentions that - * this is moved into TimingData at a future point in time. - */ - bool m_bHasNegativeBpms; + + vector ToVectorString(TimingSegmentType tst, bool isDelay = false, int dec = 6) const; }; #undef COMPARE diff --git a/src/TimingSegments.cpp b/src/TimingSegments.cpp index 64aeee8b01..deec665226 100644 --- a/src/TimingSegments.cpp +++ b/src/TimingSegments.cpp @@ -1,31 +1,50 @@ #include "global.h" #include "TimingSegments.h" +#include "EnumHelper.h" + +static const char *TimingSegmentTypeNames[] = { + "BPM", + "Stop/Delay", // TODO: separate when stops and delays are separate. + "Time Sig", + "Warp", + "Label", + "Tickcount", + "Combo", + "Speed", + "Scroll", + "Fake" +}; +XToString( TimingSegmentType ); #define LTCOMPARE(x) if(this->x < other.x) return true; if(this->x > other.x) return false; -BaseTimingSegment::~BaseTimingSegment() {} +TimingSegment::~TimingSegment() {} - -void BaseTimingSegment::SetRow(const int s) +void TimingSegment::SetRow(const int s) { this->startingRow = s; } -void BaseTimingSegment::SetBeat(const float s) +void TimingSegment::SetBeat(const float s) { SetRow(BeatToNoteRow(s)); } -int BaseTimingSegment::GetRow() const +int TimingSegment::GetRow() const { return this->startingRow; } -float BaseTimingSegment::GetBeat() const +float TimingSegment::GetBeat() const { return NoteRowToBeat(GetRow()); } +void TimingSegment::Scale( int start, int length, int newLength ) +{ + SetRow( ScalePosition( start, length, newLength, this->GetRow() ) ); +} + /* ====================================================== Here comes the actual timing segments implementation!! */ @@ -40,6 +59,16 @@ void FakeSegment::SetLength(const float b) this->lengthBeats = b; } +void FakeSegment::Scale( int start, int length, int newLength ) +{ + float startBeat = GetBeat(); + float endBeat = startBeat + GetLength(); + float newStartBeat = ScalePosition( NoteRowToBeat(start), NoteRowToBeat(length), NoteRowToBeat(newLength), startBeat ); + float newEndBeat = ScalePosition( NoteRowToBeat(start), NoteRowToBeat(length), NoteRowToBeat(newLength), endBeat ); + SetLength( newEndBeat - newStartBeat ); + TimingSegment::Scale( start, length, newLength ); +} + bool FakeSegment::operator<( const FakeSegment &other ) const { LTCOMPARE(GetRow()); @@ -60,8 +89,19 @@ void WarpSegment::SetLength(const float b) this->lengthBeats = b; } +void WarpSegment::Scale( int start, int length, int newLength ) +{ + // XXX: this function is duplicated, there should be a better way + float startBeat = GetBeat(); + float endBeat = startBeat + GetLength(); + float newStartBeat = ScalePosition( NoteRowToBeat(start), NoteRowToBeat(length), NoteRowToBeat(newLength), startBeat ); + float newEndBeat = ScalePosition( NoteRowToBeat(start), NoteRowToBeat(length), NoteRowToBeat(newLength), endBeat ); + SetLength( newEndBeat - newStartBeat ); + TimingSegment::Scale( start, length, newLength ); +} + bool WarpSegment::operator<( const WarpSegment &other ) const -{ +{ LTCOMPARE(GetRow()); LTCOMPARE(GetLength()); return false; @@ -100,10 +140,21 @@ void ComboSegment::SetCombo(const int i) this->combo = i; } +int ComboSegment::GetMissCombo() const +{ + return this->missCombo; +} + +void ComboSegment::SetMissCombo(const int i) +{ + this->missCombo = i; +} + bool ComboSegment::operator<( const ComboSegment &other ) const { LTCOMPARE(GetRow()); LTCOMPARE(GetCombo()); + LTCOMPARE(GetMissCombo()); return false; } @@ -225,6 +276,26 @@ void SpeedSegment::SetUnit(const int i) this->unit = static_cast(i); } +void SpeedSegment::Scale( int start, int oldLength, int newLength ) +{ + if( GetUnit() == 0 ) + { + // XXX: this function is duplicated, there should be a better way + float startBeat = GetBeat(); + float endBeat = startBeat + GetLength(); + float newStartBeat = ScalePosition(NoteRowToBeat(start), + NoteRowToBeat(oldLength), + NoteRowToBeat(newLength), + startBeat); + float newEndBeat = ScalePosition(NoteRowToBeat(start), + NoteRowToBeat(oldLength), + NoteRowToBeat(newLength), + endBeat); + SetLength( newEndBeat - newStartBeat ); + } + TimingSegment::Scale( start, oldLength, newLength ); +} + bool SpeedSegment::operator<( const SpeedSegment &other ) const { LTCOMPARE(GetRow()); diff --git a/src/TimingSegments.h b/src/TimingSegments.h index 72e9a267c2..b8f954d467 100644 --- a/src/TimingSegments.h +++ b/src/TimingSegments.h @@ -3,29 +3,55 @@ #include "NoteTypes.h" // Converting rows to beats and vice~versa. +enum TimingSegmentType +{ + SEGMENT_BPM, + SEGMENT_STOP_DELAY, + // uncomment the below two when stops and delays don't share one. + // SEGMENT_STOP, + // SEGMENT_DELAY, + SEGMENT_TIME_SIG, + SEGMENT_WARP, + SEGMENT_LABEL, + SEGMENT_TICKCOUNT, + SEGMENT_COMBO, + SEGMENT_SPEED, + SEGMENT_SCROLL, + SEGMENT_FAKE, + NUM_TimingSegmentType, + TimingSegmentType_Invalid, +}; + +const RString& TimingSegmentTypeToString( TimingSegmentType tst ); + /** * @brief The base timing segment for all of the changing glory. - * - * Do not derive from this class!! Instead, derive from TimingSegment! */ -struct BaseTimingSegment +struct TimingSegment { - /** @brief Set up a BaseTimingSegment with default values. */ - BaseTimingSegment(): + /** @brief Set up a TimingSegment with default values. */ + TimingSegment(): startingRow(-1) {}; /** - * @brief Set up a BaseTimingSegment with specified values. + * @brief Set up a TimingSegment with specified values. * @param s the starting row / beat. */ - BaseTimingSegment(int s): startingRow(ToNoteRow(s)) {} - BaseTimingSegment(float s): startingRow(ToNoteRow(s)) {} + TimingSegment(int s): startingRow(ToNoteRow(s)) {} + TimingSegment(float s): startingRow(ToNoteRow(s)) {} - template - BaseTimingSegment(const DerivedSegment &other): + TimingSegment(const TimingSegment &other): startingRow(other.GetRow()) {}; - virtual ~BaseTimingSegment(); + virtual ~TimingSegment(); + + /** + * @brief Scales itself. + * @param start Starting row + * @param length Length in rows + * @param newLength The new length in rows + */ + virtual void Scale( int start, int length, int newLength ); /** * @brief Set the starting row of the BaseTimingSegment. @@ -50,27 +76,17 @@ struct BaseTimingSegment * @brief Get the starting beat of the BaseTimingSegment. * @return the starting beat. */ float GetBeat() const; - -private: - /** @brief The row in which this segment activates. */ - int startingRow; -}; - -/** - * @brief The general TimingSegment for all of the changing glory. - * - * Each segment is supposed to derive from this one. */ -template -struct TimingSegment: public BaseTimingSegment -{ - - TimingSegment(): BaseTimingSegment(-1) {}; - TimingSegment(const DerivedSegment &other): BaseTimingSegment(other) {}; - - template - TimingSegment(StartType s): BaseTimingSegment(s) {}; - + virtual TimingSegmentType GetType() const + { + return TimingSegmentType_Invalid; + } + // TODO: Remove isDelay optional param and split Stops and Delays. + virtual RString ToString(int dec) const + { + return FloatToString(this->GetBeat()); + } + /** * @brief Compares two DrivedSegments to see if one is less than the other. * @param other the other TimingSegments to compare to. @@ -79,11 +95,11 @@ struct TimingSegment: public BaseTimingSegment * This is virtual to allow other segments to implement comparison * as required by them. */ - virtual bool operator<( const DerivedSegment &other ) const + bool operator<( const TimingSegment &other ) const { return this->GetRow() < other.GetRow(); }; - + /** * @brief Compares two DrivedSegments to see if they are equal to each other. * @param other the other FakeSegment to compare to. @@ -92,38 +108,45 @@ struct TimingSegment: public BaseTimingSegment * This is virtual to allow other segments to implement comparison * as required by them. */ - bool operator==( const DerivedSegment &other ) const + bool operator==( const TimingSegment &other ) const { return !this->operator<(other) && - !other.operator<(*static_cast(this)); + !other.operator<(*static_cast(this)); }; /** * @brief Compares two DrivedSegments to see if they are not equal to each other. * @param other the other DrivedSegments to compare to. * @return the inequality of the two segments. */ - bool operator!=( const DerivedSegment &other ) const { return !this->operator==(other); }; + bool operator!=( const TimingSegment &other ) const { return !this->operator==(other); }; /** * @brief Compares two DrivedSegments to see if one is less than or equal to the other. * @param other the other DrivedSegments to compare to. * @return the truth/falsehood of if the first is less or equal to than the second. */ - bool operator<=( const DerivedSegment &other ) const { return !this->operator>(other); }; + bool operator<=( const TimingSegment &other ) const { return !this->operator>(other); }; /** * @brief Compares two DrivedSegments to see if one is greater than the other. * @param other the other DrivedSegments to compare to. * @return the truth/falsehood of if the first is greater than the second. */ - bool operator>( const DerivedSegment &other ) const + bool operator>( const TimingSegment &other ) const { - return other.operator<(*static_cast(this)); + return other.operator<(*static_cast(this)); }; /** * @brief Compares two DrivedSegments to see if one is greater than or equal to the other. * @param other the other DrivedSegments to compare to. * @return the truth/falsehood of if the first is greater than or equal to the second. */ - bool operator>=( const DerivedSegment &other ) const { return !this->operator<(other); }; + bool operator>=( const TimingSegment &other ) const { return !this->operator<(other); }; + +private: + /** @brief The row in which this segment activates. */ + int startingRow; + + /** @brief The specific type of segment this is. */ + TimingSegmentType segType; }; @@ -139,7 +162,7 @@ struct TimingSegment: public BaseTimingSegment * drawn normally. * * These were inspired by the Pump It Up series. */ -struct FakeSegment : public TimingSegment +struct FakeSegment : public TimingSegment { /** * @brief Create a simple Fake Segment with default values. @@ -147,14 +170,14 @@ struct FakeSegment : public TimingSegment * It is best to override the values as soon as possible. */ FakeSegment(): - TimingSegment(-1), lengthBeats(-1) {}; + TimingSegment(-1), lengthBeats(-1) {}; /** * @brief Create a copy of another Fake Segment. * @param other the other fake segment */ FakeSegment(const FakeSegment &other): - TimingSegment(other), + TimingSegment(other.GetRow()), lengthBeats(other.GetLength()) {}; /** @@ -164,7 +187,7 @@ struct FakeSegment : public TimingSegment */ template FakeSegment( StartType s, LengthType r ): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), lengthBeats(ToBeat(max((LengthType)0, r))) {}; /** @@ -177,6 +200,8 @@ struct FakeSegment : public TimingSegment * @param b the length in beats. */ void SetLength(const float b); + void Scale( int start, int length, int newLength ); + /** * @brief Compares two FakeSegments to see if one is less than the other. * @param other the other FakeSegment to compare to. @@ -184,6 +209,15 @@ struct FakeSegment : public TimingSegment */ bool operator<( const FakeSegment &other ) const; + TimingSegmentType GetType() const { return SEGMENT_FAKE; } + + virtual RString ToString(int dec) const + { + RString str = "%.0" + IntToString(dec) + + "f=%.0" + IntToString(dec) + "f"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetLength()); + } + private: /** * @brief The number of beats the FakeSegment is alive for. @@ -198,7 +232,7 @@ private: * abusing negative BPMs. Negative BPMs should be converted to warp segments. * WarpAt=WarpToRelative is the format, where both are in beats. * (Technically they're both rows though.) */ -struct WarpSegment : public TimingSegment +struct WarpSegment : public TimingSegment { /** * @brief Create a simple Warp Segment with default values. @@ -206,14 +240,14 @@ struct WarpSegment : public TimingSegment * It is best to override the values as soon as possible. */ WarpSegment(): - TimingSegment(-1), lengthBeats(-1) {}; + TimingSegment(-1), lengthBeats(-1) {}; /** * @brief Create a copy of another Warp Segment. * @param other the other warp segment */ WarpSegment(const WarpSegment &other): - TimingSegment(other), + TimingSegment(other.GetRow()), lengthBeats(other.GetLength()) {}; /** @@ -223,7 +257,7 @@ struct WarpSegment : public TimingSegment */ template WarpSegment( StartType s, LengthType r ): - TimingSegment(s), + TimingSegment(s), lengthBeats(ToBeat(max((LengthType)0, r))) {}; /** @@ -236,12 +270,23 @@ struct WarpSegment : public TimingSegment * @param b the length in beats. */ void SetLength(const float b); + void Scale( int start, int length, int newLength ); + + virtual RString ToString(int dec) const + { + RString str = "%.0" + IntToString(dec) + + "f=%.0" + IntToString(dec) + "f"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetLength()); + } + /* * @brief Compares two WarpSegments to see if one is less than the other. * @param other the other WarpSegment to compare to. * @return the truth/falsehood of if the first is less than the second. */ bool operator<( const WarpSegment &other ) const; + + TimingSegmentType GetType() const { return SEGMENT_WARP; } private: /** * @brief The number of beats the FakeSegment is alive for. @@ -257,7 +302,7 @@ private: * system used by various based video games. The number is used to * represent how many ticks can be counted in one beat. */ -struct TickcountSegment : public TimingSegment +struct TickcountSegment : public TimingSegment { /** * @brief Creates a simple Tickcount Segment with default values. @@ -265,14 +310,14 @@ struct TickcountSegment : public TimingSegment * It is best to override the values as soon as possible. */ TickcountSegment(): - TimingSegment(-1), ticks(4) {}; + TimingSegment(-1), ticks(4) {}; /** * @brief Create a copy of another Tickcount Segment. * @param other the other tickcount segment */ TickcountSegment(const TickcountSegment &other): - TimingSegment(other), + TimingSegment(other.GetRow()), ticks(other.GetTicks()) {}; /** @@ -280,7 +325,7 @@ struct TickcountSegment : public TimingSegment * @param s the starting row / beat. */ template TickcountSegment( StartType s ): - TimingSegment(max((StartType)0, s)), ticks(4) {}; + TimingSegment(max((StartType)0, s)), ticks(4) {}; /** * @brief Creates a TickcountSegment with specified values. @@ -288,7 +333,7 @@ struct TickcountSegment : public TimingSegment * @param t the amount of ticks counted per beat. */ template TickcountSegment( StartType s, int t ): - TimingSegment(max((StartType)0, s)), ticks(max(0, t)) {}; + TimingSegment(max((StartType)0, s)), ticks(max(0, t)) {}; /** * @brief Get the number of ticks in this TickcountSegment. @@ -300,6 +345,12 @@ struct TickcountSegment : public TimingSegment * @param i the tickcount. */ void SetTicks(const int i); + virtual RString ToString(int dec) const + { + const RString str = "%.0" + IntToString(dec) + "f=%i"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetTicks()); + } + /** * @brief Compares two TickcountSegments to see if one is less than the other. * @param other the other TickcountSegment to compare to. @@ -307,6 +358,8 @@ struct TickcountSegment : public TimingSegment */ bool operator<( const TickcountSegment &other ) const; + TimingSegmentType GetType() const { return SEGMENT_TICKCOUNT; } + private: /** * @brief The amount of ticks counted per beat. @@ -320,7 +373,7 @@ private: * Admitedly, this would primarily be used for mission mode style charts. However, * it can have its place during normal gameplay. */ -struct ComboSegment : public TimingSegment +struct ComboSegment : public TimingSegment { /** * @brief Creates a simple Combo Segment with default values. @@ -328,11 +381,12 @@ struct ComboSegment : public TimingSegment * It is best to override the values as soon as possible. */ ComboSegment() : - TimingSegment(-1), combo(1) { } + TimingSegment(-1), combo(1), missCombo(1) { } ComboSegment(const ComboSegment &other) : - TimingSegment(other), - combo(other.GetCombo()) {}; + TimingSegment(other.GetRow()), + combo(other.GetCombo()), + missCombo(other.GetMissCombo()) {}; /** * @brief Creates a Combo Segment with the specified values. @@ -341,30 +395,66 @@ struct ComboSegment : public TimingSegment */ template ComboSegment( StartType s, int t ): - TimingSegment(max((StartType)0, s)), - combo(max(0,t)) {} + TimingSegment(max((StartType)0, s)), + combo(max(0,t)), missCombo(max(0,t)) {} + + /** + * @brief Creates a Combo Segment with the specified values. + * @param s the starting row / beat of this segment. + * @param t the amount the combo increases on a succesful hit. + * @param m the amount the miss combo increases on missing. + */ + template + ComboSegment(StartType s, int t, int m): + TimingSegment(max((StartType)0, s)), + combo(max(0,t)), missCombo(max(0,m)) {} /** * @brief Get the combo in this ComboSegment. * @return the combo. */ int GetCombo() const; + /** + * @brief Get the miss combo in this ComboSegment. + * @return the miss combo. */ + int GetMissCombo() const; + /** * @brief Set the combo in this ComboSegment. * @param i the combo. */ void SetCombo(const int i); + /** + * @brief Set the miss combo in this ComboSegment. + * @param i the miss combo. */ + void SetMissCombo(const int i); + + virtual RString ToString(int dec) const + { + RString str = "%.0" + IntToString(dec) + "f=%i"; + if (this->GetCombo() == this->GetMissCombo()) + { + return ssprintf(str.c_str(), this->GetBeat(), this->GetCombo()); + } + str += "=%i"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetCombo(), this->GetMissCombo()); + } + /** * @brief Compares two ComboSegments to see if one is less than the other. * @param other the other ComboSegment to compare to. * @return the truth/falsehood of if the first is less than the second. */ bool operator<( const ComboSegment &other ) const; + + TimingSegmentType GetType() const { return SEGMENT_COMBO; } private: /** * @brief The amount the combo increases at this point. */ int combo; + /** @brief The amount of miss combos given at this point. */ + int missCombo; }; @@ -374,7 +464,7 @@ private: * This is meant for helping to identify different sections of a chart * versus relying on measures and beats alone. */ -struct LabelSegment : public TimingSegment +struct LabelSegment : public TimingSegment { /** * @brief Creates a simple Label Segment with default values. @@ -382,10 +472,10 @@ struct LabelSegment : public TimingSegment * It is best to override the values as soon as possible. */ LabelSegment() : - TimingSegment(-1), label("") { } + TimingSegment(-1), label("") { } LabelSegment(const LabelSegment &other) : - TimingSegment(other), + TimingSegment(other.GetRow()), label(other.GetLabel()) {}; /** @@ -395,7 +485,7 @@ struct LabelSegment : public TimingSegment */ template LabelSegment( StartType s, RString l ): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), label(l) {} /** @@ -408,12 +498,20 @@ struct LabelSegment : public TimingSegment * @param l the label. */ void SetLabel(const RString l); + virtual RString ToString(int dec) const + { + const RString str = "%.0" + IntToString(dec) + "f=%s"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetLabel().c_str()); + } + /** * @brief Compares two LabelSegments to see if one is less than the other. * @param other the other LabelSegment to compare to. * @return the truth/falsehood of if the first is less than the second. */ bool operator<( const LabelSegment &other ) const; + + TimingSegmentType GetType() const { return SEGMENT_LABEL; } private: /** @@ -427,7 +525,7 @@ private: /** * @brief Identifies when a song changes its BPM. */ -struct BPMSegment : public TimingSegment +struct BPMSegment : public TimingSegment { /** * @brief Creates a simple BPM Segment with default values. @@ -435,15 +533,12 @@ struct BPMSegment : public TimingSegment * It is best to override the values as soon as possible. */ BPMSegment() : - TimingSegment(-1), bps(-1.0f) { } + TimingSegment(-1), bps(-1.0f) { } BPMSegment(const BPMSegment &other) : - TimingSegment(other), + TimingSegment(other.GetRow()), bps(other.GetBPS()) {}; - operator int() const { return 1; } - operator float() const { return 2.0f; } - /** * @brief Creates a BPM Segment with the specified starting row and beats per second. * @param s the starting row / beat of this segment. @@ -451,7 +546,7 @@ struct BPMSegment : public TimingSegment */ template BPMSegment( StartType s, float bpm ): - TimingSegment(max((StartType)0, s)), bps(0.0f) { SetBPM(bpm); } + TimingSegment(max((StartType)0, s)), bps(0.0f) { SetBPM(bpm); } /** * @brief Get the label in this LabelSegment. @@ -473,12 +568,21 @@ struct BPMSegment : public TimingSegment * @param l the label. */ void SetBPS(const float newBPS); + virtual RString ToString(int dec) const + { + const RString str = "%.0" + IntToString(dec) + + "f=%.0" + IntToString(dec) + "f"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetBPM()); + } + /** * @brief Compares two LabelSegments to see if one is less than the other. * @param other the other LabelSegment to compare to. * @return the truth/falsehood of if the first is less than the second. */ bool operator<( const BPMSegment &other ) const; + + TimingSegmentType GetType() const { return SEGMENT_BPM; } private: /** @@ -494,17 +598,17 @@ private: * (called the numerator here, though this isn't properly a * fraction) is the number of beats per measure. The lower number * (denominator here) is the note value representing one beat. */ -struct TimeSignatureSegment : public TimingSegment +struct TimeSignatureSegment : public TimingSegment { /** * @brief Creates a simple Time Signature Segment with default values. */ TimeSignatureSegment(): - TimingSegment(-1), + TimingSegment(-1), numerator(4), denominator(4) { } TimeSignatureSegment(const TimeSignatureSegment &other) : - TimingSegment(other), + TimingSegment(other.GetRow()), numerator(other.GetNum()), denominator(other.GetDen()) {}; /** @@ -516,7 +620,7 @@ struct TimeSignatureSegment : public TimingSegment */ template TimeSignatureSegment( StartType s, int n ): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), numerator(max(1, n)), denominator(4) {} /** * @brief Creates a Time Signature Segment with supplied values. @@ -526,7 +630,7 @@ struct TimeSignatureSegment : public TimingSegment */ template TimeSignatureSegment( StartType s, int n, int d ): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), numerator(max(1, n)), denominator(max(1, d)) {} /** @@ -549,6 +653,12 @@ struct TimeSignatureSegment : public TimingSegment * @param i the denominator. */ void SetDen(const int i); + virtual RString ToString(int dec) const + { + const RString str = "%.0" + IntToString(dec) + "f=%i=%i"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetNum(), this->GetDen()); + } + /** * @brief Retrieve the number of note rows per measure within the TimeSignatureSegment. * @@ -567,6 +677,8 @@ struct TimeSignatureSegment : public TimingSegment * @return the truth/falsehood of if the first is less than the second. */ bool operator<( const TimeSignatureSegment &other ) const; + + TimingSegmentType GetType() const { return SEGMENT_TIME_SIG; } private: /** * @brief The numerator of the TimeSignatureSegment. @@ -588,15 +700,15 @@ private: * back to 1. * * These were inspired by the Pump It Up series. */ -struct SpeedSegment : public TimingSegment +struct SpeedSegment : public TimingSegment { /** @brief Sets up the SpeedSegment with default values. */ SpeedSegment(): - TimingSegment(0), + TimingSegment(0), ratio(1), length(0), unit(0) {} SpeedSegment(const SpeedSegment &other) : - TimingSegment(other), + TimingSegment(other.GetRow()), ratio(other.GetRatio()), length(other.GetLength()), unit(other.GetUnit()) {}; @@ -607,7 +719,7 @@ struct SpeedSegment : public TimingSegment * @param p The percentage to use. */ template SpeedSegment( StartType s, float p): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), ratio(p), length(0), unit(0) {} /** @@ -617,7 +729,7 @@ struct SpeedSegment : public TimingSegment * @param w The number of beats to wait. */ template SpeedSegment(StartType s, float p, float w): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), ratio(p), length(w), unit(0) {} @@ -629,7 +741,7 @@ struct SpeedSegment : public TimingSegment * @param k The mode used for the wait variable. */ template SpeedSegment(StartType s, float p, float w, unsigned short k): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), ratio(p), length(w), unit(k) {} /** @@ -669,12 +781,25 @@ struct SpeedSegment : public TimingSegment * @param i the unit. */ void SetUnit(const int i); + void Scale( int start, int length, int newLength ); + + virtual RString ToString(int dec) const + { + const RString str = "%.0" + IntToString(dec) + + "f=%.0" + IntToString(dec) + "f=%.0" + + IntToString(dec) + "f=%u"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetRatio(), + this->GetLength(), this->GetUnit()); + } + /** * @brief Compares two SpeedSegments to see if one is less than the other. * @param other the other SpeedSegment to compare to. * @return the truth/falsehood of if the first is less than the second. */ bool operator<( const SpeedSegment &other ) const; + + TimingSegmentType GetType() const { return SEGMENT_SPEED; } private: /** @brief The percentage (ratio) to use when multiplying the Player's BPM. */ float ratio; @@ -702,10 +827,10 @@ private: * reset it by setting the precentage back to 1. * * These were inspired by the Pump It Up series. */ -struct ScrollSegment : public TimingSegment +struct ScrollSegment : public TimingSegment { /** @brief Sets up the ScrollSegment with default values. */ - ScrollSegment(): TimingSegment(0), + ScrollSegment(): TimingSegment(0), ratio(1) {} /** @@ -714,11 +839,11 @@ struct ScrollSegment : public TimingSegment * @param p The percentage to use. */ template ScrollSegment( StartType s, float p): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), ratio(p) {} ScrollSegment(const ScrollSegment &other) : - TimingSegment(other), + TimingSegment(other.GetRow()), ratio(other.GetRatio()) {} /** @@ -731,12 +856,21 @@ struct ScrollSegment : public TimingSegment * @param i the ratio. */ void SetRatio(const float i); + virtual RString ToString(int dec) const + { + const RString str = "%.0" + IntToString(dec) + + "f=%.0" + IntToString(dec) + "f"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetRatio()); + } + /** * @brief Compares two ScrollSegment to see if one is less than the other. * @param other the other ScrollSegment to compare to. * @return the truth/falsehood of if the first is less than the second. */ bool operator<( const ScrollSegment &other ) const; + + TimingSegmentType GetType() const { return SEGMENT_SCROLL; } private: /** @brief The ratio / percentage to use when multiplying the chart's scroll rate. */ float ratio; @@ -747,18 +881,18 @@ private: * * It is hopeful that stops and delays can be made into their own segments at some point. */ -struct StopSegment : public TimingSegment +struct StopSegment : public TimingSegment { /** * @brief Creates a simple Stop Segment with default values. * * It is best to override the values as soon as possible. */ - StopSegment() : TimingSegment(-1), + StopSegment() : TimingSegment(-1), pauseSeconds(-1.0f), isDelay(false) {} StopSegment (const StopSegment &other): - TimingSegment(other), + TimingSegment(other.GetRow()), pauseSeconds(other.GetPause()), isDelay(other.GetDelay()) {} @@ -772,7 +906,7 @@ struct StopSegment : public TimingSegment */ template StopSegment( StartType s, float f ): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), pauseSeconds(f), isDelay(false) {} /** * @brief Creates a Stop/Delay Segment with specified values. @@ -782,7 +916,7 @@ struct StopSegment : public TimingSegment */ template StopSegment( StartType s, float f, bool d ): - TimingSegment(max((StartType)0, s)), + TimingSegment(max((StartType)0, s)), pauseSeconds(f), isDelay(d) {} /** @@ -804,6 +938,13 @@ struct StopSegment : public TimingSegment * @brief Set the behavior in this StopSegment. * @param i the behavior. */ void SetDelay(const bool i); + + virtual RString ToString(int dec) const + { + const RString str = "%.0" + IntToString(dec) + + "f=%.0" + IntToString(dec) + "f"; + return ssprintf(str.c_str(), this->GetBeat(), this->GetPause()); + } /** * @brief Compares two StopSegments to see if one is less than the other. @@ -815,6 +956,8 @@ struct StopSegment : public TimingSegment * @return the truth/falsehood of if the first is less than the second. */ bool operator<( const StopSegment &other ) const; + + TimingSegmentType GetType() const { return SEGMENT_STOP_DELAY; } private: /** * @brief The amount of time to complete the pause at the given row. diff --git a/src/Trail.cpp b/src/Trail.cpp index 073d266c93..25ece2abd3 100644 --- a/src/Trail.cpp +++ b/src/Trail.cpp @@ -1,6 +1,7 @@ #include "global.h" #include "Trail.h" #include "Foreach.h" +#include "GameState.h" #include "Steps.h" #include "Song.h" #include "PlayerOptions.h" @@ -116,6 +117,7 @@ const RadarValues &Trail::GetRadarValues() const NoteData nd; pSteps->GetNoteData( nd ); RadarValues rv_orig; + GAMESTATE->SetProcessedTimingData(const_cast(&pSteps->m_Timing)); NoteDataUtil::CalculateRadarValues( nd, e->pSong->m_fMusicLengthSeconds, rv_orig ); PlayerOptions po; po.FromString( e->Modifiers ); @@ -124,6 +126,7 @@ const RadarValues &Trail::GetRadarValues() const NoteDataUtil::TransformNoteData( nd, e->Attacks, pSteps->m_StepsType, e->pSong ); RadarValues transformed_rv; NoteDataUtil::CalculateRadarValues( nd, e->pSong->m_fMusicLengthSeconds, transformed_rv ); + GAMESTATE->SetProcessedTimingData(NULL); rv += transformed_rv; } else diff --git a/src/UnlockManager.cpp b/src/UnlockManager.cpp index 47af088551..b3d045d649 100644 --- a/src/UnlockManager.cpp +++ b/src/UnlockManager.cpp @@ -7,6 +7,7 @@ #include "RageUtil.h" #include "SongManager.h" #include "GameState.h" +#include "GameConstantsAndTypes.h" // StepsTypeToString #include "ProfileManager.h" #include "Profile.h" #include "ThemeManager.h" @@ -24,6 +25,8 @@ UnlockManager* UNLOCKMAN = NULL; // global and accessable from anywhere in our p #define UNLOCK(x) THEME->GetMetricR("UnlockManager", ssprintf("Unlock%sCommand",x.c_str())); static ThemeMetric AUTO_LOCK_CHALLENGE_STEPS( "UnlockManager", "AutoLockChallengeSteps" ); +static ThemeMetric AUTO_LOCK_EDIT_STEPS( "UnlockManager", "AutoLockEditSteps" ); +static ThemeMetric SONGS_NOT_ADDITIONAL( "UnlockManager", "SongsNotAdditional" ); static const char *UnlockRequirementNames[] = { @@ -44,6 +47,7 @@ static const char *UnlockRewardTypeNames[] = { "Song", "Steps", + "StepsType", "Course", "Modifier", }; @@ -171,6 +175,18 @@ bool UnlockManager::StepsIsLocked( const Song *pSong, const Steps *pSteps ) cons return p->IsLocked(); } +bool UnlockManager::StepsTypeIsLocked(const Song *pSong, const Steps *pSteps, const StepsType *pSType) const +{ + if( !PREFSMAN->m_bUseUnlockSystem ) + return false; + + const UnlockEntry *p = FindStepsType( pSong, pSteps, pSType ); + if( p == NULL ) + return false; + + return p->IsLocked(); +} + bool UnlockManager::ModifierIsLocked( const RString &sOneMod ) const { if( !PREFSMAN->m_bUseUnlockSystem ) @@ -200,6 +216,19 @@ const UnlockEntry *UnlockManager::FindSteps( const Song *pSong, const Steps *pSt return NULL; } +const UnlockEntry *UnlockManager::FindStepsType(const Song *pSong, + const Steps *pSteps, + const StepsType *pSType ) const +{ + ASSERT( pSong && pSteps && pSType ); + FOREACH_CONST( UnlockEntry, m_UnlockEntries, e ) + if(e->m_Song.ToSong() == pSong && + e->m_dc == pSteps->GetDifficulty() && + e->m_StepsType == pSteps->m_StepsType) + return &(*e); + return NULL; +} + const UnlockEntry *UnlockManager::FindCourse( const Course *pCourse ) const { FOREACH_CONST( UnlockEntry, m_UnlockEntries, e ) @@ -295,7 +324,7 @@ void UnlockManager::GetPoints( const Profile *pProfile, float fScores[NUM_Unlock fScores[UnlockRequirement_SongPoints] = GetSongPoints( pProfile ); fScores[UnlockRequirement_DancePoints] = (float) pProfile->m_iTotalDancePoints; fScores[UnlockRequirement_StagesCleared] = (float) pProfile->GetTotalNumSongsPassed(); - fScores[UnlockRequirement_NumUnlocked] = (float) GetNumUnlocked(); + //fScores[UnlockRequirement_NumUnlocked] = (float) GetNumUnlocked(); } /* Return true if all songs and/or courses referenced by an unlock are available. */ @@ -309,6 +338,11 @@ bool UnlockEntry::IsValid() const case UnlockRewardType_Steps: return m_Song.IsValid() && m_dc != Difficulty_Invalid; + case UnlockRewardType_Steps_Type: + { + return m_Song.IsValid() && m_dc != Difficulty_Invalid && m_StepsType != StepsType_Invalid; + } + case UnlockRewardType_Course: return m_Course.IsValid(); @@ -323,15 +357,22 @@ bool UnlockEntry::IsValid() const UnlockEntryStatus UnlockEntry::GetUnlockEntryStatus() const { - if( !m_sEntryID.empty() && PROFILEMAN->GetMachineProfile()->m_UnlockedEntryIDs.find(m_sEntryID) != PROFILEMAN->GetMachineProfile()->m_UnlockedEntryIDs.end() ) + set &ids = PROFILEMAN->GetMachineProfile()->m_UnlockedEntryIDs; + if(!m_sEntryID.empty() && + ids.find(m_sEntryID) != ids.end() ) return UnlockEntryStatus_Unlocked; float fScores[NUM_UnlockRequirement]; UNLOCKMAN->GetPoints( PROFILEMAN->GetMachineProfile(), fScores ); for( int i = 0; i < NUM_UnlockRequirement; ++i ) + { + if( i == UnlockRequirement_NumUnlocked ) + continue; + if( m_fRequirement[i] && fScores[i] >= m_fRequirement[i] ) return UnlockEntryStatus_RequirementsMet; + } if( m_bRequirePassHardSteps && m_Song.IsValid() ) { @@ -347,7 +388,21 @@ UnlockEntryStatus UnlockEntry::GetUnlockEntryStatus() const if( PROFILEMAN->GetMachineProfile()->HasPassedSteps(pSong, *s) ) return UnlockEntryStatus_RequirementsMet; } - + + if (m_bRequirePassChallengeSteps && m_Song.IsValid()) + { + Song *pSong = m_Song.ToSong(); + vector vp; + SongUtil::GetSteps(pSong, + vp, + StepsType_Invalid, + Difficulty_Challenge); + FOREACH_CONST(Steps*, vp, s) + { + if (PROFILEMAN->GetMachineProfile()->HasPassedSteps(pSong, *s)) + return UnlockEntryStatus_RequirementsMet; + } + } return UnlockEntryStatus_RequrementsNotMet; } @@ -363,10 +418,16 @@ RString UnlockEntry::GetDescription() const case UnlockRewardType_Song: return pSong ? pSong->GetDisplayFullTitle() : ""; case UnlockRewardType_Steps: - { - StepsType st = GAMEMAN->GetHowToPlayStyleForGame( GAMESTATE->m_pCurGame )->m_StepsType; // TODO: Is this the best thing we can do here? - return (pSong ? pSong->GetDisplayFullTitle() : "") + ", " + CustomDifficultyToLocalizedString( GetCustomDifficulty(st, m_dc, CourseType_Invalid) ); - } + { + StepsType st = GAMEMAN->GetHowToPlayStyleForGame( GAMESTATE->m_pCurGame )->m_StepsType; // TODO: Is this the best thing we can do here? + return (pSong ? pSong->GetDisplayFullTitle() : "") + ", " + CustomDifficultyToLocalizedString( GetCustomDifficulty(st, m_dc, CourseType_Invalid) ); + } + case UnlockRewardType_Steps_Type: + { + RString ret = (pSong ? pSong->GetDisplayFullTitle() : ""); + ret += "," + CustomDifficultyToLocalizedString( GetCustomDifficulty(m_StepsType, m_dc, CourseType_Invalid) ); + return ret + "," + StringConversion::ToString(m_StepsType); // yeah, bit strange. + } case UnlockRewardType_Course: return m_Course.IsValid() ? m_Course.ToCourse()->GetDisplayFullTitle() : ""; case UnlockRewardType_Modifier: @@ -384,6 +445,7 @@ RString UnlockEntry::GetBannerFile() const return ""; case UnlockRewardType_Song: case UnlockRewardType_Steps: + case UnlockRewardType_Steps_Type: return pSong ? pSong->GetBannerPath() : ""; case UnlockRewardType_Course: return m_Course.ToCourse() ? m_Course.ToCourse()->GetBannerPath() : ""; @@ -402,6 +464,7 @@ RString UnlockEntry::GetBackgroundFile() const return ""; case UnlockRewardType_Song: case UnlockRewardType_Steps: + case UnlockRewardType_Steps_Type: return pSong ? pSong->GetBackgroundPath() : ""; case UnlockRewardType_Course: return ""; @@ -458,7 +521,7 @@ void UnlockManager::Load() if( SongUtil::GetOneSteps(*s, StepsType_Invalid, Difficulty_Challenge) == NULL ) continue; - if( SONGMAN->WasLoadedFromAdditionalSongs(*s) ) + if( SONGS_NOT_ADDITIONAL && SONGMAN->WasLoadedFromAdditionalSongs(*s) ) continue; UnlockEntry ue; @@ -470,6 +533,33 @@ void UnlockManager::Load() m_UnlockEntries.push_back( ue ); } } + + if (AUTO_LOCK_EDIT_STEPS) + { + FOREACH_CONST( Song*, SONGMAN->GetAllSongs(), s ) + { + // no challenge steps to play: skip. + if (SongUtil::GetOneSteps(*s, StepsType_Invalid, Difficulty_Challenge) == NULL) + continue; + + // no edit steps to unlock: skip. + if (SongUtil::GetOneSteps(*s, StepsType_Invalid, Difficulty_Edit) == NULL) + continue; + + // don't add additional songs. + if (SONGS_NOT_ADDITIONAL && SONGMAN->WasLoadedFromAdditionalSongs(*s)) + continue; + + UnlockEntry ue; + ue.m_sEntryID = "_edit_" + (*s)->GetSongDir(); + ue.m_Type = UnlockRewardType_Steps; + ue.m_cmd.Load( (*s)->m_sGroupName+"/"+(*s)->GetTranslitFullTitle()+",edit" ); + ue.m_bRequirePassChallengeSteps = true; + + m_UnlockEntries.push_back(ue); + + } + } // Make sure that we don't have duplicate unlock IDs. This can cause problems // with UnlockCelebrate and with codes. @@ -503,6 +593,30 @@ void UnlockManager::Load() } break; + case UnlockRewardType_Steps_Type: + { + e->m_Song.FromSong( SONGMAN->FindSong( e->m_cmd.GetArg(0).s ) ); + if( !e->m_Song.IsValid() ) + { + LOG->Warn( "Unlock: Cannot find song matching \"%s\"", e->m_cmd.GetArg(0).s.c_str() ); + break; + } + + e->m_dc = StringToDifficulty( e->m_cmd.GetArg(1).s ); + if( e->m_dc == Difficulty_Invalid ) + { + LOG->Warn( "Unlock: Invalid difficulty \"%s\"", e->m_cmd.GetArg(1).s.c_str() ); + break; + } + + e->m_StepsType = GAMEMAN->StringToStepsType(e->m_cmd.GetArg(2).s); + if (e->m_StepsType == StepsType_Invalid) + { + LOG->Warn( "Unlock: Invalid steps type \"%s\"", e->m_cmd.GetArg(2).s.c_str() ); + break; + } + break; + } case UnlockRewardType_Course: e->m_Course.FromCourse( SONGMAN->FindCourse(e->m_cmd.GetArg(0).s) ); if( !e->m_Course.IsValid() ) @@ -525,6 +639,8 @@ void UnlockManager::Load() str += ssprintf( "%s = %f; ", UnlockRequirementToString(j).c_str(), e->m_fRequirement[j] ); if( e->m_bRequirePassHardSteps ) str += "RequirePassHardSteps; "; + if (e->m_bRequirePassChallengeSteps) + str += "RequirePassChallengeSteps; "; str += ssprintf( "entryID = %s ", e->m_sEntryID.c_str() ); str += e->IsLocked()? "locked":"unlocked"; @@ -601,7 +717,7 @@ int UnlockManager::GetNumUnlocked() const int count = 0; FOREACH_CONST( UnlockEntry, m_UnlockEntries, ue ) { - if( ue->GetUnlockEntryStatus() == UnlockEntryStatus_Unlocked ) + if( !ue->IsLocked() ) count++; } return count; @@ -667,6 +783,11 @@ public: static int GetUnlockRewardType( T* p, lua_State *L ) { lua_pushnumber(L, p->m_Type ); return 1; } static int GetRequirement( T* p, lua_State *L ) { UnlockRequirement i = Enum::Check( L, 1 ); lua_pushnumber(L, p->m_fRequirement[i] ); return 1; } static int GetRequirePassHardSteps( T* p, lua_State *L ){ lua_pushboolean(L, p->m_bRequirePassHardSteps); return 1; } + static int GetRequirePassChallengeSteps( T* p, lua_State *L ) + { + lua_pushboolean(L, p->m_bRequirePassChallengeSteps); + return 1; + } static int GetSong( T* p, lua_State *L ) { Song *pSong = p->m_Song.ToSong(); @@ -697,6 +818,7 @@ public: static int song( T* p, lua_State *L ) { GetArgs( p, L ); p->m_Type = UnlockRewardType_Song; return 0; } static int steps( T* p, lua_State *L ) { GetArgs( p, L ); p->m_Type = UnlockRewardType_Steps; return 0; } + static int steps_type(T* p, lua_State *L) { GetArgs(p, L); p->m_Type = UnlockRewardType_Steps_Type; return 0; } static int course( T* p, lua_State *L ) { GetArgs( p, L ); p->m_Type = UnlockRewardType_Course; return 0; } static int mod( T* p, lua_State *L ) { GetArgs( p, L ); p->m_Type = UnlockRewardType_Modifier; return 0; } static int code( T* p, lua_State *L ) { p->m_sEntryID = SArg(1); return 0; } @@ -718,10 +840,12 @@ public: ADD_METHOD( GetUnlockRewardType ); ADD_METHOD( GetRequirement ); ADD_METHOD( GetRequirePassHardSteps ); + ADD_METHOD( GetRequirePassChallengeSteps ); ADD_METHOD( GetSong ); ADD_METHOD( GetCourse ); ADD_METHOD( song ); ADD_METHOD( steps ); + ADD_METHOD( steps_type ); ADD_METHOD( course ); ADD_METHOD( mod ); ADD_METHOD( code ); diff --git a/src/UnlockManager.h b/src/UnlockManager.h index 6c085e6680..56a14d3db6 100644 --- a/src/UnlockManager.h +++ b/src/UnlockManager.h @@ -16,16 +16,17 @@ class Steps; class Profile; struct lua_State; +/** @brief What is needed to unlock an item? */ enum UnlockRequirement { - UnlockRequirement_ArcadePoints, - UnlockRequirement_DancePoints, - UnlockRequirement_SongPoints, - UnlockRequirement_ExtraCleared, - UnlockRequirement_ExtraFailed, - UnlockRequirement_Toasties, - UnlockRequirement_StagesCleared, - UnlockRequirement_NumUnlocked, + UnlockRequirement_ArcadePoints, /**< Get a certain number of arcade points. */ + UnlockRequirement_DancePoints, /**< Get a certain number of dance points. */ + UnlockRequirement_SongPoints, /**< Get a certain number of song points. */ + UnlockRequirement_ExtraCleared, /**< Pass the extra stage. */ + UnlockRequirement_ExtraFailed, /**< Fail the extra stage. */ + UnlockRequirement_Toasties, /**< Get a number of toasties. */ + UnlockRequirement_StagesCleared, /**< Clear a number of stages. */ + UnlockRequirement_NumUnlocked, /**< Have a number of locked items already unlocked. */ NUM_UnlockRequirement, UnlockRequirement_Invalid, }; @@ -33,10 +34,11 @@ LuaDeclareType( UnlockRequirement ); enum UnlockRewardType { - UnlockRewardType_Song, - UnlockRewardType_Steps, - UnlockRewardType_Course, - UnlockRewardType_Modifier, + UnlockRewardType_Song, /**< A song is unlocked. */ + UnlockRewardType_Steps, /**< A step pattern for all styles is unlocked. */ + UnlockRewardType_Steps_Type, /**< A step pattern for a specific style is unlocked. */ + UnlockRewardType_Course, /**< A course is unlocked. */ + UnlockRewardType_Modifier, /**< A modifier is unlocked. */ NUM_UnlockRewardType, UnlockRewardType_Invalid }; @@ -60,7 +62,8 @@ public: * if not specified. */ UnlockEntry(): m_Type(UnlockRewardType_Invalid), m_cmd(), m_Song(), m_dc(Difficulty_Invalid), m_Course(), - m_bRequirePassHardSteps(false), m_bRoulette(false), + m_StepsType(StepsType_Invalid), m_bRequirePassHardSteps(false), + m_bRequirePassChallengeSteps(false), m_bRoulette(false), m_sEntryID(RString("")) { ZERO( m_fRequirement ); @@ -74,9 +77,13 @@ public: SongID m_Song; Difficulty m_dc; CourseID m_Course; + StepsType m_StepsType; float m_fRequirement[NUM_UnlockRequirement]; // unlocked if any of of these are met + /** @brief Must the hard steps be passed to unlock a higher level? */ bool m_bRequirePassHardSteps; + /** @brief Must the challenge steps be passed to unlock a higher level? */ + bool m_bRequirePassChallengeSteps; bool m_bRoulette; RString m_sEntryID; @@ -117,6 +124,7 @@ public: float PointsUntilNextUnlock( UnlockRequirement t ) const; int SongIsLocked( const Song *pSong ) const; bool StepsIsLocked( const Song *pSong, const Steps *pSteps ) const; + bool StepsTypeIsLocked( const Song *pSong, const Steps *pSteps, const StepsType *pSType ) const; int CourseIsLocked( const Course *course ) const; bool ModifierIsLocked( const RString &sOneMod ) const; @@ -153,6 +161,7 @@ public: const UnlockEntry *FindSong( const Song *pSong ) const; const UnlockEntry *FindSteps( const Song *pSong, const Steps *pSteps ) const; + const UnlockEntry *FindStepsType( const Song *pSong, const Steps *pSteps, const StepsType *pSType ) const; const UnlockEntry *FindCourse( const Course *pCourse ) const; const UnlockEntry *FindModifier( const RString &sOneMod ) const; diff --git a/src/arch/ArchHooks/ArchHooks_Unix.cpp b/src/arch/ArchHooks/ArchHooks_Unix.cpp index 6f33443e79..eba3d49970 100644 --- a/src/arch/ArchHooks/ArchHooks_Unix.cpp +++ b/src/arch/ArchHooks/ArchHooks_Unix.cpp @@ -278,7 +278,7 @@ void ArchHooks::MountInitialFilesystems( const RString &sDirOfExecutable ) const char *szHome = getenv( "HOME" ); RString sProductId = PRODUCT_ID; sProductId.MakeLower(); - RString sUserDataPath = ssprintf( "%s/.%s", szHome? szHome:".", sProductId.c_str() ); + RString sUserDataPath = ssprintf( "%s/.%s", szHome? szHome:".", "stepmania5" ); FILEMAN->Mount( "dir", sUserDataPath + "/Cache", "/Cache" ); FILEMAN->Mount( "dir", sUserDataPath + "/Logs", "/Logs" ); FILEMAN->Mount( "dir", sUserDataPath + "/Save", "/Save" ); diff --git a/src/arch/ArchHooks/ArchHooks_Win32Static.cpp b/src/arch/ArchHooks/ArchHooks_Win32Static.cpp index 3e63241dc4..4b10291357 100644 --- a/src/arch/ArchHooks/ArchHooks_Win32Static.cpp +++ b/src/arch/ArchHooks/ArchHooks_Win32Static.cpp @@ -55,14 +55,13 @@ static RString GetMountDir( const RString &sDirOfExecutable ) void ArchHooks::MountInitialFilesystems( const RString &sDirOfExecutable ) { RString sDir = GetMountDir( sDirOfExecutable ); - RString sCommonAppDataDir = SpecialDirs::GetCommonAppDataDir() + PRODUCT_ID; + FILEMAN->Mount( "dir", sDir, "/" ); - FILEMAN->Mount( "dir", sCommonAppDataDir, "/" ); - FILEMAN->Mount( "dir", sCommonAppDataDir + "/Cache", "/Cache" ); } void ArchHooks::MountUserFilesystems( const RString &sDirOfExecutable ) { + RString sCommonAppDataDir = SpecialDirs::GetCommonAppDataDir() + PRODUCT_ID; RString sAppDataDir = SpecialDirs::GetAppDataDir() + PRODUCT_ID; RString sLocalAppDataDir = SpecialDirs::GetLocalAppDataDir() + PRODUCT_ID; RString sPicturesDir = SpecialDirs::GetPicturesDir() + PRODUCT_ID; @@ -70,6 +69,8 @@ void ArchHooks::MountUserFilesystems( const RString &sDirOfExecutable ) FILEMAN->Mount( "dir", sAppDataDir + "/Logs", "/Logs" ); FILEMAN->Mount( "dir", sAppDataDir + "/Save", "/Save" ); FILEMAN->Mount( "dir", sPicturesDir + " Screenshots", "/Screenshots" ); + FILEMAN->Mount( "dir", sCommonAppDataDir, "/" ); + FILEMAN->Mount( "dir", sCommonAppDataDir + "/Cache", "/Cache" ); FILEMAN->Mount( "dir", sAppDataDir + "/Packages", "/" + SpecialFiles::USER_PACKAGES_DIR ); } diff --git a/src/arch/InputHandler/InputHandler_DirectInput.cpp b/src/arch/InputHandler/InputHandler_DirectInput.cpp index 9817a88d0d..42d8387441 100644 --- a/src/arch/InputHandler/InputHandler_DirectInput.cpp +++ b/src/arch/InputHandler/InputHandler_DirectInput.cpp @@ -384,6 +384,10 @@ void InputHandler_DInput::UpdatePolled( DIDevice &device, const RageTimer &tm ) if( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) return; + // reset mousewheel + ButtonPressed( DeviceInput(device.dev, MOUSE_WHEELUP, 0, tm) ); + ButtonPressed( DeviceInput(device.dev, MOUSE_WHEELDOWN, 0, tm) ); + for( unsigned i = 0; i < device.Inputs.size(); ++i ) { const input_t &in = device.Inputs[i]; @@ -476,6 +480,12 @@ void InputHandler_DInput::UpdateBuffered( DIDevice &device, const RageTimer &tm return; } + // reset mousewheel + DeviceInput diUp = DeviceInput(device.dev, MOUSE_WHEELUP, 0.0f, tm); + ButtonPressed( diUp ); + DeviceInput diDown = DeviceInput(device.dev, MOUSE_WHEELDOWN, 0.0f, tm); + ButtonPressed( diDown ); + for( int i = 0; i < (int) numevents; ++i ) { for(unsigned j = 0; j < device.Inputs.size(); ++j) @@ -522,6 +532,7 @@ void InputHandler_DInput::UpdateBuffered( DIDevice &device, const RageTimer &tm GetCursorPos(&cursorPos); // convert screen coordinates to client ScreenToClient(GraphicsWindow::GetHwnd(), &cursorPos); + switch(in.ofs) { case DIMOFS_X: diff --git a/src/arch/LoadingWindow/LoadingWindow.cpp b/src/arch/LoadingWindow/LoadingWindow.cpp index 2002e81f45..c96afbff84 100644 --- a/src/arch/LoadingWindow/LoadingWindow.cpp +++ b/src/arch/LoadingWindow/LoadingWindow.cpp @@ -47,12 +47,17 @@ LoadingWindow *LoadingWindow::Create() } } - if( ret ) + if( ret ) { LOG->Info( "Loading window: %s", Driver.c_str() ); + ret->SetIndeterminate(true); + } + return ret; } +LoadingWindow *pLoadingWindow; + /* * (c) 2002-2005 Glenn Maynard * All rights reserved. diff --git a/src/arch/LoadingWindow/LoadingWindow.h b/src/arch/LoadingWindow/LoadingWindow.h index 888a265e39..ec92728e1f 100644 --- a/src/arch/LoadingWindow/LoadingWindow.h +++ b/src/arch/LoadingWindow/LoadingWindow.h @@ -11,11 +11,21 @@ public: virtual RString Init() { return RString(); } virtual ~LoadingWindow() { } - virtual void Paint() { } virtual void SetText( RString str ) = 0; virtual void SetIcon( const RageSurface *pIcon ) { } + virtual void SetSplash( const RString sPath ) { } + virtual void SetProgress( const int progress ) { m_progress=progress; } + virtual void SetTotalWork( const int totalWork ) { m_totalWork=totalWork; } + virtual void SetIndeterminate( bool indeterminate ) { m_indeterminate=indeterminate; } + +protected: + int m_progress; + int m_totalWork; + bool m_indeterminate; }; +extern LoadingWindow *pLoadingWindow; + #endif /** diff --git a/src/arch/LoadingWindow/LoadingWindow_Gtk.cpp b/src/arch/LoadingWindow/LoadingWindow_Gtk.cpp index c27a6f3cb2..ec82aa8f3d 100644 --- a/src/arch/LoadingWindow/LoadingWindow_Gtk.cpp +++ b/src/arch/LoadingWindow/LoadingWindow_Gtk.cpp @@ -11,6 +11,8 @@ static void *Handle = NULL; static INIT Module_Init; static SHUTDOWN Module_Shutdown; static SETTEXT Module_SetText; +static SETPROGRESS Module_SetProgress; +static SETINDETERMINATE Module_SetIndeterminate; LoadingWindow_Gtk::LoadingWindow_Gtk() { @@ -33,6 +35,12 @@ RString LoadingWindow_Gtk::Init() Module_SetText = (SETTEXT) dlsym(Handle, "SetText"); if( !Module_SetText ) return "Couldn't load symbol Module_SetText"; + Module_SetProgress = (SETPROGRESS) dlsym(Handle, "SetProgress"); + if( !Module_SetProgress ) + return "Couldn't load symbol Module_SetProgress"; + Module_SetIndeterminate = (SETINDETERMINATE) dlsym(Handle, "SetIndeterminate"); + if( !Module_SetIndeterminate ) + return "Couldn't load symbol Module_SetIndeterminate"; const char *ret = Module_Init( &g_argc, &g_argv ); if( ret != NULL ) @@ -56,6 +64,24 @@ void LoadingWindow_Gtk::SetText( RString s ) Module_SetText( s ); } +void LoadingWindow_Gtk::SetProgress( const int progress ) +{ + LoadingWindow::SetProgress( progress ); + Module_SetProgress( m_progress, m_totalWork ); +} + +void LoadingWindow_Gtk::SetTotalWork( const int totalWork ) +{ + LoadingWindow::SetTotalWork( totalWork ); + Module_SetProgress( m_progress, m_totalWork ); +} + +void LoadingWindow_Gtk::SetIndeterminate( bool indeterminate ) +{ + LoadingWindow::SetIndeterminate( indeterminate ); + Module_SetIndeterminate( m_indeterminate ); +} + /* * (c) 2003-2004 Glenn Maynard, Sean Burke * All rights reserved. diff --git a/src/arch/LoadingWindow/LoadingWindow_Gtk.h b/src/arch/LoadingWindow/LoadingWindow_Gtk.h index 14752cc58a..3ccca35841 100644 --- a/src/arch/LoadingWindow/LoadingWindow_Gtk.h +++ b/src/arch/LoadingWindow/LoadingWindow_Gtk.h @@ -11,8 +11,11 @@ public: LoadingWindow_Gtk(); RString Init(); ~LoadingWindow_Gtk(); - void SetText( RString str ); + void SetSplash( const RString str ) {} + void SetProgress( const int progress ); + void SetTotalWork( const int totalWork ); + void SetIndeterminate( bool indeterminate ); }; #define USE_LOADING_WINDOW_GTK diff --git a/src/arch/LoadingWindow/LoadingWindow_GtkModule.cpp b/src/arch/LoadingWindow/LoadingWindow_GtkModule.cpp index 78c65d1fb2..edc722fcb0 100644 --- a/src/arch/LoadingWindow/LoadingWindow_GtkModule.cpp +++ b/src/arch/LoadingWindow/LoadingWindow_GtkModule.cpp @@ -5,6 +5,7 @@ static GtkWidget *label; static GtkWidget *window; +static GtkWidget *progressBar; extern "C" const char *Init( int *argc, char ***argv ) { @@ -22,9 +23,12 @@ extern "C" const char *Init( int *argc, char ***argv ) loadimage = gtk_image_new_from_file(splash_image_path); label = gtk_label_new(NULL); gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_CENTER); + progressBar = gtk_progress_bar_new(); + gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR(progressBar), 0.0 ); vbox = gtk_vbox_new(FALSE,5); gtk_container_add(GTK_CONTAINER(window),vbox); gtk_box_pack_start(GTK_BOX(vbox),loadimage,FALSE,FALSE,0); + gtk_box_pack_end(GTK_BOX(vbox),progressBar,TRUE,TRUE,0); gtk_box_pack_end(GTK_BOX(vbox),label,TRUE,TRUE,0); gtk_widget_show_all(window); @@ -47,6 +51,21 @@ extern "C" void SetText( const char *s ) gtk_main_iteration_do(FALSE); } +extern "C" void SetProgress( int progress, int totalWork ) +{ + gdouble fraction = ( totalWork > 0 ? progress / (gdouble)totalWork : 0 ); + if( fraction > 1.0 ) fraction = 1.0; + if( fraction < 0.0 ) fraction = 0.0; + gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR(progressBar), fraction ); + gtk_main_iteration_do(FALSE); +} + +extern "C" void SetIndeterminate( bool indeterminate ) +{ + gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progressBar)); + gtk_main_iteration_do(FALSE); +} + /* * (c) 2003-2004 Glenn Maynard, Sean Burke * All rights reserved. diff --git a/src/arch/LoadingWindow/LoadingWindow_GtkModule.h b/src/arch/LoadingWindow/LoadingWindow_GtkModule.h index 77ad5a3233..350e1375d2 100644 --- a/src/arch/LoadingWindow/LoadingWindow_GtkModule.h +++ b/src/arch/LoadingWindow/LoadingWindow_GtkModule.h @@ -4,6 +4,8 @@ typedef const char *(*INIT)(int *argc, char ***argv); typedef void (*SHUTDOWN)(); typedef void (*SETTEXT)( const char *s ); +typedef void (*SETPROGRESS)( int progress, int totalWork ); +typedef void (*SETINDETERMINATE)( bool indeterminate ); #endif diff --git a/src/arch/LoadingWindow/LoadingWindow_MacOSX.h b/src/arch/LoadingWindow/LoadingWindow_MacOSX.h index 29636eb7c0..37694a9a93 100644 --- a/src/arch/LoadingWindow/LoadingWindow_MacOSX.h +++ b/src/arch/LoadingWindow/LoadingWindow_MacOSX.h @@ -9,6 +9,10 @@ public: LoadingWindow_MacOSX(); ~LoadingWindow_MacOSX(); void SetText( RString str ); + void SetSplash( const RString path ) {} + void SetProgress( const int progress ); + void SetTotalWork( const int totalWork ); + void SetIndeterminate( bool indeterminate ); }; #define USE_LOADING_WINDOW_MACOSX diff --git a/src/arch/LoadingWindow/LoadingWindow_MacOSX.mm b/src/arch/LoadingWindow/LoadingWindow_MacOSX.mm index 4f26434a41..356d3cc638 100644 --- a/src/arch/LoadingWindow/LoadingWindow_MacOSX.mm +++ b/src/arch/LoadingWindow/LoadingWindow_MacOSX.mm @@ -10,8 +10,12 @@ NSWindow *m_Window; NSTextView *m_Text; NSAutoreleasePool *m_Pool; + NSProgressIndicator *m_ProgressIndicator; } - (void) setupWindow:(NSImage *)image; +- (void) setProgress:(NSNumber *)progress; +- (void) setTotalWork:(NSNumber *)totalWork; +- (void) setIndeterminate:(NSNumber *)indeterminate; @end @implementation LoadingWindowHelper @@ -21,14 +25,25 @@ NSRect viewRect, windowRect; float height = 0.0f; + NSRect progressIndicatorRect; + progressIndicatorRect = NSMakeRect(0, 0, size.width, 0); + m_ProgressIndicator = [[NSProgressIndicator alloc] initWithFrame:progressIndicatorRect]; + [m_ProgressIndicator sizeToFit]; + [m_ProgressIndicator setIndeterminate:YES]; + [m_ProgressIndicator setMinValue:0]; + [m_ProgressIndicator setMaxValue:1]; + [m_ProgressIndicator setDoubleValue:0]; + progressIndicatorRect = [m_ProgressIndicator frame]; + float progressHeight = progressIndicatorRect.size.height; + NSFont *font = [NSFont systemFontOfSize:0.0f]; NSRect textRect; // Just give it a size until it is created. - textRect = NSMakeRect( 0, 0, size.width, size.height ); + textRect = NSMakeRect( 0, progressHeight, size.width, size.height ); m_Text = [[NSTextView alloc] initWithFrame:textRect]; [m_Text setFont:font]; height = [[m_Text layoutManager] defaultLineHeightForFont:font]*3 + 4; - textRect = NSMakeRect( 0, 0, size.width, height ); + textRect = NSMakeRect( 0, progressHeight, size.width, height ); [m_Text setFrame:textRect]; [m_Text setEditable:NO]; @@ -40,12 +55,12 @@ [m_Text setVerticallyResizable:NO]; [m_Text setString:@"Initializing Hardware..."]; - viewRect = NSMakeRect( 0, height, size.width, size.height ); + viewRect = NSMakeRect( 0, height + progressHeight, size.width, size.height ); NSImageView *iView = [[NSImageView alloc] initWithFrame:viewRect]; [iView setImage:image]; [iView setImageFrameStyle:NSImageFrameNone]; - windowRect = NSMakeRect( 0, 0, size.width, size.height + height ); + windowRect = NSMakeRect( 0, 0, size.width, size.height + height + progressHeight); m_Window = [[NSWindow alloc] initWithContentRect:windowRect styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered @@ -66,10 +81,27 @@ [view addSubview:iView]; [m_Text release]; [iView release]; + [view addSubview:m_ProgressIndicator]; // Display the window. [m_Window makeKeyAndOrderFront:nil]; } + +- (void) setProgress:(NSNumber *)progress +{ + [m_ProgressIndicator setDoubleValue:[progress doubleValue]]; +} + +- (void) setTotalWork:(NSNumber *)totalWork +{ + [m_ProgressIndicator setMaxValue:[totalWork doubleValue]]; +} + +- (void) setIndeterminate:(NSNumber *)indeterminate +{ + [m_ProgressIndicator setIndeterminate:([indeterminate doubleValue] > 0 ? YES : NO)]; +} + @end static LoadingWindowHelper *g_Helper = nil; @@ -124,6 +156,22 @@ void LoadingWindow_MacOSX::SetText( RString str ) [s release]; } +void LoadingWindow_MacOSX::SetProgress( const int progress ) +{ + [g_Helper performSelectorOnMainThread:@selector(setProgress:) withObject:[NSNumber numberWithDouble:(double)progress] waitUntilDone:NO]; +} + +void LoadingWindow_MacOSX::SetTotalWork( const int totalWork ) +{ + [g_Helper performSelectorOnMainThread:@selector(setTotalWork:) withObject:[NSNumber numberWithDouble:(double)totalWork] waitUntilDone:NO]; +} + +void LoadingWindow_MacOSX::SetIndeterminate( bool indeterminate ) +{ + double tmp = indeterminate ? 1 : 0; + [g_Helper performSelectorOnMainThread:@selector(setIndeterminate:) withObject:[NSNumber numberWithDouble:tmp] waitUntilDone:NO]; +} + /* * (c) 2003-2006, 2008 Steve Checkoway * All rights reserved. diff --git a/src/arch/LoadingWindow/LoadingWindow_Null.h b/src/arch/LoadingWindow/LoadingWindow_Null.h index 1ca5d89341..4b470f80b2 100644 --- a/src/arch/LoadingWindow/LoadingWindow_Null.h +++ b/src/arch/LoadingWindow/LoadingWindow_Null.h @@ -7,6 +7,7 @@ class LoadingWindow_Null: public LoadingWindow { public: void SetText( RString str ) { } + void SetSplash( RString str ) { } }; #define USE_LOADING_WINDOW_NULL diff --git a/src/arch/LoadingWindow/LoadingWindow_Win32.cpp b/src/arch/LoadingWindow/LoadingWindow_Win32.cpp index 4801e0bac7..8412965205 100644 --- a/src/arch/LoadingWindow/LoadingWindow_Win32.cpp +++ b/src/arch/LoadingWindow/LoadingWindow_Win32.cpp @@ -7,6 +7,7 @@ #include "archutils/win32/WindowIcon.h" #include "archutils/win32/ErrorStrings.h" #include +#include "CommCtrl.h" #include "RageSurface_Load.h" #include "RageSurface.h" #include "RageSurfaceUtils.h" @@ -17,7 +18,9 @@ #include "RageSurfaceUtils_Zoom.h" static HBITMAP g_hBitmap = NULL; -/* Load a RageSurface into a GDI surface. */ +#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + +// Load a RageSurface into a GDI surface. static HBITMAP LoadWin32Surface( RageSurface *&s ) { RageSurfaceUtils::ConvertSurface( s, s->w, s->h, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0 ); @@ -31,14 +34,14 @@ static HBITMAP LoadWin32Surface( RageSurface *&s ) HDC BitmapDC = CreateCompatibleDC( hScreen ); SelectObject( BitmapDC, bitmap ); - /* This is silly, but simple. We only do this once, on a small image. */ + // This is silly, but simple. We only do this once, on a small image. for( int y = 0; y < s->h; ++y ) { unsigned const char *line = ((unsigned char *) s->pixels) + (y * s->pitch); for( int x = 0; x < s->w; ++x ) { unsigned const char *data = line + (x*s->format->BytesPerPixel); - + SetPixelV( BitmapDC, x, y, RGB( data[3], data[2], data[1] ) ); } } @@ -58,7 +61,7 @@ static HBITMAP LoadWin32Surface( RString sFile, HWND hWnd ) if( pSurface == NULL ) return NULL; - /* Resize the splash image to fit the dialog. Stretch to fit horizontally, + /* Resize the splash image to fit the dialog. Stretch to fit horizontally, * maintaining aspect ratio. */ { RECT r; @@ -76,8 +79,17 @@ static HBITMAP LoadWin32Surface( RString sFile, HWND hWnd ) return ret; } -BOOL CALLBACK LoadingWindow_Win32::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +INT_PTR CALLBACK LoadingWindow_Win32::DlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { + LoadingWindow_Win32 *self; + + if(msg==WM_INITDIALOG) { + self=(LoadingWindow_Win32 *)lParam; + SetWindowLong(hWnd,DWL_USER,(LONG)self); + } else { + self=(LoadingWindow_Win32 *)GetWindowLong(hWnd,DWL_USER); + } + switch( msg ) { case WM_INITDIALOG: @@ -95,11 +107,25 @@ BOOL CALLBACK LoadingWindow_Win32::WndProc( HWND hWnd, UINT msg, WPARAM wParam, (WPARAM) IMAGE_BITMAP, (LPARAM) (HANDLE) g_hBitmap ); SetWindowTextA( hWnd, PRODUCT_ID ); + break; + case WM_CLOSE: + return FALSE; + case WM_DESTROY: DeleteObject( g_hBitmap ); g_hBitmap = NULL; + self->runMessageLoop=false; + self->hwnd=NULL; + return TRUE; + break; + + case WM_APP: + DestroyWindow(hWnd); + self->runMessageLoop=false; + ExitThread(0); + return TRUE; break; } @@ -108,7 +134,7 @@ BOOL CALLBACK LoadingWindow_Win32::WndProc( HWND hWnd, UINT msg, WPARAM wParam, void LoadingWindow_Win32::SetIcon( const RageSurface *pIcon ) { - if( m_hIcon != NULL ) + if( g_hBitmap != NULL ) DestroyIcon( m_hIcon ); m_hIcon = IconFromSurface( pIcon ); @@ -116,36 +142,76 @@ void LoadingWindow_Win32::SetIcon( const RageSurface *pIcon ) SetClassLong( hwnd, GCL_HICON, (LONG) m_hIcon ); } +void LoadingWindow_Win32::SetSplash( const RString sPath ) +{ + if( g_hBitmap != NULL ) + { + DeleteObject( g_hBitmap ); + g_hBitmap = NULL; + } + + g_hBitmap = LoadWin32Surface( sPath, hwnd ); + if( g_hBitmap != NULL ) + { + SendDlgItemMessage( + hwnd, IDC_SPLASH, + STM_SETIMAGE, + (WPARAM) IMAGE_BITMAP, + (LPARAM) (HANDLE) g_hBitmap + ); + } +} + LoadingWindow_Win32::LoadingWindow_Win32() { + INITCOMMONCONTROLSEX cceData; + cceData.dwSize=sizeof(INITCOMMONCONTROLSEX); + cceData.dwICC=ICC_PROGRESS_CLASS; + InitCommonControlsEx(&cceData); + m_hIcon = NULL; - hwnd = CreateDialog( handle.Get(), MAKEINTRESOURCE(IDD_LOADING_DIALOG), NULL, WndProc ); + + runMessageLoop=true; + + guiReadyEvent=CreateEvent(NULL,FALSE,FALSE,NULL); + + pumpThread=CreateThread(NULL, NULL, MessagePump, (void *)this, 0, &pumpThreadId); + + WaitForSingleObject(guiReadyEvent,INFINITE); + for( unsigned i = 0; i < 3; ++i ) text[i] = "ABC"; /* always set on first call */ SetText( "" ); - Paint(); } LoadingWindow_Win32::~LoadingWindow_Win32() { - if( hwnd ) - DestroyWindow( hwnd ); + SendMessage(hwnd,WM_APP,0,0); + //SendMessage(hwnd,WM_NULL,0,0); + WaitForSingleObject(pumpThread,INFINITE); + if(guiReadyEvent) + CloseHandle(guiReadyEvent); if( m_hIcon != NULL ) DestroyIcon( m_hIcon ); } -void LoadingWindow_Win32::Paint() +DWORD WINAPI LoadingWindow_Win32::MessagePump(LPVOID thisAsVoidPtr) { - SendMessage( hwnd, WM_PAINT, 0, 0 ); + LoadingWindow_Win32 *self=(LoadingWindow_Win32 *)thisAsVoidPtr; - /* Process all queued messages since the last paint. This allows the window to - * come back if it loses focus during load. */ + self->hwnd = CreateDialogParam( self->handle.Get(), MAKEINTRESOURCE(IDD_LOADING_DIALOG), NULL, DlgProc, (LPARAM)thisAsVoidPtr); + + SetEvent(self->guiReadyEvent); + + // Run the message loop in a separate thread to keep the gui responsive during the loading MSG msg; - while( PeekMessage( &msg, hwnd, 0, 0, PM_NOREMOVE ) ) + while(self->runMessageLoop && GetMessage(&msg, self->hwnd, 0, 0 ) ) { - GetMessage(&msg, hwnd, 0, 0 ); + if(IsDialogMessage(self->hwnd,&msg)) continue; DispatchMessage( &msg ); } + + return msg.wParam; } void LoadingWindow_Win32::SetText( RString sText ) @@ -168,6 +234,35 @@ void LoadingWindow_Win32::SetText( RString sText ) } } +void LoadingWindow_Win32::SetProgress(const int progress) +{ + m_progress=progress; + HWND hwndItem = ::GetDlgItem( hwnd, IDC_PROGRESS ); + ::SendMessage(hwndItem,PBM_SETPOS,progress,0); +} + +void LoadingWindow_Win32::SetTotalWork(const int totalWork) +{ + m_totalWork=totalWork; + HWND hwndItem = ::GetDlgItem( hwnd, IDC_PROGRESS ); + SendMessage(hwndItem,PBM_SETRANGE32,0,totalWork); +} + +void LoadingWindow_Win32::SetIndeterminate(bool indeterminate) { + m_indeterminate=indeterminate; + + HWND hwndItem = ::GetDlgItem( hwnd, IDC_PROGRESS ); + + if(indeterminate) { + SetWindowLong(hwndItem,GWL_STYLE, PBS_MARQUEE | GetWindowLong(hwndItem,GWL_STYLE)); + SendMessage(hwndItem,PBM_SETMARQUEE,1,0); + } else { + SendMessage(hwndItem,PBM_SETMARQUEE,0,0); + SetWindowLong(hwndItem,GWL_STYLE, (~PBS_MARQUEE) & GetWindowLong(hwndItem,GWL_STYLE)); + } + +} + /* * (c) 2001-2004 Chris Danford, Glenn Maynard * All rights reserved. diff --git a/src/arch/LoadingWindow/LoadingWindow_Win32.h b/src/arch/LoadingWindow/LoadingWindow_Win32.h index f490392acb..3780c85178 100644 --- a/src/arch/LoadingWindow/LoadingWindow_Win32.h +++ b/src/arch/LoadingWindow/LoadingWindow_Win32.h @@ -14,16 +14,26 @@ public: ~LoadingWindow_Win32(); void SetText( RString sText ); - void Paint(); void SetIcon( const RageSurface *pIcon ); + void SetSplash( const RString sPath ); + void SetProgress( const int progress ); + void SetTotalWork( const int totalWork ); + void SetIndeterminate( bool indeterminate ); private: AppInstance handle; HWND hwnd; RString text[3]; HICON m_hIcon; + HANDLE pumpThread; + DWORD pumpThreadId; + HANDLE guiReadyEvent; - static BOOL CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); + volatile bool runMessageLoop; + + static DWORD WINAPI MessagePump(LPVOID thisAsVoidPtr); + + static INT_PTR CALLBACK DlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); }; #define USE_LOADING_WINDOW_WIN32 diff --git a/src/arch/MovieTexture/MovieTexture.h b/src/arch/MovieTexture/MovieTexture.h index a97ea7e89f..b36b15fcae 100644 --- a/src/arch/MovieTexture/MovieTexture.h +++ b/src/arch/MovieTexture/MovieTexture.h @@ -5,6 +5,8 @@ #include "arch/RageDriver.h" #include +void ForceToAscii( RString &str ); + class RageMovieTexture : public RageTexture { public: diff --git a/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp b/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp index ed70a0acbf..ba00dbacb0 100644 --- a/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp +++ b/src/arch/MovieTexture/MovieTexture_FFMpeg.cpp @@ -28,6 +28,10 @@ namespace avcodec #endif }; +int URLRageFile_open( avcodec::URLContext *h, const char *filename, int flags ); +int URLRageFile_read( avcodec::URLContext *h, unsigned char *buf, int size ); +int URLRageFile_close( avcodec::URLContext *h ); + /* #if defined(_MSC_VER) #pragma comment(lib, "ffmpeg/lib/avcodec.lib") diff --git a/src/archutils/Unix/CrashHandlerChild.cpp b/src/archutils/Unix/CrashHandlerChild.cpp index 4255470779..518ad0c7f6 100644 --- a/src/archutils/Unix/CrashHandlerChild.cpp +++ b/src/archutils/Unix/CrashHandlerChild.cpp @@ -28,6 +28,8 @@ extern const char *const version_date; extern const char *const version_time; #endif +bool child_read( int fd, void *p, int size ); + const char *g_pCrashHandlerArgv0 = NULL; diff --git a/src/archutils/Win32/Crash.cpp b/src/archutils/Win32/Crash.cpp index 18f482adbb..8f51fd4d85 100644 --- a/src/archutils/Win32/Crash.cpp +++ b/src/archutils/Win32/Crash.cpp @@ -206,7 +206,7 @@ void RunChild() WriteToChild( hToStdin, &g_CrashInfo, sizeof(g_CrashInfo) ); // 2. Write info. - const char *p = RageLog::GetInfo(); + const TCHAR *p = RageLog::GetInfo(); int iSize = strlen( p ); WriteToChild( hToStdin, &iSize, sizeof(iSize) ); WriteToChild( hToStdin, p, iSize ); @@ -219,7 +219,7 @@ void RunChild() // 4. Write RecentLogs. int cnt = 0; - const char *ps[1024]; + const TCHAR *ps[1024]; while( cnt < 1024 && (ps[cnt] = RageLog::GetRecentLog( cnt )) != NULL ) ++cnt; @@ -232,7 +232,7 @@ void RunChild() } // 5. Write CHECKPOINTs. - static char buf[1024*32]; + static TCHAR buf[1024*32]; Checkpoints::GetLogs( buf, sizeof(buf), "$$" ); iSize = strlen( buf )+1; WriteToChild( hToStdin, &iSize, sizeof(iSize) ); @@ -255,7 +255,7 @@ void RunChild() if( !ReadFile( hFromStdout, &hMod, sizeof(hMod), &iActual, NULL) ) break; - char szName[MAX_PATH]; + TCHAR szName[MAX_PATH]; if( !CrashGetModuleBaseName(hMod, szName) ) strcpy( szName, "???" ); iSize = strlen( szName ); diff --git a/src/archutils/Win32/StepMania.ico b/src/archutils/Win32/StepMania.ico index 95519364bc..c9363aaa34 100644 Binary files a/src/archutils/Win32/StepMania.ico and b/src/archutils/Win32/StepMania.ico differ diff --git a/src/archutils/Win32/WindowsResources.h b/src/archutils/Win32/WindowsResources.h index 348f2ffdb0..be6ceda5c4 100644 --- a/src/archutils/Win32/WindowsResources.h +++ b/src/archutils/Win32/WindowsResources.h @@ -29,7 +29,6 @@ #define IDC_BUTTON_CLOSE 1011 #define IDC_VIEW_LOG 1012 #define IDC_STATIC_MESSAGE3 1013 -#define IDC_PROGRESS1 1014 #define IDC_PROGRESS 1014 #define IDC_HUSH 1016 #define IDC_MESSAGE 1017 diff --git a/src/archutils/Win32/WindowsResources.rc b/src/archutils/Win32/WindowsResources.rc index fea25b16fb..a9792bbfe8 100644 --- a/src/archutils/Win32/WindowsResources.rc +++ b/src/archutils/Win32/WindowsResources.rc @@ -43,14 +43,17 @@ BEGIN CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,34,332,1 END -IDD_LOADING_DIALOG DIALOG 0, 0, 312, 82 -STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE -FONT 8, "MS Sans Serif" +IDD_LOADING_DIALOG DIALOGEX 0, 0, 317, 94 +STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Stepmania" +FONT 8, "MS Sans Serif", 0, 0, 0x0 BEGIN - CTEXT "line1",IDC_STATIC_MESSAGE1,0,41,310,10,SS_NOPREFIX | SS_CENTERIMAGE - CTEXT "line2",IDC_STATIC_MESSAGE2,0,54,310,10,SS_NOPREFIX | SS_CENTERIMAGE - CTEXT "line3",IDC_STATIC_MESSAGE3,0,65,310,10,SS_NOPREFIX | SS_CENTERIMAGE + CTEXT "line1",IDC_STATIC_MESSAGE1,7,43,303,10,SS_NOPREFIX | SS_CENTERIMAGE + CTEXT "line2",IDC_STATIC_MESSAGE2,7,52,303,10,SS_NOPREFIX | SS_CENTERIMAGE + CTEXT "line3",IDC_STATIC_MESSAGE3,7,61,303,10,SS_NOPREFIX | SS_CENTERIMAGE CONTROL "",IDC_SPLASH,"Static",SS_BITMAP,0,0,310,25 + CONTROL "",IDC_PROGRESS,"msctls_progress32",0x0,7,73,303,14 END IDD_DISASM_CRASH DIALOGEX 0, 0, 332, 114 @@ -107,9 +110,9 @@ BEGIN IDD_LOADING_DIALOG, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 305 + RIGHTMARGIN, 310 TOPMARGIN, 7 - BOTTOMMARGIN, 75 + BOTTOMMARGIN, 87 END IDD_DISASM_CRASH, DIALOG @@ -180,8 +183,8 @@ IDI_ICON1 ICON "smzip.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 5,0,0,2 - PRODUCTVERSION 5,0,0,2 + FILEVERSION 5,0,0,3 + PRODUCTVERSION 5,0,0,3 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -198,12 +201,12 @@ BEGIN BEGIN VALUE "CompanyName", "StepMania Team\nhttp://www.stepmania.com/" VALUE "FileDescription", "StepMania" - VALUE "FileVersion", "5, 0, 0, 2" - VALUE "InternalName", "sm-ssc" + VALUE "FileVersion", "5, 0, 0, 3" + VALUE "InternalName", "sm-ssc v1.3.1" VALUE "LegalCopyright", "Copyright 2001-2011" VALUE "OriginalFilename", "StepMania.exe" VALUE "ProductName", "StepMania" - VALUE "ProductVersion", "5, 0, 0, 2" + VALUE "ProductVersion", "5, 0, 0, 3" END END BLOCK "VarFileInfo" diff --git a/src/archutils/Win32/arch_setup.h b/src/archutils/Win32/arch_setup.h index 983aa3868d..c403f26b4c 100644 --- a/src/archutils/Win32/arch_setup.h +++ b/src/archutils/Win32/arch_setup.h @@ -66,7 +66,7 @@ C4355: 'this' : used in base member initializer list /* Pull in NT-only definitions. Note that we support Win98 and WinME; you can * make NT calls, but be sure to fall back on 9x if they're not supported. */ -#define _WIN32_WINNT 0x0400 +#define _WIN32_WINNT 0x0501 #define _WIN32_IE 0x0400 // If this isn't defined to 0, VC fails to define things like stat and alloca. diff --git a/src/archutils/Win32/mapconv.exe b/src/archutils/Win32/mapconv.exe index 5d30c815fa..8b23d80115 100644 Binary files a/src/archutils/Win32/mapconv.exe and b/src/archutils/Win32/mapconv.exe differ diff --git a/src/archutils/Win32/verinc.exe b/src/archutils/Win32/verinc.exe index 545ffec5db..d17008756a 100644 Binary files a/src/archutils/Win32/verinc.exe and b/src/archutils/Win32/verinc.exe differ diff --git a/src/sm-ssc-net2003.sln b/src/sm5-net2003.sln similarity index 100% rename from src/sm-ssc-net2003.sln rename to src/sm5-net2003.sln diff --git a/src/sm-ssc-net2005.sln b/src/sm5-net2005.sln similarity index 100% rename from src/sm-ssc-net2005.sln rename to src/sm5-net2005.sln diff --git a/src/sm-ssc-net2008.sln b/src/sm5-net2008.sln similarity index 100% rename from src/sm-ssc-net2008.sln rename to src/sm5-net2008.sln diff --git a/src/sm-ssc-net2010.sln b/src/sm5-net2010.sln similarity index 100% rename from src/sm-ssc-net2010.sln rename to src/sm5-net2010.sln