diff --git a/.hgignore b/.hgignore index 61c47b6743..2b9724952e 100644 --- a/.hgignore +++ b/.hgignore @@ -32,9 +32,11 @@ src/libtomcrypt/build-* src/libtomcrypt/Release-* src/libtommath/build-* src/libtommath/Release-* +src/*.old ver.cpp lib*_link.a Data/UserPrefs +Data/GamePrefs/*.cfg PBProject/Hardware.plist Themes/pump Themes/optical-release @@ -42,6 +44,8 @@ src/version.bin src/verstub.cpp nsis_strings_temp.inc Data/SpeedMods.txt +Program/StepMania*.lib +crashinfo.txt syntax: regexp .*\#.*\#$ diff --git a/Announcers/instructions.txt b/Announcers/instructions.txt index eb1029fc97..272930e3b0 100644 --- a/Announcers/instructions.txt +++ b/Announcers/instructions.txt @@ -1 +1,50 @@ -Place announcer folders in this directory. \ No newline at end of file +Place announcer folders in this directory. + +[Announcer format] +sm-ssc's announcers look for certain names. These can either be a single sound, +or a folder containing many sounds (of which one is picked at random). + +[Announcer calls] +Grouped by Screen/Element that calls them, though only the sound/folder name for +each item is important. + +ScreenWithMenuElements +* (ScreenName) intro + +ScreenTitleMenu +* title menu game name + +ScreenSelect +* (ScreenName) IdleComment + +ScreenSelectMusic +* select music intro +* select music comment general +* select music comment hard +* select music comment new +* select music comment repeat +* select course comment general + +ScreenGameplay +* gameplay intro +* gameplay ready +* gameplay here we go normal +* gameplay here we go final +* gameplay here we go extra +* gameplay comment hot +* gameplay comment danger +* gameplay comment good +* gameplay comment oni +* gameplay (100-1000) combo +* gameplay combo stopped +* gameplay combo overflow +* gameplay battle trick level(1-3) +* gameplay battle damage level(1-3) +* gameplay extra +* gameplay cleared +* gameplay failed +* gameplay oni failed +* gameplay oni failed halfway + +MenuTimer +* hurry up \ No newline at end of file diff --git a/Docs/Changelog_SSCformat.txt b/Docs/Changelog_SSCformat.txt new file mode 100644 index 0000000000..ae2eb57362 --- /dev/null +++ b/Docs/Changelog_SSCformat.txt @@ -0,0 +1,17 @@ +.ssc Format Changelog +________________________________________________________________________________ +In case anyone else wishes to implement the .ssc format in their own simulator, +a changelog is provided here between each version. + +Notice: .ssc is not a finalized format at the moment. There are plans for a +change to JSON, but it is unsure if this will be done. + +Implement .ssc at your own risk. +________________________________________________________________________________ + +[v0.51] - AJ +* Move VERSION tag to the first line. +* Limit VERSION tag to two decimal places. + +[v0.5] - Wolfman2000 +* Initial MSD-based version. \ No newline at end of file diff --git a/Docs/Changelog_sm-ssc.txt b/Docs/Changelog_sm-ssc.txt index 4c66657a84..12e18fbbe5 100644 --- a/Docs/Changelog_sm-ssc.txt +++ b/Docs/Changelog_sm-ssc.txt @@ -1,7 +1,7 @@ sm-ssc Changelog ________________________________________________________________________________ The sm-ssc changelog mostly deals with source code-related changes, -as theme changes happen at a rapid pace. +as theme changes happen at a faster pace. Changes are grouped by date. Not all changes are documented, for various reasons. @@ -10,9 +10,232 @@ supported but exist anyways.) _____________________________________________________________________________ ================================================================================ -sm-ssc v1.2 | 201012xx +sm-ssc v1.2.2 | 201102?? -------------------------------------------------------------------------------- +20110213 +-------- +* Life Difficulty 4 is now as difficult as Life 6 was. [AJ] + Change name of the life difficulty options: + Old: 1, 2, 3, 4, 5, 6, 7 + New: 1.2, 1.0, 0.8, 0.6, 0.4, 0.33, 0.25 + +20110212 +-------- +* [PlayerOptions] Added metrics to allow changing how often random modifiers + activate in the proper setting. At this time, the mods to be activated have + NOT been changed. [Wolfman2000] +* [ArrowEffects] Allow the Boomerang, Expand, Tipsy, Drunk, Tornado, Beat, and + Mini modifiers to be customized by metrics. As usual, change at your own + risk here. [Wolfman2000] +* Started the process of doxygen'ing the code. Goodness knows we need more + documentation on here. For the most part, don't expect comments on + particular files, though this may change. [Wolfman2000] +* [TimingData] Fix getting a Stop or Delay at a row if one of each occupies + the same row. This may need some extra testing. [Wolfman2000] + +20110211 +-------- +* Introduced the .ssc file format for future features and expansion. All .sm + files will still work, and will still be generated when saved in the editor. + At this point, saving to the DWI format is being deprecated. [Wolfman2000] + +================================================================================ +sm-ssc v1.2.1 | 20110210 +-------------------------------------------------------------------------------- + +20110210 +-------- +* Had to go back on the ScreenNetSelectMusic controls commit. My apologies. [AJ] + +20110209 +-------- +* [ScreenOptionsMemoryCard] Added three strings: "(no label)", "size ???", and + "%dMB". [AJ] +* [ScreenSelectMusic] Added RouletteTimerSeconds metric. [AJ] +* [ArrowEffects] Added QuantizeArrowYPosition metric. [AJ] + +20110208 +-------- +* [ScreenNetSelectMusic] Added MusicWheelType metric. [AJ] + +20110201 +-------- +* [Song] Added IsDisplayBpmRandom Lua binding. [AJ] + +20110130 +-------- +* [ScreenSelectMaster] Only run cursor commands on players if they exist. [AJ] + +20110118 +-------- +* [ScreenEdit] Move editing Timing Data to their own mini menu. [Wolfman2000] +* Implement #TICKCOUNTS tag for better checkpoint behavior. + This officially deprecates the CheckpointsUseTimeSignatures metric for + the CheckpointsUseTickcounts metric. [Wolfman2000] +* [NoteField] Add metrics for more flexible TimingData labels. [Wolfman2000] + +20110116 +-------- +* [ScreenEdit] Allow editing TimeSignatureSegments one fractional half at + a time. [Wolfman2000] + +20110115 +-------- +* [ArrowEffects] Allow modifying modifier characteristics in the metrics. + At present, Blink, Boost, Brake, and Wave can have modifications. + [Wolfman2000] +* [Player] Allow Combo Stopped message to be flexible via metrics. The + default is 50, as it was before. [Wolfman2000] +* [Player] Allow the default attack times for both random and mine attacks + to be changed. [Wolfman2000] +* [NoteField] Allow for adjustable fade fail time (for AJ). [Wolfman2000] +* [MenuTimer] Allow the hurry up transition to be adjusted. [Wolfman2000] +* [MusicWheel] Added RouletteColor, RandomColor, and PortalColor metrics. [freem] +* Fix a bug with VisualDelaySeconds where choosing -1 would lead to it being +1. [freem] + +20110112 +-------- +* [PlayerStageStats] Change score to an unsigned long from a signed int. [FSX] +* Noteskin changes. [Daisuke Master] +* [SpecialScoring] MIGS scoring, improved SN and SN2 scoring. [FSX] +* [RageFile] Added ReadBytes() Lua binding. [FSX] +* [NetworkSyncManager] Added CloseConnection() Lua binding. [freem] +* [ScreenTextEntry] Added Load(TextEntrySettings) Lua binding. [freem] + TextEntrySettings is implemented similar to the Attributes in BitmapText. +local teSettings = { + SendOnPop = "", -- ScreenMessage to send on pop (optional, "SM_None" if omitted) + Question = "", -- The question to display + InitialAnswer = "", -- Initial answer text + MaxInputLength = 0, -- Maximum amount of characters + Password = false, -- Mask character input (optional) + Validate = nil, -- Validation function; function(answer, errorOut), must return boolean, string. + OnOK = nil, -- On OK; function(answer) + OnCancel = nil, -- On Cancel; function() + ValidateAppend = nil, -- Validate appending a character; function(answer,append), must return boolean + FormatAnswerForDisplay = nil, -- Format answer for display; function(answer), must return string +}; + +20110111 +-------- +* [ScreenManager] Added ReloadOverlayScreens() Lua binding. [freem] + +20110110 +-------- +* [Character] Added GetDisplayName Lua binding. [freem] +* Make sure that DELAYS come first if STOPS share the same beat. [Wolfman2000] + +20110109 +-------- +* Add the semicolon and apostrophe keys as alternatives to the Page Up and Page + Down keys in the editor, mainly for laptop users. [Wolfman2000] +* Removed Song sample length limitations. [freem] +* Removed hard-coded values from the Step Editor. Now TimeSignatures are used + in place of these former constants. [Wolfman2000] +* [RoomWheel] Various metrics changes: [freem] + * Removed TextWidth/DescWidth metrics. + * "Desc" is now "Description". (DescX -> DescriptionX) + * Removed hardcoded commands (shadowlength,0;maxwidth,[max width metric];halign,0). + +================================================================================ +sm-ssc v1.2 | 20110107 +-------------------------------------------------------------------------------- + +20110107 +-------- +* Fix PrefsManager init list not being in order [vyhd] +* Add hack to ThemeManager to make GetThemeName() work intuitively for Scripts dirs [vyhd] +* [SongManager] Check the root Songs/ folder for extra stage course files. [freem] +* Make routine mode use ScreenGameplayShared instead of ScreenGameplay. [freem] +* Make pump-routine spacing the same as pump-double spacing. [FSX] + +20110106 +-------- +* [SpecialScoring] Fix some minor issues [FSX] +* New pump routine noteskins [cesarmades] + +20110102 +-------- +* Fix routine mode saving in the editor. [Wolfman2000] + +20110101 +-------- +* [Screen] Added HandleBackButton metric; useful for custom menus that need to + use the Back button for more user-friendly canceling. [freem] + +20101230 +-------- +* [StepsDisplay] Make the StepsType react to SetMessage as well. [freem] + +20101229 +-------- +* [ScreenHowToPlay] Replaced LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND macro + calls with ActorUtil::LoadAllCommandsAndSetXY(). Fixes an odd bug I ran into + during the porting of DDR 5th Mix. [freem] +* [ScreenInstallOverlay] Added bare DownloadFinished message. [freem] + +20101228 +-------- +* [ScreenHowToPlay] Have Character ignore the Miss steps instead of trying to + hit them. [freem] + +20101227 +-------- +* [ScreenHowToPlay] Added CharacterName metric, which will force the Character + that shows up. [freem] + +20101226 +-------- +* [ScreenEdit] Added GetEditState Lua binding. [freem] +* [ScreenNetSelectMusic] StepsDisplay changed to load from StepsDisplayNet. [freem] +* [RoomWheelItem] Added OverPart (just like in MusicWheelItem). [freem] +* [SongManager] Added GetSongRank(Song) Lua binding. [freem] +* Changed Steps picking logic in ScreenGameplaySyncMachine; now playable Steps + are chosen, instead of whatever NoteData happens to be first. + Also added pump-single data to ScreenGameplaySyncMachine music.sm. [freem] +* [Banner, FadingBanner] Various changes: [freem] + * Removed (now unused) All Music banner. + * Fixed swapped ScrollRandom and ScrollRoulette metrics. +* [Banner] Added GetScrolling(), GetPercentScrolling() and + SetScrolling(bool,float) Lua bindings. +* [FadingBanner] Added GetLatestIndex() Lua binding. [freem] + +20101225 +-------- +* Fixed Life difficulty scale being 0. [Daisuke Master] + +20101223 +-------- +* Added Banners for most SortOrders. (Group is excluded (song group banners + still work), as is Recent (which has no sections).) [freem] + +20101222 +-------- +* Added Shift+Ctrl+F2 shortcut for reloading overlay screens (and metrics) [freem] + +20101221 +-------- +* SM5SVN r28586: Only unload fonts if not used by the next screen. [shakesoda] +* [ScreenSelectMaster] Fix DoSwitchAnyways to actually work again. +* [ScreenInstallOverlay] Installs won't jump to SelMusic on Gameplay or System + Menus (e.g. Edit Mode) anymore on download completion. [freem] + +20101220 +-------- +* [Actor] Add bezier. (_fallback/02 Actor.lua) [FSX] +* [MessageManager] Added MenuStartP1 and MenuStartP2 messages. [freem] +* [ScreenSelectMaster] Broadcast MenuStartP# messages; allow themers to handle + the MenuStartP# messageitems. [freem] + +20101219 +-------- +* [WheelNotifyIcon] add BlinkPlayersBest metric. [freem] +* [GameCommand] Add GetScreen, GetSteps, GetCourse, GetTrail, and GetCharacter + Lua bindings. [freem] +* [StreamDisplay] Remove UseThreePartMethod. +* [Style] Add ColumnsPerPlayer and NeedsZoomOutWith2Players bindings. [freem] +* [Profile] Add GetLastUsedHighScoreName Lua binding. [freem] + 20101218 -------- * [MusicWheelItem] Add OverPart. [freem] @@ -1753,4 +1976,4 @@ ActorScroller changes: -------- * Project begins. * Remove ScreenEz2SelectPlayer, which only the Xbox project still referenced. -_____________________________________________________________________________ \ No newline at end of file +_____________________________________________________________________________ diff --git a/Docs/Devdocs/SMO_protocol-aj.txt b/Docs/Devdocs/SMO_protocol-aj.txt index 4874f6db68..b84a4669ad 100644 --- a/Docs/Devdocs/SMO_protocol-aj.txt +++ b/Docs/Devdocs/SMO_protocol-aj.txt @@ -118,7 +118,7 @@ ________________________________________________________________________________ 0x05 (005) Game Status Update The payload changes between protocols, and it will likely have to change again -to acconut for some more StepIDs. +to account for some more StepIDs. Payload: [Size] [Description] @@ -155,7 +155,7 @@ Payload: 32767 would be DEAD on the note If the user is hitting late, the # will be higher. It if the user is exactly 0.25 seconds off, the number will be - different by 500. With this pattern 0.5 gives a difference of 1000. + different by 500. With this pattern 0.5 seconds gives a difference of 1000. Expected response: None ________________________________________________________________________________ diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index 4c5b58b1fd..85cd618dd9 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -10,6 +10,7 @@ + @@ -38,11 +39,22 @@ + + + + + + + + + + + @@ -55,7 +67,9 @@ + + @@ -72,6 +86,7 @@ + @@ -79,8 +94,10 @@ + + @@ -110,13 +127,17 @@ + + + + @@ -131,6 +152,8 @@ + + @@ -149,11 +172,13 @@ + + @@ -163,6 +188,7 @@ + @@ -170,6 +196,7 @@ + @@ -180,6 +207,7 @@ + @@ -286,6 +314,7 @@ + @@ -493,6 +522,8 @@ + + @@ -500,8 +531,10 @@ + + @@ -529,6 +562,7 @@ + @@ -600,6 +634,7 @@ + @@ -608,18 +643,20 @@ - - - + + + + + @@ -638,6 +675,7 @@ + @@ -710,6 +748,7 @@ + @@ -776,10 +815,8 @@ - - @@ -792,9 +829,6 @@ - - - @@ -869,6 +903,7 @@ + @@ -896,6 +931,7 @@ + @@ -923,6 +959,7 @@ + @@ -939,8 +976,6 @@ - - @@ -959,6 +994,7 @@ + @@ -990,11 +1026,15 @@ + + + + @@ -1013,6 +1053,7 @@ + @@ -1060,6 +1101,9 @@ + + + @@ -1102,6 +1146,7 @@ + @@ -1132,6 +1177,7 @@ + @@ -1150,6 +1196,7 @@ + @@ -1190,6 +1237,7 @@ + @@ -1210,9 +1258,11 @@ + + @@ -1251,14 +1301,12 @@ - - + - @@ -1426,6 +1474,12 @@ + + + + + + @@ -1806,10 +1860,11 @@ - - - - + + + + + @@ -1878,16 +1933,16 @@ - + - + - + - + @@ -1896,9 +1951,9 @@ - + - sm-ssc v1.0 - 2010-09-10 + sm-ssc v1.2.1 + 2011-02-10 diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index 4bc3a19a5f..173a5495d0 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -20,7 +20,6 @@ -> CoinMode --> - @@ -48,6 +47,9 @@ 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. + A generic interface to Lua's garbage collector. Performs different functions based on the value of opt. @@ -510,12 +512,18 @@ Sets the Actor's base Z rotation to rot. + + Sets the Actor's base zoom to zoom. + Sets the Actor's base X zoom to zoom. Sets the Actor's base Y zoom to zoom. + + Sets the Actor's base Z zoom to zoom. + Sets the Actor to use the specified blend mode. @@ -657,7 +665,7 @@ Returns the Actor's current effect delta. - + Returns the Actor's current effect magnitude as three floats (not one; I hate Lua.xsd). @@ -711,6 +719,9 @@ Set the fractional horizontal alignment of the Actor according to fAlign which should be a float in the range 0..1. An alignment of 0 is left aligned while an alignment of 1 is right aligned. See for the common case. + + Hides the Actor for the specified amount of time. + [Deprecated] Compatibility alias for the hidden command, which was removed in sm-ssc. Use instead. @@ -732,6 +743,12 @@ Sets the Actor's name to sName. + + Stops the Actor's movement. (Usually used for Sprites or Models.) + + + Starts the Actor's movement. (Usually used for Sprites or Models.) + Plays a command named sCommandName. @@ -862,6 +879,9 @@ Zooms the Actor to zoom scale on the Z axis. + + [02 Actor.lua] + [03 ProductivityHelpers.lua] Centers an Actor on the X axis. (equivalent to x,SCREEN_CENTER_X) @@ -1101,6 +1121,12 @@ + + Returns true if the Banner is currently scrolling. + + + + Loads the background from an UnlockEntry. @@ -1122,6 +1148,9 @@ Loads a Banner from a specified Song Group. + + Loads a Banner from a specified SortOrder. + Loads an icon from the specified Character. @@ -1131,6 +1160,9 @@ See . + + + @@ -1223,6 +1255,9 @@ Returns the path of the dancing animation of this character. + + Returns the character's display name. + Returns the path to the character's icon. @@ -1413,6 +1448,12 @@ + + Returns any Character associated with this item (or nil if there isn't one). + + + Returns any Course that may have been set. + Returns the index of this item. @@ -1425,18 +1466,27 @@ Returns any Profile ID that may have been set. + + Returns any screen that may have been set as a string. + Returns any Song that may have been set. Returns the name of any song group that may have been set. + + Returns any Steps that may have been set. + Returns any Style that may have been set. Returns the display text. + + Returns any Trail that may have been set. + Returns any Url that may have been set. @@ -1479,6 +1529,9 @@ Returns the environment table. See . + + Returns the current for the specified . + Returns the current . @@ -1710,6 +1763,9 @@ Saves the bookkeeping and machine profile data. + + Sets the current for the specified . + Sets the current Course to course. @@ -1860,6 +1916,9 @@ Returns the number of lives remaining. + + + @@ -2109,6 +2168,9 @@ Returns true if the player was disqualified from ranking. + + Sets the Player's score to iScore. + @@ -2250,6 +2312,9 @@ Returns true if the specified code sUnlockEntryID is unlocked. + + Sets the current for the Profile. + Sets the goal to iCals calories. @@ -2353,6 +2418,9 @@ Returns a string containing the entire contents of the file. + + Returns length bytes from the RageFile's current position. + Seeks to a position in the file and returns the new position. @@ -2414,6 +2482,9 @@ + + Loads the metrics for this RollingNumbers from sGroupName. + Sets the target number to f. @@ -2432,6 +2503,11 @@ Posts a message with the text sScreenMsg to the Screen. + + + Returns the current . + + Returns the current StageStats. @@ -2475,6 +2551,9 @@ Gets the screen at the top of the screen stack. + + Reloads any loaded overlay screens. + Returns true if screen class s exists. @@ -2581,6 +2660,14 @@ Sets the profile index of Player pn to iProfileIndex. + + + See the Changelog for details on TextEntrySetting's format. + + + Sets up a ScreenTextEntry's values. + + Tells the screen to go to the previous screen. @@ -2698,6 +2785,9 @@ Returns true if the song's DisplayBPM is constant. + + Returns true if the song's DisplayBPM is random. + Returns true if the song's DisplayBPM is secret. @@ -2737,7 +2827,7 @@ Returns an array of all the installed songs. - Returns the course color of course c. + Returns the course color of Course c. Returns the extra stage info (Song, Steps) for the specified Style s. (If bExtra2 is true, it will use the second Extra Stage data instead of the first. Again, Lua.xsd sucks) @@ -2773,7 +2863,7 @@ Returns a random song. - Returns the song color of song s. + Returns the song color of Song s. Returns a Song given a set of Steps st. @@ -2785,6 +2875,9 @@ Returns a table containing all of the song group names. + + Returns the rank (popularity) of Song s. + Returns a table containing all of the songs in group sGroupName. @@ -2872,6 +2965,9 @@ [01 alias.lua] Alias for CropTo. + + Sets all the state delays to fRate. Useful for Sprites that need to change by BPM (e.g. Tran from DDR 5th Mix, the cube from DS EuroMix 2). + @@ -2937,6 +3033,9 @@ Returns the Steps description. + + Returns the author that made that particular Steps pattern. + Returns the Steps difficulty. @@ -2983,6 +3082,9 @@ + + Returns the number of total tracks this Style contains (e.g. 4 for dance-versus, but 8 for dance-double). + Returns the name of the Style. @@ -2992,6 +3094,9 @@ Returns the StyleType for this Style. + + Returns true if the Style needs to be zoomed out with two players. + @@ -3093,7 +3198,7 @@ Returns the Trail's difficulty. - + Returns a table of TrailEntry items. @@ -3120,7 +3225,7 @@ Returns the Steps used in this TrailEntry. - (why'd I think this was a good idea when we have CourseEntry:IsSecret?) + (why'd I think this was a good idea when we have ?) diff --git a/Docs/SMLanProtocol.txt b/Docs/SMLanProtocol.txt deleted file mode 100644 index 6a206cbade..0000000000 --- a/Docs/SMLanProtocol.txt +++ /dev/null @@ -1,455 +0,0 @@ - -PRELIMINARY - - - - - - - - 05/03/2004 -Protocol version 4 - But 0x04 will be its version for inter-protocol purposes. - -This protocol is only intended to replace current protocol. Because current protocol -not expanable - -SMLAN PROTCOL TCP/8765 - -Protcol is entirelly packaged in EzSockets Data Packets (use send and receive packet) - -This will prevent any out-of-sync errors with future or past versions. - -The protocol is impervious to fragmented, or bonded TCP packets. - -Basic Representation: - -Octet 0123 4 5 - +----+-+---//--+ - |ssss|C|Payload| - +----+-+---//--+ - -ssss - size of packet, handled by ezsockets (if you're using C++) -C - Command. -Payload - variable size based on command - -The payload may contain more data than expected, i.e. new protocol version. - - -In the following protocol, the term size means the size of the chunk of data. -If the "size" is "NT" then that means it's a null-terminating string. - "MSN" most significant 4 bits (byte/16) - "LSN" least significant 4 bits (byte%16) - - -Note: Primary player is 0x0, secondary player is 0x1 - -CLIENT to SERVER protocol: - -000: No Operation - Desc: This command will cause server to respond with a no op response. - Payload: None - Response: Server 001 - -001: No Operation Response - Desc: This command is used to respond to a no operation. - Payload: None - Response: None - -002: Hello - Desc: This is the first packet from a client to server, stating below - information (NOTE: Names are no longer sent in this packet) - Payload: - Size Description: - 1 Client protocol version - NT Name of build of StepMania - Response: Server 002 - - - -003: Game Start Request - Desc: This command is called once after most loading is done, and - again immediately before the sound starts. - Payload: - Size Description - MSN Primary player difficulty (feet) (0 for no player) - LSN Secondary player difficulty (feet) (0 for no player) - MSN Primary player difficulty (0=Beginner, 1=easy, etc.) - LSN Second player difficulty (0=Beginner, 1=easy, etc.) - MSN Start Position (0 is pre-sync, 1 is for sync) - LSN Reserved - NT Song Title - NT Song Subtitle - NT Song Artist - NT Course Title (If none exists; make it just a null) - NT Song Options (in string-format) - NT Primary Player's options (Null if non-existant) - NT Secondary Player's Options (Null if non-existant) - - Response: Server 003 - - -004: Game Over Notice - Desc: This command is sent when end of game is encounterd - Payload: None. - Response: None. - -005: Game Status update - Desc: Updates game info for each step - Payload: - Size Description - MSN Player # -Protocol <= 2 - LSN StepID - 1: Miss - 2: W5 - 3: W4 - 4: W3 - 5: W2 - 6: W1 - 7: LetGo - 8: Held -Protocol >= 3 - LSN StepID - 1: HitMine - 2: AvoidMine - 3: Miss - 4: W5 - 5: W4 - 6: W3 - 7: W2 - 8: W1 - 9: LetGo - 10: Held - - MSN Projected Grade (StepMania enum int) - LSN Reserved - 4 Net-order long containing score. - 2 Net-order int containing combo. - 2 Net-order int containing health. - 2 Net-order # containing offset - 32767 would be DEAD on the note - If the user is hitting late, the # will be higher - It if the user is exactly 0.25 seconds off, the - number will be different by 500, if 0.5, it will be - different by 1000. - Response: None. - -006: Style Update (PLEASE NOTE THIS HAS NOTHING TO DO WITH SERVER COMMAND 6) - Desc: This is sent when a style is chosen. - Size: - 1 # of enabled players (1 means 1, 2 means 2) - 1 Player # (0 means 1st, 1 means 2nd) - NT Player Name for # - (Additional player's and #'s) (enabled players ONLY) - - Response: None - -007: Chat message - Desc: The user typed a message for general chat. - Size: - NT Message - -008: Request Start Game and Tell server existance/non existance of song. - Desc: The user selected a song on a Net-enabled selection - Size: - 1 Usage of message - 0: (in response to server 8) User has specified song - 1: (in response to server 8) User does NOT have specified song - 2: User requested a start game on given song - NT Song Title (As gotten by GetTranslitMainTitle) - NT Song Artist (As Gotten by GetTranslitArtist) - NT Song Subtitle (As gotten by GetTranslitSubTitle) - -009: //Reserved - -010: User entered/exited Network Music Selection Screen - Size: - 1 - 0: exited ScreenNetSelectMusic - 1: entered ScreenNetSelectMusic - 2: **Not Sent** - 3: entered options screen - 4: exited the evaluation screen - 5: entered evaluation screen - 6: exited ScreenNetRoom - 7: entered ScreenNetRoom - -011: User has changed player options - Size: - NT Player 0's options - NT Player 1's options - - -012: SMOnline Packet. //SPECIAL CASE!!! - NOTE: The smonline packet is not defined here. - The SMLan packet 12 is a wrapper for the SMOnline packet. - This is so that we can have "protection" of sorts when - it comes to the coding of SMOnline, so we don't have to - use the lower level commands when dealing with SMOnline. - Size: - 1 SMOnline command //This used to say 2, but it looks like 1 in all cases - SMOnline data - - -013: Reserved - -SERVER to CLIENT protocol: (begins at 128) - -NOTE: Server responses always add 128, thus a server response for no operation - is 128, not 000 - -000(128):No Operation - Desc: This command will cause server to respond with a no op response. - Payload: None - Response: Server 001 - -001(129):No Operation Response - Desc: This command is used to respond to a no operation. - Payload: None - Response: None - -002(130):Server Hello Response - Desc: This introduces the server. - Payload: - Size Description - 1 Server protocol version //NOTE: if protocol version is 128+, then this - server is an SMOnline server - NT Server Name - 4 Random key ( at the moment only used for an alternate login method ) - -003(131):Allow Start - Desc: This will cause the client to start the game. - Payload: None - Response: None - -004(132):Game over stats - Desc: this packet is send in response to the game over packet - it contains information regarding how well each player did. - Payload: - 1 # of players sent in this packet (active players) - The way this works is to send every player's info for a given - field. Like every player's score will be sent first, then every - player's grade. - 1 First player's player ID - - 4 Score - - 1 Grade - - 1 Difficulty (0=beginner, 1=light, etc.) - - - #this next chunk of step types is actually reversed - 2 miss - - 2 boo - - 2 good (All players) - 2 great (All players) - 2 perfect (All players) - 2 marvelous (All players) - - 2 ok (All players) - 2 max_combo (All players) - NT Player's options - - - -005:(133)Scoreboard update - Desc: This will update the client's scoreboard. - Payload: - Size - 1 Which section - 0: Names - 1: Combos - 2: Projected Grades - 1 # of players to display - - If Names, then: - 1 Player in first place's index - 1 Player in second place's index - ... - 1 Last player's index - If Combos, then: - 2 First player's combo - 2 Second Player's combo - ... - 2 Last player's combo - If Project grades - 1 Player 1's grade (in the same format used when reporting projected grades) - 1 Player 2's grade - ... - 1 Last player's projected grade - - -006:(134)System Message (PLEASE NOTE THIS HAS NOTHING TO DO WITH CLIENT COMMAND 6) - Desc: Send system message to user - Payload: - Size Description - NT Message - -007:(135)Chat Message - Desc: Add a chat message to the chat window on some StepMania screens. - Payload: - Size Description - NT Message - -008:(136)Tell client to start song/ask if client has song - Desc: The user selected a song on a Net-enabled selection - Size: - 1 Usage of message - 0: See if client has song - 1: See if client has song, if so, scroll to song - 2: See if client has song, if so, scroll to song, and play that song - 3: Blindly start song - NT Song Title (As gotten by GetTranslitMainTitle) - NT Song Artist (As Gotten by GetTranslitArtist) - NT Song Subtitle (As gotten by GetTranslitSubTitle) - -009:(137)Update user list - Desc: This sends all the users currently connected - Size: - 1 Max # of players - 1 # of players in this packet - 1 Player 0's status - NT Player 0's name (if there is no player here... make it a null ("")) - 1 Player 1's status - NT Player 1's name - ... - 1 Last player's status - NT Last player's name - Status: - 0 Inative (no info on this user yet) - 1 Active (you know who it is) - 2 In Selection Screen - 3 In Options - 4 In Evaluation - -010:(138)Force change to Networking select music screen. - Size: - NT Set Specified gametype - NT Set Specified style - -011:(139)Reserved - - -012:(140)SMOnline Packet. //SPECIAL CASE!!! - NOTE: The smonline packet is not defined here. - The SMLan packet 12 is a wrapper for the SMOnline packet. - This is so that we can have "protection" of sorts when - it comes to the coding of SMOnline, so we don't have to - use the lower level commands when dealing with SMOnline. - Size: - 1 SMOnline command - SMOnline data - - -013:(141)Formatted information packet - Desc: Send formatted information regarding the server back to the player. - NOTE: The purpose of this function is alternatively to be a broadcast - packet. (You can expect it via UDP broadcast) - Size: - NT Server Name - 2 Port the server is listening on - 2 Number of players connected - -014:(142)Attack Client - Size: - 1 Player Number - 4 Time to Last (in MS) - NT Text describing modifiers. - ----------------------------------------------------------------- -Client SMOnline packets: -000: Send Login Information - Size: - 1 Player Number - 1 Encryption text - 0: MD5 hash - 1: MD5 ( MD5 hash + salt ) (salt is plain text, base 10 string ) - NT Username - NT Password - - Note: The client is not permitted to use method (1) for authentication - if the salt it received from the server is 0 - -001: User asks to enter room - Size: - 1 Enter/Exit? - 0: User wishes to exit room - 1: User wishes to enter room - NT Room Name (Used when entering rooms) - NT Password (Empty if password not used) - -002: Create a new Room - Size: - 1 Room Type - 0: Normal room (has sub rooms) - 1: Game room (no sub rooms) - NT Room Title - NT Room Description - NT Room Password (blank if no password) - -003: Requests Room Info - Size: - NT Room Name - - -Server SMOnline packets: -000: Login Response - 1 Approval Status - 0: Approved - 1: Approval Failed - NT Login response (plain text) - -001: Room Update (Changing rooms) - Size: - 1 Type of update - 0: Change Room Title - 1: Update List of other rooms (or games) - - If Room Title Update: - NT Room Title - NT Room Description - 1 Type of room: - 0: Chat room - 1: Game room - 1 Allows creation of sub room. - 0: Does not allow creation of subrooms - 1: Allows creation of subrooms - - If Room List Update: - 1 Number of rooms - NT Room1 Title - NT Room1 Description - NT Room2 Title - NT Room2 Description - ... - NT RoomN Title - NT RoomN Description - - Room Status appended for reverse compatibility - 1 Room1 Status - 0: Normal Room - 1: Unused - 2: Room in game - 3: First stage of song selection has been done - 4: Second stage of song selection has been done - 1 Room2 Status - ... - 1 RoomN Status - - Room Flags appended for reverse compatibility - 1 Room1 Flags - bit 0: Passworded if true - 1 Room2 Status - ... - 1 RoomN Status - -002: Request general information from server. - 1 Format for stats - 0: Normal unformatted stats - -003: Room Info - Size: - NT Last Song Title - NT Last Song Subtitle - NT Last Song Artist - 1 Num Players - 1 Max Players - NT Player1 Name - ... - NT PlayerN Name diff --git a/Docs/SimfileFormats/new format draft.txt b/Docs/SimfileFormats/new format draft.txt new file mode 100644 index 0000000000..b19f658190 --- /dev/null +++ b/Docs/SimfileFormats/new format draft.txt @@ -0,0 +1,47 @@ +$INFORMATION:maintitle:subtitle:artist:genre:credit; +$TRANSLITS:main:sub:artist; +$GRAPHICS:banner:background:disc:cdtitle; +$MUSIC:music-file:base-track:intro-file:lyrics; +// should be used if a intro file is not defined +$SAMPLEPREVIEW:start:length; +$DISPLAYBPM:[from:to]|[one]|[show yes/no]; +$BGCHANGES: + beat=file:p,r,o,p,s +; +$FGCHANGES:; +$KEYSOUNDS:; + +// cache tags here +$CACHE: + firstbeat: + lastbeat: + songfilename: + hasmusic: + hasbanner +; + +// note data +#NOTEDATA# +$META: + STEPSTYPE=stepstype: + DIFFICULTY=difficulty: + DESCRIPTION=description: + METER=meter: + RADARVALUES=r,a,d,a,r,v,a,l,u,e,s; +$TIMINGDATA: + BPM=bpms: + SPEED=speed: + STOPS=stops: + DELAYS=delays: + TIMESIGNATURES=timesigs; +$NOTES: +00000 +00000 +00000 +00000 +, +00000 +00000 +00000 +00000 +; \ No newline at end of file diff --git a/Docs/SimfileFormats/ssc_msd5.txt b/Docs/SimfileFormats/ssc_msd5.txt new file mode 100644 index 0000000000..ddea11957e --- /dev/null +++ b/Docs/SimfileFormats/ssc_msd5.txt @@ -0,0 +1,59 @@ +// sm-ssc step chart/msd5 hacky file format doc. +// based off of .sm, which was based off of DWI's modified MSD format. +#TITLE:; +#SUBTITLE:; +#ARTIST:; +#TITLETRANSLIT:; +#SUBTITLETRANSLIT:; +#ARTISTTRANSLIT:; +#GENRE:; +#CREDIT:; +#BANNER:; +#BACKGROUND:; +#LYRICSPATH:; +#CDTITLE:; +#MUSIC:; +#INSTRUMENTTRACK:; +#MUSICLENGTH:; +#OFFSET:; +#STOPS:; +#DELAYS:; +#BPMS:; +#TIMESIGNATURES:; +#LASTBEATHINT:; +#SAMPLESTART:; +#SAMPLELENGTH:; +#DISPLAYBPM:[xxx][xxx:xxx]|[*]; +#SELECTABLE:; +#BGCHANGES:; +#FGCHANGES:; +#KEYSOUNDS:; +#ATTACKS:; + +// stored in cache +#FIRSTBEAT:; // calculated +#LASTBEAT:; // calculated +#SONGFILENAME:; +#MUSICBYTES:; // ignored by loader +#HASMUSIC:; +#HASBANNER:; + +// begin +#NOTEDATA# // marks a new note data section +// information from #NOTES moved here +#STEPSTYPE:; +#DESCRIPTION:; +#DIFFICULTY:; +#METER:; +#RADARVALUES:; +#CREDIT:; + +// steps-based timingdata +#STOPS:; +#DELAYS:; +#BPMS:; +#TIMESIGNATURES:; +#LASTBEATHINT:; + +// actual step data +#NOTES:; \ No newline at end of file diff --git a/Docs/TextEntry.txt b/Docs/TextEntry.txt deleted file mode 100644 index c5e975d583..0000000000 --- a/Docs/TextEntry.txt +++ /dev/null @@ -1,14 +0,0 @@ -Code that uses ScreenTextEntry::TextEntry() -------------------------------------------- -RoomWheel.cpp -ScreenEdit.cpp -ScreenEditMenu.cpp -ScreenNetRoom.cpp -ScreenNetworkOptions.cpp -ScreenOptionsCourseOverview.cpp -ScreenOptionsManageCourses.cpp -ScreenOptionsManageEditSteps.cpp -ScreenOptionsManageProfiles.cpp -ScreenOptionsReviewWorkout.cpp -ScreenPackages.cpp -ScreenTestFonts.cpp \ No newline at end of file diff --git a/Docs/Themerdocs/Noteskin elements Reference.txt b/Docs/Themerdocs/Noteskin elements Reference.txt index c08563ba78..32fcde44f0 100644 --- a/Docs/Themerdocs/Noteskin elements Reference.txt +++ b/Docs/Themerdocs/Noteskin elements Reference.txt @@ -1,4 +1,4 @@ -Noteskin elements Reference: +[Noteskin Elements Reference] { Taps } button Tap Note button Tap Mine @@ -35,6 +35,8 @@ button Roll Body Inactive button Roll Bottomcap Inactive button Roll Tail Inactive +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { button } --dance-- Left @@ -51,6 +53,15 @@ Center DownLeft DownRight +--kb7-- +Key1 +Key2 +Key3 +Key4 +Key5 +Key6 +Key7 + --ez2-- FootUpLeft FootUpRight @@ -68,7 +79,14 @@ UpRight Right --ds3ddx-- - +HandLeft +FootDownLeft +FootUpLeft +HandUp +HandDown +FootUpRight +FootDownRight +HandRight --beat-- Key1 @@ -82,11 +100,32 @@ Scratch up Scratch down --maniax-- - +HandUpLeft +HandUpRight +HandLrLeft +HandLrRight --techno-- +Left +Right +Up +Down +UpLeft +UpRight +Center +DownLeft +DownRight --popn-- +Left White +Left Yellow +Left Green +Left Blue +Red +Right Blue +Right Green +Right Yellow +Right White --guitar-- (not enabled yet) Fret1 @@ -95,4 +134,12 @@ Fret3 Fret4 Fret5 ---lights-- (rofl) \ No newline at end of file +--lights-- (rofl) +MarqueeUpLeft +MarqueeUpRight +MarqueeLrLeft +MarqueeLrRight +ButtonsLeft +ButtonsRight +BassLeft +BassRight \ No newline at end of file diff --git a/Docs/Themerdocs/ScreenTextEntry.txt b/Docs/Themerdocs/ScreenTextEntry.txt new file mode 100644 index 0000000000..4e3b4d2bf7 --- /dev/null +++ b/Docs/Themerdocs/ScreenTextEntry.txt @@ -0,0 +1,17 @@ +-- how to connect to a server with the new ScreenTextEntry Lua bindings +-- (this is the base code; I'll come up with a full tutorial later.) +SCREENMAN:AddNewScreenToTop("ScreenTextEntry"); +local serverSettings = { + Question = "Connect to server:", + MaxInputLength = 255, + OnOK = function(answer) + if IsNetConnected() then + -- close connection before connecting to new server + CloseConnection() + end + + -- connect to server + ConnectToServer(answer) + end, +}; +SCREENMAN:GetTopScreen():Load(serverSettings); \ No newline at end of file diff --git a/Docs/Themerdocs/ThemePrefs.txt b/Docs/Themerdocs/ThemePrefs.txt new file mode 100644 index 0000000000..d0307503ba --- /dev/null +++ b/Docs/Themerdocs/ThemePrefs.txt @@ -0,0 +1,88 @@ +ThemePrefs, v0.7 +---------------- + +ThemePrefs is a system for handling theme-specific preferences in a standard, +efficient, and predictable way. All you do, basically, is declare a table of +preferences and options and use GetThemePref(name) to get your preference +values as needed. This system will handle all disk I/O as well. + +Additionally, it can work in combination with ThemePrefsRows to generate +OptionsRows for all preferences, saving you (most of) the trouble with +integrating it into your theme. More on that later. + +The prefs are written, using IniFile, into Save/ThemePrefs.ini, written under +the section corresponding to your theme name (if ThemeInfo exists, it will +use the Name field listed there; otherwise, it will use the folder name). + +---------------------- +Section 1: Declaration +---------------------- + +To declare preferences for your theme to use, make a table with named +tables in it; its name is used for the preference, and the tables hold +the options for that preference. All you need to know for now is that +Default is required; for more options, check ThemePrefsRows. + +After the table is declared, pass it to the function ThemePrefs.InitAll(). +(If you're planning not to use any OptionsRows at all, you can just use +ThemePrefs.Init() to save some processing time, but seriously give the +ThemePrefsRows system a look before you disregard it.) + +[code] +local Prefs = +{ + BoolPref = { Default = false }, + IntPref = { Default = 3 }, +} + +ThemePrefs.InitAll( Prefs ) +[/code] + +If your theme is "default", this will generate a ThemePrefs.ini like so: + +[default] +BoolPref=false +IntPref=3 + +---------------- +Section 2: Usage +---------------- + +You can access the value with ThemePrefs.Get(name) or GetThemePref(name): +both calls work identically. The return type will be based on whatever you set +it to, but the subsystem will always try number, then bool, then string, in +that order. Use true and false for bools, not 1 and 0. + +For example, if you wanted to branch something in the metrics based on +the value of BoolPref (which is a boolean), you could use the following: + +NextScreen=GetThemePref('BoolPref') and "ScreenTrue" or "ScreenFalse" + +If you want to set a preference value for some reason, you can use either +ThemePrefs.Set(name, value) or SetThemePref(name, value), but the point of +this API is to simplify and standardize prefs handling, so you really should +not need it. (Use ThemePrefsRows instead.) + +----------------------- +Section 3: Localization +----------------------- + +ThemePrefs has two strings that can be localized, to be placed under +[ThemePrefs] in the appropriate language INI. + +IniFileMissing - displayed when IniFile.lua is not found, which means + ThemePrefs cannot be loaded from or written to disk + +UnknownPreference - displayed when an attempt is made to read or write + a preference that does not exist in the system. Uses %s for the + name of the unknown preference. + +--------------------- +Section 4: Disclaimer +--------------------- + +Though this is working fine so far, it is still experimental! If you run +into problems, or have suggestions, comments, questions, etc., please talk +to "vyhd" in #sm-ssc on irc.badnik.net, as it's his code to maintain; he +hates subjecting other people to his code (and occasionally vice versa), +but will gladly address concerns that come up. diff --git a/Docs/Themerdocs/ThemePrefsRows.txt b/Docs/Themerdocs/ThemePrefsRows.txt new file mode 100644 index 0000000000..42a9d6bf14 --- /dev/null +++ b/Docs/Themerdocs/ThemePrefsRows.txt @@ -0,0 +1,145 @@ +ThemePrefsRows, v0.5 +-------------------- + +ThemePrefsRows is an optional system that works with ThemePrefs to generate +Lua-based OptionsRows for every preference used in the system. All you do is +declare a table of preferences and pass it to ThemePrefs.InitAll(), which will +also initialize ThemePrefs. Note that you do need to add an entry for each +preference in [OptionTitles] and [OptionExplanations] to give the row its name +and describe what it does; I hope to find a (clean) way to do it from Lua. + +---------------------- +Section 1: Declaration +---------------------- + +Declaring preferences is the same basic concept as ThemePrefs; see that doc +for the basics. So I'll go into the stuff that's important to this API. + +As mentioned in ThemePrefs, the table contains options. The possible options +and their types are outlaid here. (The pref's type is defined by Default.) + +Default: whatever the value is set to by default. For sanity's sake, you + should have this in your Choices table. + +Choices (table): an indexed array containing all the possible OptionsRow + choices. If you're using a Values table, the array values should be + strings. If not, you can use any type that can cast to a string. + +Values (table): indexed array of the pref's type containing the value used when + the Choices entry with the same index is chosen in the row. If that + confused you, don't worry: it'll make more sense in the example. + This is optional, if your pref type can cast to strings. + +Params (table): optional modifications to the OptionsRow. I'll cover this in + more detail in a later section. You probably won't need it. + +To make this clearer, have an example of a valid prefs table: + +[code] +local prefs = +{ + BoolPref = + { + Default = false, + Choices = { "On", "Off" }, + Values = { true, false }, + }, + + IntPref = + { + Default = 3, + Choices = { 1, 2, 3, 4, 5 }, + Params = { SelectType = "ShowOneInRow" } + } +} + +ThemePrefs.InitAll( prefs ) +[/code] + +So when "On" is selected, BoolPref will be set to true, and selecting "Off" +will set it false. Simple enough, yeah? This will scale to any type you like. +Enumerations, strings, whatever. + +----------------- +Section 2: Params +----------------- + +We did promise a more in-depth look at Params, so here it is. + +The following arguments and values are currently accepted for Params: + +LayoutType (string): "ShowAllInRow" (default), "ShowOneInRow". + +ExportOnChange (bool): currently disabled in the source, but available to + set in case it's enabled later. If true, the Save function (which + handles actually setting the preference) is called whenever a value + is changed rather than when the screen changes. + +EnabledForPlayers (function): has 'self' as an argument, returns a table of + PlayerNumbers who are allowed to select stuff. Not important yet. + +ReloadRowMessages (table): contains an indexed array of strings. Whenever + any of the messages in this table are broadcast, the Load function + (which loads the list of possible options and sets the selected + value/s) is called again. + +LoadSelections (function): takes self, list, pn, overrides the default + function. This is advanced usage, so you should probably know + what you're doing to use it. Probably unnecessary. + +SaveSelections (function): takes self, list, pn, and overrides the default + function. This is advanced as well, for the same reasons. Fortunately, + you probably won't need it. + +---------------- +Section 3: Usage +---------------- + +To get the OptionsRow for the preference you want, use ThemePrefRow(name) +or ThemePrefsRows.GetRow(name); they're the same function. You'd use this +as, for example in the metrics: + +Line1="lua,ThemePrefRow('BoolPref')" + +Unfortunately, you do need to do some more work with the Language INIs too. +For each declared preference, you need an entry under [OptionTitles] for its +title and an entry under [OptionExplanations] for its description. The key for +both is the name of the preference. With the above example, that'd be e.g. + +[OptionTitles] +(...) +BoolPref=BoolPref +IntPref=IntPref + +[OptionExplanations] +(...) +BoolPref=Toggles a simple boolean preference between true and false. +IntPref=Sets an integer value between 1 and 5. + +----------------------- +Section 4: Localization +----------------------- + +ThemePrefsRows has three themable strings: + +NoDefaultInValues - if the default value isn't actually in choices or values, + this is displayed. Takes %s for the affected preference's name. + +TypeMismatch - if the default type and a value type mismatch, this is shown. + Takes %s, %d, and %s for the default's type, the index of the + mismatching value, and the value's type respectively. + +ChoicesSizeMismatch - if the Choices and Values arrays have different + lengths, this is displayed. Takes %d and %d for the size of + Choices and Values, respectively. + +--------------------- +Section 5: Disclaimer +--------------------- + +This isn't as tested as I'd like. For this version, it remains experimental. +Quite experimental. If you run into problems, please let me know so I can +fix them. + +Please direct all questions, comments, complaints, bug reports, etc. to "vyhd" +in #sm-ssc on irc.badnik.net or whatever other form of communication you like. diff --git a/Docs/Windows7.txt b/Docs/Windows7.txt deleted file mode 100644 index eefe4e833d..0000000000 --- a/Docs/Windows7.txt +++ /dev/null @@ -1 +0,0 @@ -If you are using Windows Vista or Windows 7, please do not install StepMania SSC into the Program Files directory. \ No newline at end of file diff --git a/Docs/WindowsNotes.txt b/Docs/WindowsNotes.txt new file mode 100644 index 0000000000..df305c466d --- /dev/null +++ b/Docs/WindowsNotes.txt @@ -0,0 +1,17 @@ +[IMPORTANT INSTALL NOTE] +If you are using Windows Vista or Windows 7, please do not install StepMania SSC into the Program Files directory. + +[Using Google Chrome?] +If you are using Google Chrome as your primary web browser, you will have to perform some extra steps to get stepmania:// URI handling to work: + +Find yout user data +Windows XP: C:\Documents and Settings\\Local Settings\Application Data\Google\Chrome\User Data +Windows Vista/7: C:\Users\\AppData\Local\Google\Chrome\User Data + +Add your protocol to the 'Local State' file under the 'protocol_handler' section, as such: +"protocol_handler": { + "excluded_schemes": { + ... + "stepmania": false, + ... + } \ No newline at end of file diff --git a/Docs/credits.txt b/Docs/credits.txt index 34f00fff58..2daa02afa0 100644 --- a/Docs/credits.txt +++ b/Docs/credits.txt @@ -59,7 +59,7 @@ Kaox * Pump/default noteskin cesarmades - * Pump/cmd noteskin + * Pump/cmd-* noteskins David Santamaría Rogado (howl) * Various patches (see Changelog_sm-ssc.txt for more details and links) @@ -106,6 +106,9 @@ juanelote * [SongManager] GetSongGroupByIndex function * [MusicWheel] JumpToNextGroup/JumpToPrevGroup logic modifications +NitroX72 + * Pump/frame noteskin + ==the beta testers== [SSC Beta Testing Team] KeithD diff --git a/NoteSkins/pump/cmd-routine-p1/Center Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/Center Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..dfe7648d1e Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/Center Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/Center Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/Center Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..a228086721 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/Center Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/Center Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/Center Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..1ee360e9f5 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/Center Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/Center Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/Center Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..e11f43ef27 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/Center Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/DownLeft Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/DownLeft Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..dec008a0ba Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/DownLeft Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/DownLeft Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/DownLeft Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..c285faa23a Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/DownLeft Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/DownLeft Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/DownLeft Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..4d21e18cd9 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/DownLeft Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/DownLeft Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/DownLeft Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..7e32671f0e Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/DownLeft Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/DownRight Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/DownRight Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..37d6bb73f8 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/DownRight Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/DownRight Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/DownRight Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..9b4f33fc8f Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/DownRight Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/DownRight Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/DownRight Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..4dba753d2e Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/DownRight Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/DownRight Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/DownRight Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..622cdfc51c Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/DownRight Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/UpLeft Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/UpLeft Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..6722c02ed8 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/UpLeft Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/UpLeft Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/UpLeft Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..8df1561175 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/UpLeft Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/UpLeft Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/UpLeft Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..5ce7ffd928 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/UpLeft Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/UpLeft Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/UpLeft Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..c4aaba680b Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/UpLeft Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/UpRight Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/UpRight Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..651deb994e Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/UpRight Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/UpRight Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p1/UpRight Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..20f1d4ba10 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/UpRight Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/UpRight Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/UpRight Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..45b98f36b3 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/UpRight Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p1/UpRight Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p1/UpRight Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..4e95142637 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p1/UpRight Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/Center Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/Center Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..29c39ffcc0 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/Center Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/Center Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/Center Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..bd5245a932 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/Center Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/Center Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/Center Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..8527a7a1d8 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/Center Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/Center Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/Center Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..3e38c9c708 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/Center Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/DownLeft Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/DownLeft Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..aedf15180e Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/DownLeft Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/DownLeft Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/DownLeft Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..9de812c29e Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/DownLeft Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/DownLeft Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/DownLeft Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..9008fe19fc Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/DownLeft Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/DownLeft Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/DownLeft Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..f0a506b795 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/DownLeft Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/DownRight Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/DownRight Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..f46d37be93 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/DownRight Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/DownRight Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/DownRight Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..bcf475dc3a Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/DownRight Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/DownRight Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/DownRight Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..6b2b525264 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/DownRight Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/DownRight Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/DownRight Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..51e2890ffd Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/DownRight Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/NoteSkin.lua b/NoteSkins/pump/cmd-routine-p2/NoteSkin.lua new file mode 100644 index 0000000000..1bbeae06d8 --- /dev/null +++ b/NoteSkins/pump/cmd-routine-p2/NoteSkin.lua @@ -0,0 +1,11 @@ +local Noteskin = ... or {} + +Noteskin.PartsToRotate = { + --["elemenu"] = true|false; + ["Roll Head Active"] = false; + ["Roll Head Inactive"] = false; + -- + ["Tap Note"] = false; +} + +return Noteskin \ No newline at end of file diff --git a/NoteSkins/pump/cmd-routine-p2/UpLeft Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/UpLeft Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..268e2a4f88 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/UpLeft Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/UpLeft Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/UpLeft Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..d2dc4c2710 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/UpLeft Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/UpLeft Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/UpLeft Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..0bf008cab0 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/UpLeft Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/UpLeft Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/UpLeft Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..3c7875dcfa Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/UpLeft Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/UpRight Hold Body active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/UpRight Hold Body active (doubleres) 6x1.png new file mode 100644 index 0000000000..d612eec8f8 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/UpRight Hold Body active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/UpRight Hold BottomCap active (doubleres) 6x1.png b/NoteSkins/pump/cmd-routine-p2/UpRight Hold BottomCap active (doubleres) 6x1.png new file mode 100644 index 0000000000..71cb3a3606 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/UpRight Hold BottomCap active (doubleres) 6x1.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/UpRight Roll Head Active (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/UpRight Roll Head Active (doubleres) 3x2.png new file mode 100644 index 0000000000..4202922718 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/UpRight Roll Head Active (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/UpRight Tap Note (doubleres) 3x2.png b/NoteSkins/pump/cmd-routine-p2/UpRight Tap Note (doubleres) 3x2.png new file mode 100644 index 0000000000..1f367ca797 Binary files /dev/null and b/NoteSkins/pump/cmd-routine-p2/UpRight Tap Note (doubleres) 3x2.png differ diff --git a/NoteSkins/pump/cmd-routine-p2/metrics.ini b/NoteSkins/pump/cmd-routine-p2/metrics.ini new file mode 100644 index 0000000000..9450d5ed0c --- /dev/null +++ b/NoteSkins/pump/cmd-routine-p2/metrics.ini @@ -0,0 +1,2 @@ +[Global] +FallbackNoteSkin=cmd \ No newline at end of file diff --git a/NoteSkins/pump/default/DownLeft Outline Receptor.redir b/NoteSkins/pump/default/DownLeft Outline Receptor.redir new file mode 100644 index 0000000000..04b2ead777 --- /dev/null +++ b/NoteSkins/pump/default/DownLeft Outline Receptor.redir @@ -0,0 +1 @@ +_blank \ No newline at end of file diff --git a/NoteSkins/pump/default/DownRight Ready Receptor.lua b/NoteSkins/pump/default/DownRight Ready Receptor.lua index d61466c6b6..ca0aa5d395 100644 --- a/NoteSkins/pump/default/DownRight Ready Receptor.lua +++ b/NoteSkins/pump/default/DownRight Ready Receptor.lua @@ -4,5 +4,4 @@ return NOTESKIN:LoadActor("DownLeft", "Ready Receptor")..{ { Frame = 1 }; { Frame = 2 }; }; - --InitCommand=cmd(rotationy,180); }; \ No newline at end of file diff --git a/NoteSkins/pump/default/DownRight Tap Note.lua b/NoteSkins/pump/default/DownRight Tap Note.lua index 9832f98f23..197b1b9d37 100644 --- a/NoteSkins/pump/default/DownRight Tap Note.lua +++ b/NoteSkins/pump/default/DownRight Tap Note.lua @@ -1,3 +1 @@ -return NOTESKIN:LoadActor("DownLeft","Tap Note")..{ - --InitCommand=cmd(rotationy,180); -}; \ No newline at end of file +return NOTESKIN:LoadActor("DownLeft","Tap Note")..{}; \ No newline at end of file diff --git a/NoteSkins/pump/default/NoteSkin.lua b/NoteSkins/pump/default/NoteSkin.lua index d084ed4c17..a7abc397ba 100644 --- a/NoteSkins/pump/default/NoteSkin.lua +++ b/NoteSkins/pump/default/NoteSkin.lua @@ -36,13 +36,14 @@ Noteskin.ElementRedirs = { ["Roll Bottomcap Inactive"] = "Hold Bottomcap Active"; ["Roll Tail Inactive"] = "Hold Tail Active"; } -Noteskin.ButtonRedirs = { +-- explicit, n/w +--[[Noteskin.ButtonRedirs = { Center = "Center"; UpLeft = "UpLeft"; UpRight = "UpRight"; DownLeft = "DownLeft"; DownRight = "DownRight"; -} +}]] Noteskin.BaseRotX = { Center = 0; UpLeft = 0; @@ -57,7 +58,23 @@ Noteskin.BaseRotY = { DownLeft = 0; DownRight = 180; } +Noteskin.BaseRotZ = { + Center = 0; + UpLeft = 0; + UpRight = 0; + DownLeft = 0; + DownRight = 0; +} +--[[-------------------------------------------------------------------------- +DONT EDIT THE FUNCTION, DON'T COPY AND PASTE THE WHOLE NOTESKIN.LUA +JUST MAKE A NEW ONE AND GRAB WHATEVER IS USEFUL FOR YOUR NOTESKIN. +phew~ + +See cmd-routine-p* noteskin.lua for a simple and clear example on +how to do this properly, notice how the rest of the noteskins just +have graphics and at least a metrics.ini with few things +--]]-------------------------------------------------------------------------- local function func() local sButton = Var "Button" local sElement = Var "Element" @@ -76,7 +93,6 @@ local function func() ElementToLoad = sElement end - --update: ahora receptor también if sElement == "Explosion" or sElement == "Tap Lift" or sElement == "Tap Mine" @@ -84,11 +100,10 @@ local function func() then sButton = "UpLeft" end - local path = NOTESKIN:GetPath(Noteskin.ButtonRedirs[sButton],ElementToLoad) - --Graficos separados para holds y rolls - --if string.find(sElement,"Hold") or string.find(sElement,"Roll") then - if ( string.find(sElement,"Hold") or string.find(sElement,"Roll") ) and not ( string.find(sElement,"Head") or string.find(sElement,"Tail") ) then - --if ( string.find(sElement,"Hold") or string.find(sElement,"Roll") ) and ( string.find(sElement,"Body") ) then + local path = NOTESKIN:GetPath(sButton,ElementToLoad) + if ( string.find(sElement,"Hold") or string.find(sElement,"Roll") ) + and not ( string.find(sElement,"Head") or string.find(sElement,"Tail") ) + then path = NOTESKIN:GetPath(sButton,ElementToLoad) end @@ -100,6 +115,7 @@ local function func() if bRotate then t.BaseRotationX=Noteskin.BaseRotX[sButton] t.BaseRotationY=Noteskin.BaseRotY[sButton] + t.BaseRotationZ=Noteskin.BaseRotZ[sButton] end return t diff --git a/NoteSkins/pump/default/UpLeft Explosion.lua b/NoteSkins/pump/default/UpLeft Explosion.lua index 13dda698b2..f3d6852e9d 100644 --- a/NoteSkins/pump/default/UpLeft Explosion.lua +++ b/NoteSkins/pump/default/UpLeft Explosion.lua @@ -38,23 +38,7 @@ return Def.ActorFrame { }; --thing... Def.Quad { - InitCommand=cmd(zoomto,60,4800;diffusealpha,0); + InitCommand=cmd(zoomto,50,5000;diffusealpha,0); HitMineCommand=cmd(finishtweening;diffusealpha,1;linear,0.3;diffusealpha,0); }; - --[[Def.Quad { - InitCommand=function(self) - local style = GAMESTATE:GetCurrentStyle()GetStyleType() - local maxzoom = SCREEN_WIDTH - if style == 'StyleType_OnePlayerTwoSides' then - maxzoom = 320 - end - - self:diffuse(1,1,1,0); - self:zoomx(maxzoom); - self:zoomy(SCREEN_HEIGHT*5) - end; - --cmd(diffuse,1,1,1,0;zoomy,SCREEN_HEIGHT*100); - HitMineCommand=function(self) MESSAGEMAN:BroadCast("AMineWasHit"); end; - --cmd(finishtweening;diffusealpha,1;linear,0.3;diffusealpha,0); - };]] } \ No newline at end of file diff --git a/NoteSkins/pump/default/UpLeft Receptor.lua b/NoteSkins/pump/default/UpLeft Receptor.lua index a5d1e7e0f7..d6845a1d7d 100644 --- a/NoteSkins/pump/default/UpLeft Receptor.lua +++ b/NoteSkins/pump/default/UpLeft Receptor.lua @@ -19,20 +19,26 @@ return Def.ActorFrame { -- LAYERS -- NOTESKIN:LoadActor("Center", "Outline Receptor")..{ - Name="Outline"; - Condition=Var "Button" == "Center"; + Name="Outline Full"; + Condition=Var "Button" == "Center" and GAMESTATE:GetCurrentStyle():GetStepsType() ~= 'StepsType_Pump_Halfdouble'; --InitCommand=cmd(x,96); }; + NOTESKIN:LoadActor("DownLeft", "Outline Receptor")..{ + Name="Outline Half"; + Condition=Var "Button" == "DownLeft" and GAMESTATE:GetCurrentStyle():GetStepsType() == 'StepsType_Pump_Halfdouble'; + --InitCommand=cmd(x,96); + }; + NOTESKIN:LoadActor(Var "Button", "Ready Receptor")..{ Name="Base"; Frames = { { Frame = 0 } }; - --PressCommand=cmd(finishtweening;glow,1,1,1,1;linear,0.1;glow,1,1,1,0); + PressCommand=cmd(finishtweening;linear,0.05;zoom,0.9;linear,0.1;zoom,1); }; NOTESKIN:LoadActor(Var "Button", "Ready Receptor")..{ Name="Glow"; Frames = { { Frame = 1 } }; InitCommand=cmd(blend,'BlendMode_Add'); - --PressCommand=cmd(finishtweening;linear,0.05;zoom,0.9;linear,0.1;zoom,1); + PressCommand=cmd(finishtweening;linear,0.05;zoom,0.9;linear,0.1;zoom,1); }; --[[ NOTESKIN:LoadActor(Var "Button", "Ready Receptor")..{ diff --git a/NoteSkins/pump/default/UpRight Ready Receptor.lua b/NoteSkins/pump/default/UpRight Ready Receptor.lua index cae1506df9..367c0bada7 100644 --- a/NoteSkins/pump/default/UpRight Ready Receptor.lua +++ b/NoteSkins/pump/default/UpRight Ready Receptor.lua @@ -4,5 +4,4 @@ return NOTESKIN:LoadActor("UpLeft", "Ready Receptor")..{ { Frame = 1 }; { Frame = 2 }; }; - --InitCommand=cmd(rotationy,180); }; \ No newline at end of file diff --git a/NoteSkins/pump/default/UpRight Tap Note.lua b/NoteSkins/pump/default/UpRight Tap Note.lua index 7b882b751d..d9129448d8 100644 --- a/NoteSkins/pump/default/UpRight Tap Note.lua +++ b/NoteSkins/pump/default/UpRight Tap Note.lua @@ -1,4 +1 @@ -return NOTESKIN:LoadActor("UpLeft","Tap Note")..{ - --InitCommand=cmd(rotationy,180); - --BaseRotationY=180; -}; \ No newline at end of file +return NOTESKIN:LoadActor("UpLeft","Tap Note")..{}; \ No newline at end of file diff --git a/NoteSkins/pump/frame5p/Center Hold Body active (doubleres).png b/NoteSkins/pump/frame5p/Center Hold Body active (doubleres).png new file mode 100644 index 0000000000..049deee19d Binary files /dev/null and b/NoteSkins/pump/frame5p/Center Hold Body active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/Center Hold BottomCap active (doubleres).png b/NoteSkins/pump/frame5p/Center Hold BottomCap active (doubleres).png new file mode 100644 index 0000000000..1bbca50d4e Binary files /dev/null and b/NoteSkins/pump/frame5p/Center Hold BottomCap active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/Center Outline Receptor.redir b/NoteSkins/pump/frame5p/Center Outline Receptor.redir new file mode 100644 index 0000000000..04b2ead777 --- /dev/null +++ b/NoteSkins/pump/frame5p/Center Outline Receptor.redir @@ -0,0 +1 @@ +_blank \ No newline at end of file diff --git a/NoteSkins/pump/frame5p/Center Ready Receptor 3x1 (doubleres).png b/NoteSkins/pump/frame5p/Center Ready Receptor 3x1 (doubleres).png new file mode 100644 index 0000000000..5dccc11527 Binary files /dev/null and b/NoteSkins/pump/frame5p/Center Ready Receptor 3x1 (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/Center Tap Note 8x1 (doubleres).png b/NoteSkins/pump/frame5p/Center Tap Note 8x1 (doubleres).png new file mode 100644 index 0000000000..83dfd0f3dc Binary files /dev/null and b/NoteSkins/pump/frame5p/Center Tap Note 8x1 (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/DownLeft Hold Body active (doubleres).png b/NoteSkins/pump/frame5p/DownLeft Hold Body active (doubleres).png new file mode 100644 index 0000000000..447e0cadfe Binary files /dev/null and b/NoteSkins/pump/frame5p/DownLeft Hold Body active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/DownLeft Hold BottomCap active (doubleres).png b/NoteSkins/pump/frame5p/DownLeft Hold BottomCap active (doubleres).png new file mode 100644 index 0000000000..d20477629c Binary files /dev/null and b/NoteSkins/pump/frame5p/DownLeft Hold BottomCap active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/DownLeft Hold TopCap Active (doubleres).png b/NoteSkins/pump/frame5p/DownLeft Hold TopCap Active (doubleres).png new file mode 100644 index 0000000000..46249a36e0 Binary files /dev/null and b/NoteSkins/pump/frame5p/DownLeft Hold TopCap Active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/DownLeft Ready Receptor 3x1 (doubleres).png b/NoteSkins/pump/frame5p/DownLeft Ready Receptor 3x1 (doubleres).png new file mode 100644 index 0000000000..28aba4f386 Binary files /dev/null and b/NoteSkins/pump/frame5p/DownLeft Ready Receptor 3x1 (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/DownLeft Tap Note 8x1 (doubleres).png b/NoteSkins/pump/frame5p/DownLeft Tap Note 8x1 (doubleres).png new file mode 100644 index 0000000000..7b7946bcc7 Binary files /dev/null and b/NoteSkins/pump/frame5p/DownLeft Tap Note 8x1 (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/DownRight Hold Body active (doubleres).png b/NoteSkins/pump/frame5p/DownRight Hold Body active (doubleres).png new file mode 100644 index 0000000000..0308ffdba2 Binary files /dev/null and b/NoteSkins/pump/frame5p/DownRight Hold Body active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/DownRight Hold BottomCap active (doubleres).png b/NoteSkins/pump/frame5p/DownRight Hold BottomCap active (doubleres).png new file mode 100644 index 0000000000..49fa97be0b Binary files /dev/null and b/NoteSkins/pump/frame5p/DownRight Hold BottomCap active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/DownRight Hold TopCap Active(doubleres).png b/NoteSkins/pump/frame5p/DownRight Hold TopCap Active(doubleres).png new file mode 100644 index 0000000000..20d5423ddb Binary files /dev/null and b/NoteSkins/pump/frame5p/DownRight Hold TopCap Active(doubleres).png differ diff --git a/NoteSkins/pump/frame5p/UpLeft Hold Body active (doubleres).png b/NoteSkins/pump/frame5p/UpLeft Hold Body active (doubleres).png new file mode 100644 index 0000000000..282db1ab02 Binary files /dev/null and b/NoteSkins/pump/frame5p/UpLeft Hold Body active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/UpLeft Hold BottomCap active (doubleres).png b/NoteSkins/pump/frame5p/UpLeft Hold BottomCap active (doubleres).png new file mode 100644 index 0000000000..9c0413bc7c Binary files /dev/null and b/NoteSkins/pump/frame5p/UpLeft Hold BottomCap active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/UpLeft Hold TopCap (doubleres).png b/NoteSkins/pump/frame5p/UpLeft Hold TopCap (doubleres).png new file mode 100644 index 0000000000..ee95f2fa89 Binary files /dev/null and b/NoteSkins/pump/frame5p/UpLeft Hold TopCap (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/UpLeft Ready Receptor 3x1 (doubleres).png b/NoteSkins/pump/frame5p/UpLeft Ready Receptor 3x1 (doubleres).png new file mode 100644 index 0000000000..75592a2c51 Binary files /dev/null and b/NoteSkins/pump/frame5p/UpLeft Ready Receptor 3x1 (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/UpLeft Tap Note 8x1 (doubleres).png b/NoteSkins/pump/frame5p/UpLeft Tap Note 8x1 (doubleres).png new file mode 100644 index 0000000000..ddd5bce858 Binary files /dev/null and b/NoteSkins/pump/frame5p/UpLeft Tap Note 8x1 (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/UpRight Hold Body active (doubleres).png b/NoteSkins/pump/frame5p/UpRight Hold Body active (doubleres).png new file mode 100644 index 0000000000..282db1ab02 Binary files /dev/null and b/NoteSkins/pump/frame5p/UpRight Hold Body active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/UpRight Hold BottomCap active (doubleres).png b/NoteSkins/pump/frame5p/UpRight Hold BottomCap active (doubleres).png new file mode 100644 index 0000000000..840a485ec1 Binary files /dev/null and b/NoteSkins/pump/frame5p/UpRight Hold BottomCap active (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/UpRight Hold TopCap (doubleres).png b/NoteSkins/pump/frame5p/UpRight Hold TopCap (doubleres).png new file mode 100644 index 0000000000..2205e4b202 Binary files /dev/null and b/NoteSkins/pump/frame5p/UpRight Hold TopCap (doubleres).png differ diff --git a/NoteSkins/pump/frame5p/metrics.ini b/NoteSkins/pump/frame5p/metrics.ini new file mode 100644 index 0000000000..daf9021fa2 --- /dev/null +++ b/NoteSkins/pump/frame5p/metrics.ini @@ -0,0 +1,10 @@ +[NoteDisplay] +TapNoteAnimationLength=0.333 +TapMineAnimationLength=0.333 +TapLiftAnimationLength=0.333 +TapFakeAnimationLength=0.333 +HoldHeadAnimationLength=0.333 +HoldTopCapAnimationLength=0.333 +HoldBottomCapAnimationLength=0.333 +HoldBodyAnimationLength=0.333 +HoldTailAnimationLength=0.333 diff --git a/NoteSkins/pump/newextra/Center Hold Body Active 6x1.png b/NoteSkins/pump/newextra/Center Hold Body Active 6x1.png new file mode 100644 index 0000000000..6c2468f553 Binary files /dev/null and b/NoteSkins/pump/newextra/Center Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/newextra/Center Hold BottomCap Active 6x1.png b/NoteSkins/pump/newextra/Center Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..445f925bd9 Binary files /dev/null and b/NoteSkins/pump/newextra/Center Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/newextra/Center Outline Receptor.png b/NoteSkins/pump/newextra/Center Outline Receptor.png new file mode 100644 index 0000000000..71470b7fef Binary files /dev/null and b/NoteSkins/pump/newextra/Center Outline Receptor.png differ diff --git a/NoteSkins/pump/newextra/Center Ready Receptor 1x3.png b/NoteSkins/pump/newextra/Center Ready Receptor 1x3.png new file mode 100644 index 0000000000..3e91998f09 Binary files /dev/null and b/NoteSkins/pump/newextra/Center Ready Receptor 1x3.png differ diff --git a/NoteSkins/pump/newextra/Center Tap Note 3x2.png b/NoteSkins/pump/newextra/Center Tap Note 3x2.png new file mode 100644 index 0000000000..bbcacc5c7a Binary files /dev/null and b/NoteSkins/pump/newextra/Center Tap Note 3x2.png differ diff --git a/NoteSkins/pump/newextra/DownLeft Hold Body Active 6x1.png b/NoteSkins/pump/newextra/DownLeft Hold Body Active 6x1.png new file mode 100644 index 0000000000..cc92bc75ea Binary files /dev/null and b/NoteSkins/pump/newextra/DownLeft Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/newextra/DownLeft Hold BottomCap Active 6x1.png b/NoteSkins/pump/newextra/DownLeft Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..7e6f92964a Binary files /dev/null and b/NoteSkins/pump/newextra/DownLeft Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/newextra/DownLeft Ready Receptor 1x3.png b/NoteSkins/pump/newextra/DownLeft Ready Receptor 1x3.png new file mode 100644 index 0000000000..eba181ed4d Binary files /dev/null and b/NoteSkins/pump/newextra/DownLeft Ready Receptor 1x3.png differ diff --git a/NoteSkins/pump/newextra/DownLeft Tap Note 3x2.png b/NoteSkins/pump/newextra/DownLeft Tap Note 3x2.png new file mode 100644 index 0000000000..7e2981d5b8 Binary files /dev/null and b/NoteSkins/pump/newextra/DownLeft Tap Note 3x2.png differ diff --git a/NoteSkins/pump/newextra/DownRight Hold Body Active 6x1.png b/NoteSkins/pump/newextra/DownRight Hold Body Active 6x1.png new file mode 100644 index 0000000000..e57c3e6f5a Binary files /dev/null and b/NoteSkins/pump/newextra/DownRight Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/newextra/DownRight Hold BottomCap Active 6x1.png b/NoteSkins/pump/newextra/DownRight Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..534f6cc4e4 Binary files /dev/null and b/NoteSkins/pump/newextra/DownRight Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/newextra/UpLeft Hold Body Active 6x1.png b/NoteSkins/pump/newextra/UpLeft Hold Body Active 6x1.png new file mode 100644 index 0000000000..42306997fc Binary files /dev/null and b/NoteSkins/pump/newextra/UpLeft Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/newextra/UpLeft Hold BottomCap Active 6x1.png b/NoteSkins/pump/newextra/UpLeft Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..eb094a1fdb Binary files /dev/null and b/NoteSkins/pump/newextra/UpLeft Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/newextra/UpLeft Ready Receptor 1x3.png b/NoteSkins/pump/newextra/UpLeft Ready Receptor 1x3.png new file mode 100644 index 0000000000..530d05b313 Binary files /dev/null and b/NoteSkins/pump/newextra/UpLeft Ready Receptor 1x3.png differ diff --git a/NoteSkins/pump/newextra/UpLeft Tap Note 3x2.png b/NoteSkins/pump/newextra/UpLeft Tap Note 3x2.png new file mode 100644 index 0000000000..115bd460d3 Binary files /dev/null and b/NoteSkins/pump/newextra/UpLeft Tap Note 3x2.png differ diff --git a/NoteSkins/pump/newextra/UpRight Hold Body Active 6x1.png b/NoteSkins/pump/newextra/UpRight Hold Body Active 6x1.png new file mode 100644 index 0000000000..4e386ccbaf Binary files /dev/null and b/NoteSkins/pump/newextra/UpRight Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/newextra/UpRight Hold BottomCap Active 6x1.png b/NoteSkins/pump/newextra/UpRight Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..dc0a392887 Binary files /dev/null and b/NoteSkins/pump/newextra/UpRight Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/Center Hold Body Active 6x1.png b/NoteSkins/pump/rhythm/Center Hold Body Active 6x1.png new file mode 100644 index 0000000000..9eb72a07bc Binary files /dev/null and b/NoteSkins/pump/rhythm/Center Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/Center Hold BottomCap Active 6x1.png b/NoteSkins/pump/rhythm/Center Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..020a6dba48 Binary files /dev/null and b/NoteSkins/pump/rhythm/Center Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/Center Ready Receptor 1x3.png b/NoteSkins/pump/rhythm/Center Ready Receptor 1x3.png new file mode 100644 index 0000000000..f315e99211 Binary files /dev/null and b/NoteSkins/pump/rhythm/Center Ready Receptor 1x3.png differ diff --git a/NoteSkins/pump/rhythm/Center Tap Note.lua b/NoteSkins/pump/rhythm/Center Tap Note.lua new file mode 100644 index 0000000000..5271c2ed97 --- /dev/null +++ b/NoteSkins/pump/rhythm/Center Tap Note.lua @@ -0,0 +1,4 @@ +return Def.Sprite { + Texture=NOTESKIN:GetPath( '_center', 'tap note' ); + Frames = Sprite.LinearFrames( 6, 1 ); +}; \ No newline at end of file diff --git a/NoteSkins/pump/rhythm/DownLeft Hold Body Active 6x1.png b/NoteSkins/pump/rhythm/DownLeft Hold Body Active 6x1.png new file mode 100644 index 0000000000..ce982adada Binary files /dev/null and b/NoteSkins/pump/rhythm/DownLeft Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/DownLeft Hold BottomCap Active 6x1.png b/NoteSkins/pump/rhythm/DownLeft Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..f4342a536e Binary files /dev/null and b/NoteSkins/pump/rhythm/DownLeft Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/DownLeft Ready Receptor 1x3.png b/NoteSkins/pump/rhythm/DownLeft Ready Receptor 1x3.png new file mode 100644 index 0000000000..100672ed69 Binary files /dev/null and b/NoteSkins/pump/rhythm/DownLeft Ready Receptor 1x3.png differ diff --git a/NoteSkins/pump/rhythm/DownLeft Tap Note.lua b/NoteSkins/pump/rhythm/DownLeft Tap Note.lua new file mode 100644 index 0000000000..4f830b9cc4 --- /dev/null +++ b/NoteSkins/pump/rhythm/DownLeft Tap Note.lua @@ -0,0 +1,4 @@ +return Def.Sprite { + Texture=NOTESKIN:GetPath( '_downleft', 'tap note' ); + Frames = Sprite.LinearFrames( 6, 1 ); +}; \ No newline at end of file diff --git a/NoteSkins/pump/rhythm/DownRight Hold Body Active 6x1.png b/NoteSkins/pump/rhythm/DownRight Hold Body Active 6x1.png new file mode 100644 index 0000000000..7c7847e5fa Binary files /dev/null and b/NoteSkins/pump/rhythm/DownRight Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/DownRight Hold BottomCap Active 6x1.png b/NoteSkins/pump/rhythm/DownRight Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..b86bd760e1 Binary files /dev/null and b/NoteSkins/pump/rhythm/DownRight Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/UpLeft Hold Body Active 6x1.png b/NoteSkins/pump/rhythm/UpLeft Hold Body Active 6x1.png new file mode 100644 index 0000000000..92e648f947 Binary files /dev/null and b/NoteSkins/pump/rhythm/UpLeft Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/UpLeft Hold BottomCap Active 6x1.png b/NoteSkins/pump/rhythm/UpLeft Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..e5a40f3123 Binary files /dev/null and b/NoteSkins/pump/rhythm/UpLeft Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/UpLeft Ready Receptor 1x3.png b/NoteSkins/pump/rhythm/UpLeft Ready Receptor 1x3.png new file mode 100644 index 0000000000..d16a140390 Binary files /dev/null and b/NoteSkins/pump/rhythm/UpLeft Ready Receptor 1x3.png differ diff --git a/NoteSkins/pump/rhythm/UpLeft Tap Note.lua b/NoteSkins/pump/rhythm/UpLeft Tap Note.lua new file mode 100644 index 0000000000..0e94651b2d --- /dev/null +++ b/NoteSkins/pump/rhythm/UpLeft Tap Note.lua @@ -0,0 +1,4 @@ +return Def.Sprite { + Texture=NOTESKIN:GetPath( '_upleft', 'tap note' ); + Frames = Sprite.LinearFrames( 6, 1 ); +}; \ No newline at end of file diff --git a/NoteSkins/pump/rhythm/UpRight Hold Body Active 6x1.png b/NoteSkins/pump/rhythm/UpRight Hold Body Active 6x1.png new file mode 100644 index 0000000000..4cad240121 Binary files /dev/null and b/NoteSkins/pump/rhythm/UpRight Hold Body Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/UpRight Hold BottomCap Active 6x1.png b/NoteSkins/pump/rhythm/UpRight Hold BottomCap Active 6x1.png new file mode 100644 index 0000000000..313f0e67cc Binary files /dev/null and b/NoteSkins/pump/rhythm/UpRight Hold BottomCap Active 6x1.png differ diff --git a/NoteSkins/pump/rhythm/_Center Tap Note 6x8.png b/NoteSkins/pump/rhythm/_Center Tap Note 6x8.png new file mode 100644 index 0000000000..4ef2fd8eb1 Binary files /dev/null and b/NoteSkins/pump/rhythm/_Center Tap Note 6x8.png differ diff --git a/NoteSkins/pump/rhythm/_DownLeft Tap Note 6x8.png b/NoteSkins/pump/rhythm/_DownLeft Tap Note 6x8.png new file mode 100644 index 0000000000..f62421dc16 Binary files /dev/null and b/NoteSkins/pump/rhythm/_DownLeft Tap Note 6x8.png differ diff --git a/NoteSkins/pump/rhythm/_UpLeft Tap Note 6x8.png b/NoteSkins/pump/rhythm/_UpLeft Tap Note 6x8.png new file mode 100644 index 0000000000..2b343ac0a5 Binary files /dev/null and b/NoteSkins/pump/rhythm/_UpLeft Tap Note 6x8.png differ diff --git a/NoteSkins/pump/rhythm/metrics.ini b/NoteSkins/pump/rhythm/metrics.ini new file mode 100644 index 0000000000..faaa880191 --- /dev/null +++ b/NoteSkins/pump/rhythm/metrics.ini @@ -0,0 +1,5 @@ +[NoteDisplay] +TapNoteNoteColorTextureCoordSpacingX=0 +TapNoteNoteColorTextureCoordSpacingY=0.125 +HoldHeadNoteColorTextureCoordSpacingX=0 +HoldHeadNoteColorTextureCoordSpacingY=0.125 \ No newline at end of file diff --git a/Themes/_fallback/Fonts/_Thai 16px [PhayanChana-stroke] 16x4.png b/Themes/_fallback/Fonts/_Thai 16px [PhayanChana-stroke] 16x4.png new file mode 100644 index 0000000000..28db2e9342 Binary files /dev/null and b/Themes/_fallback/Fonts/_Thai 16px [PhayanChana-stroke] 16x4.png differ diff --git a/Themes/_fallback/Fonts/_Thai 16px [PhayanChana] 16x4.png b/Themes/_fallback/Fonts/_Thai 16px [PhayanChana] 16x4.png index ce54c11145..c3f8d0bbbb 100644 Binary files a/Themes/_fallback/Fonts/_Thai 16px [PhayanChana] 16x4.png and b/Themes/_fallback/Fonts/_Thai 16px [PhayanChana] 16x4.png differ diff --git a/Themes/_fallback/Fonts/_Thai 16px [Sara1-stroke] 8x2.png b/Themes/_fallback/Fonts/_Thai 16px [Sara1-stroke] 8x2.png new file mode 100644 index 0000000000..95206cd3a6 Binary files /dev/null and b/Themes/_fallback/Fonts/_Thai 16px [Sara1-stroke] 8x2.png differ diff --git a/Themes/_fallback/Fonts/_Thai 16px [Sara1] 8x2.png b/Themes/_fallback/Fonts/_Thai 16px [Sara1] 8x2.png index 409ac902b2..d98c4de575 100644 Binary files a/Themes/_fallback/Fonts/_Thai 16px [Sara1] 8x2.png and b/Themes/_fallback/Fonts/_Thai 16px [Sara1] 8x2.png differ diff --git a/Themes/_fallback/Fonts/_Thai 16px [Sara2-stroke] 8x2.png b/Themes/_fallback/Fonts/_Thai 16px [Sara2-stroke] 8x2.png new file mode 100644 index 0000000000..36c7b1b64f Binary files /dev/null and b/Themes/_fallback/Fonts/_Thai 16px [Sara2-stroke] 8x2.png differ diff --git a/Themes/_fallback/Fonts/_Thai 16px [Sara2] 8x2.png b/Themes/_fallback/Fonts/_Thai 16px [Sara2] 8x2.png index ae38cef82e..3569e7029c 100644 Binary files a/Themes/_fallback/Fonts/_Thai 16px [Sara2] 8x2.png and b/Themes/_fallback/Fonts/_Thai 16px [Sara2] 8x2.png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji 1-stroke] 8x8 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji 1-stroke] 8x8 (doubleres).png new file mode 100644 index 0000000000..dc6fd4c950 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji 1-stroke] 8x8 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji 2-stroke] 8x8 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji 2-stroke] 8x8 (doubleres).png new file mode 100644 index 0000000000..246065ac46 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji 2-stroke] 8x8 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji 3-stroke] 8x8 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji 3-stroke] 8x8 (doubleres).png new file mode 100644 index 0000000000..d6a367d091 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji 3-stroke] 8x8 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji 4-stroke] 8x8 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji 4-stroke] 8x8 (doubleres).png new file mode 100644 index 0000000000..d90985e7e6 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji 4-stroke] 8x8 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji 5-stroke] 8x8 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji 5-stroke] 8x8 (doubleres).png new file mode 100644 index 0000000000..069eb81db2 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji 5-stroke] 8x8 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji 6-stroke] 8x8 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji 6-stroke] 8x8 (doubleres).png new file mode 100644 index 0000000000..f3654b5a01 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji 6-stroke] 8x8 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji 7-stroke] 8x8 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji 7-stroke] 8x8 (doubleres).png new file mode 100644 index 0000000000..7fb83c3bad Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji 7-stroke] 8x8 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji 8-stroke] 8x8 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji 8-stroke] 8x8 (doubleres).png new file mode 100644 index 0000000000..0d03515d65 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji 8-stroke] 8x8 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji 9-stroke] 8x8 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji 9-stroke] 8x8 (doubleres).png new file mode 100644 index 0000000000..9970f68791 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji 9-stroke] 8x8 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji-jis1-stroke] 32x32 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji-jis1-stroke] 32x32 (doubleres).png new file mode 100644 index 0000000000..afe28378ba Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji-jis1-stroke] 32x32 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji-jis2-stroke] 32x106 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji-jis2-stroke] 32x106 (doubleres).png new file mode 100644 index 0000000000..eb3266a6dd Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji-jis2-stroke] 32x106 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [kanji-regular-stroke] 32x61 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [kanji-regular-stroke] 32x61 (doubleres).png new file mode 100644 index 0000000000..ec9e30f473 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [kanji-regular-stroke] 32x61 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [main-stroke] 16x16 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [main-stroke] 16x16 (doubleres).png new file mode 100644 index 0000000000..3ba67dd436 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [main-stroke] 16x16 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_japanese 24px [symbol-stroke] 26x3 (doubleres).png b/Themes/_fallback/Fonts/_japanese 24px [symbol-stroke] 26x3 (doubleres).png new file mode 100644 index 0000000000..7591eca1a3 Binary files /dev/null and b/Themes/_fallback/Fonts/_japanese 24px [symbol-stroke] 26x3 (doubleres).png differ diff --git a/Themes/_fallback/Fonts/_korean 24px [jamo 1-stroke] 8x8.png b/Themes/_fallback/Fonts/_korean 24px [jamo 1-stroke] 8x8.png new file mode 100644 index 0000000000..846d93cebd Binary files /dev/null and b/Themes/_fallback/Fonts/_korean 24px [jamo 1-stroke] 8x8.png differ diff --git a/Themes/_fallback/Fonts/_korean 24px [jamo 1] 8x8.png b/Themes/_fallback/Fonts/_korean 24px [jamo 1] 8x8.png index 3d1b4c60aa..324e977e45 100644 Binary files a/Themes/_fallback/Fonts/_korean 24px [jamo 1] 8x8.png and b/Themes/_fallback/Fonts/_korean 24px [jamo 1] 8x8.png differ diff --git a/Themes/_fallback/Fonts/_korean 24px [jamo 2-stroke] 8x8.png b/Themes/_fallback/Fonts/_korean 24px [jamo 2-stroke] 8x8.png new file mode 100644 index 0000000000..0e2927eb32 Binary files /dev/null and b/Themes/_fallback/Fonts/_korean 24px [jamo 2-stroke] 8x8.png differ diff --git a/Themes/_fallback/Fonts/_korean 24px [jamo 2] 8x8.png b/Themes/_fallback/Fonts/_korean 24px [jamo 2] 8x8.png index e6db762fcd..681a12d9b6 100644 Binary files a/Themes/_fallback/Fonts/_korean 24px [jamo 2] 8x8.png and b/Themes/_fallback/Fonts/_korean 24px [jamo 2] 8x8.png differ diff --git a/Themes/_fallback/Fonts/_korean 24px [jamo 3-stroke] 8x8.png b/Themes/_fallback/Fonts/_korean 24px [jamo 3-stroke] 8x8.png new file mode 100644 index 0000000000..4ef50db1c5 Binary files /dev/null and b/Themes/_fallback/Fonts/_korean 24px [jamo 3-stroke] 8x8.png differ diff --git a/Themes/_fallback/Fonts/_korean 24px [jamo 3] 8x8.png b/Themes/_fallback/Fonts/_korean 24px [jamo 3] 8x8.png index 1184ace8d9..2aed57aec9 100644 Binary files a/Themes/_fallback/Fonts/_korean 24px [jamo 3] 8x8.png and b/Themes/_fallback/Fonts/_korean 24px [jamo 3] 8x8.png differ diff --git a/Themes/_fallback/Fonts/_korean 24px [jamo 4-stroke] 8x8.png b/Themes/_fallback/Fonts/_korean 24px [jamo 4-stroke] 8x8.png new file mode 100644 index 0000000000..529df808ef Binary files /dev/null and b/Themes/_fallback/Fonts/_korean 24px [jamo 4-stroke] 8x8.png differ diff --git a/Themes/_fallback/Fonts/_korean 24px [jamo 4] 8x8.png b/Themes/_fallback/Fonts/_korean 24px [jamo 4] 8x8.png index 8e1536aa3d..d7c9138b63 100644 Binary files a/Themes/_fallback/Fonts/_korean 24px [jamo 4] 8x8.png and b/Themes/_fallback/Fonts/_korean 24px [jamo 4] 8x8.png differ diff --git a/Themes/_fallback/Fonts/frutiger 24px [alt-stroke] 12x11.png b/Themes/_fallback/Fonts/frutiger 24px [alt-stroke] 12x11.png new file mode 100644 index 0000000000..03124f7f1d Binary files /dev/null and b/Themes/_fallback/Fonts/frutiger 24px [alt-stroke] 12x11.png differ diff --git a/Themes/_fallback/Graphics/Banner Artist.redir b/Themes/_fallback/Graphics/Banner Artist.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Artist.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner BPM.redir b/Themes/_fallback/Graphics/Banner BPM.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner BPM.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner ChallengeMeter.redir b/Themes/_fallback/Graphics/Banner ChallengeMeter.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner ChallengeMeter.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner DoubleChallengeMeter.redir b/Themes/_fallback/Graphics/Banner DoubleChallengeMeter.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner DoubleChallengeMeter.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner DoubleEasyMeter.redir b/Themes/_fallback/Graphics/Banner DoubleEasyMeter.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner DoubleEasyMeter.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner DoubleHardMeter.redir b/Themes/_fallback/Graphics/Banner DoubleHardMeter.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner DoubleHardMeter.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner DoubleMediumMeter.redir b/Themes/_fallback/Graphics/Banner DoubleMediumMeter.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner DoubleMediumMeter.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner EasyMeter.redir b/Themes/_fallback/Graphics/Banner EasyMeter.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner EasyMeter.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Genre.redir b/Themes/_fallback/Graphics/Banner Genre.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Genre.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner HardMeter.redir b/Themes/_fallback/Graphics/Banner HardMeter.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner HardMeter.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Length.redir b/Themes/_fallback/Graphics/Banner Length.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Length.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner MediumMeter.redir b/Themes/_fallback/Graphics/Banner MediumMeter.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner MediumMeter.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner Title.redir b/Themes/_fallback/Graphics/Banner Title.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner Title.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/Banner TopGrades.redir b/Themes/_fallback/Graphics/Banner TopGrades.redir new file mode 100644 index 0000000000..507050cda9 --- /dev/null +++ b/Themes/_fallback/Graphics/Banner TopGrades.redir @@ -0,0 +1 @@ +Common fallback banner \ No newline at end of file diff --git a/Themes/_fallback/Graphics/RoomWheelItem OverPart.redir b/Themes/_fallback/Graphics/RoomWheelItem OverPart.redir new file mode 100644 index 0000000000..d9001bdd6c --- /dev/null +++ b/Themes/_fallback/Graphics/RoomWheelItem OverPart.redir @@ -0,0 +1 @@ +MusicWheelItem Song OverPart \ No newline at end of file diff --git a/Themes/_fallback/Graphics/ScreenMapControllers exit.lua b/Themes/_fallback/Graphics/ScreenMapControllers exit.lua new file mode 100644 index 0000000000..30d51e6f23 --- /dev/null +++ b/Themes/_fallback/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("#808080")); + 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;effectcolor2,color("#808080");effectcolor1,color("#FFFFFF")); + LoseFocusCommand=cmd(stopeffect); +}; diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index b7ea3a02cc..032631c80e 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -497,8 +497,11 @@ Shuffle=Shuffle the songs around. 1.6x=1.6x 1.7x=1.7x 1.75x=1.75x +x1.75=1.75x 1.8x=1.8x 1.9x=1.9x +x2.25=2.25x +x2.5=2.5x 10=10 11=11 12=12 @@ -819,6 +822,7 @@ DisplayResolution=Display Resolution Duration seconds=Duration seconds EasterEggs=Easter Eggs Edit Songs/Steps=Edit Songs/Steps +Genre=Genre Practice Songs/Steps=Practice Songs/Steps Edit Courses=Edit Courses Edit BPM change=Edit BPM change @@ -827,6 +831,11 @@ Edit steps information=Edit steps information Exit Edit Mode=Exit Edit Mode Edit stop=Edit stop Edit delay=Edit delay +Edit Timing Data=Edit Timing Data +Edit time signature=Edit time signature (not working yet) +Edit time signature (top)=Edit time signature (beats per measure) +Edit time signature (bottom)=Edit time signature (single beat note value) +Edit tickcount=Edit tickcount Editor options=Options EditorShowBGChangesPlay=Show Backgrounds Effect=Effect @@ -980,6 +989,7 @@ SoundResampleQuality=Resampling Quality SoundVolume=Sound Volume SoundVolumeAttract=Attract Volume Speed=Speed +Step Author=Step Author Steps=Steps Stream=Stream Style=Style @@ -1187,11 +1197,15 @@ Do you want to save changes before exiting?=Do you want to save changes before e Enter a new BPM value.=Enter a new BPM value. Enter a new Stop value.=Enter a new Stop value. Enter a new Delay value.=Enter a new Delay value. +Enter a new Time Signature numerator value.=Enter the number of beats per measure. +Enter a new Time Signature denominator value.=Enter the note value that represents one beat. +Enter a new Tickcount value.=Enter a new Tickcount value. Enter a new artist transliteration.=Enter a new artist transliteration. 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 the author who made this step pattern.=Enter the author who made this step pattern. Enter a new last beat hint.=Enter a new last beat hint. Enter a new main title transliteration.=Enter a new main title transliteration. Enter a new main title.=Enter a new main title. @@ -1312,7 +1326,7 @@ HelpText=Ctrl+ENTER Selects &BACK; Exit &MENULEFT;&MENURIGHT; Move [ScreenNetSelectMusic] HeaderText=Select Music Online HeaderSubText=Song Selection -HelpText=Ctrl+ENTER Selects &BACK; Exit &MENULEFT;&MENURIGHT; Move::&MENUUP; Options &MENUDOWN; Change Difficulty +HelpText=Ctrl+ENTER Selects &BACK; Exit &MENULEFT;&MENURIGHT; Move::&MENUUP; Player Options &MENUDOWN; Change Difficulty [ScreenNetworkOptions] Disconnected from server.=Disconnected from server. @@ -1361,6 +1375,10 @@ Error deleting the file '%s'.=Error deleting the file "%s". Error renaming file. Destination file '%s' already exists.=Error renaming file. Destination file '%s' already exists. Error writing file '%s'.=Error writing file '%s'. +[NotesWriterSSC] +Error renaming file. Destination file '%s' already exists.=Error renaming file. Destination file '%s' already exists. +Error writing file '%s'.=Error writing file '%s'. + [ScreenOptionsManageProfiles] Are you sure you want to clear all data in the profile '%s'?=Are you sure you want to clear all data in the profile &oq;%s&cq;? Are you sure you want to delete the profile '%s'?=Are you sure you want to delete the profile &oq;%s&cq;? @@ -1375,6 +1393,9 @@ Off=Off [ScreenOptionsMemoryCard] Error mounting card: %s=Error mounting card: %s +(no label)=(no label) +size ???=size ??? +%dMB=%dMB [ScreenOptionsService] HeaderText=Options @@ -1589,6 +1610,7 @@ The folder "%s" appears to be a song folder. All song folders must reside in a 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 edit. Please use a different name.=The name you chose conflicts with another edit. Please use a different name. 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 [SongSort] FewestPlays=Fewest Plays @@ -1651,6 +1673,8 @@ texture=texture dance-couple=couple dance-double=double dance-single=single +dance-solo=solo +dance-threepanel=3panel dance-routine=routine lights-cabinet=Lights # SSC @@ -1675,6 +1699,7 @@ W5=Boo Reloaded metrics=Reloaded metrics Reloaded metrics and textures=Reloaded metrics and textures Reloaded scripts=Reloaded scripts +Reloaded overlay screens=Reloaded overlay screens [WorkoutManager] You must supply a name for your workout.=You must supply a name for your workout. @@ -1890,6 +1915,7 @@ Shift BPM changes and stops up one beat=Shift BPM changes and stops up one beat Lay mine=Lay mine Lay lift=Lay lift Add to/remove from right half=Add to/remove from right half +Switch player (Routine only)=Switch player (Routine only) [Grade] Tier01=AAAA @@ -1944,6 +1970,7 @@ W5=Boo Held=Held MaxCombo=Max Combo Miss=Miss + [NativeLanguageNames] Afar=Afar Abkhazian=аҧÑуа бызшәа @@ -2271,4 +2298,13 @@ Karaoke=Karaoke Lights_Cabinet=Lights [ScreenHowToInstallSongs] -HeaderText=Installing Songs \ No newline at end of file +HeaderText=Installing Songs + +[ThemePrefs] +IniFileMissing=IniFile missing. Can't read or write from disk :( +UnknownPreference=Unknown preference "%s" + +[ThemePrefsRows] +ChoicesSizeMismatch=Choices and Values have different sizes (%d, %d) +NoDefaultInValues=Preference "%s" has no values matching default +TypeMismatch=Type mismatch between default (%s) and value %d (%s) diff --git a/Themes/_fallback/Other/ScreenGameplaySyncMachine music.sm b/Themes/_fallback/Other/ScreenGameplaySyncMachine music.sm deleted file mode 100644 index 04761e58f0..0000000000 --- a/Themes/_fallback/Other/ScreenGameplaySyncMachine music.sm +++ /dev/null @@ -1,98 +0,0 @@ -#TITLE:Sync; -#SUBTITLE:; -#ARTIST:Unknown artist; -#TITLETRANSLIT:; -#SUBTITLETRANSLIT:; -#ARTISTTRANSLIT:; -#GENRE:; -#CREDIT:; -#BANNER:; -#BACKGROUND:; -#LYRICSPATH:; -#CDTITLE:; -#MUSIC:ScreenGameplaySyncMachine music.ogg; -#OFFSET:-0.012; -#SAMPLESTART:0.000; -#SAMPLELENGTH:12.000; -#SELECTABLE:YES; -#BPMS:0.000=132.000; -#STOPS:; -#BGCHANGES:; -#KEYSOUNDS:; - -//---------------dance-single - blank---------------- -#NOTES: - dance-single: - blank: - Beginner: - 1: - 0.302,0.205,0.000,0.000,0.000: - // measure 1 -0000 -0000 -0000 -0000 -, // measure 2 -1000 -0001 -1000 -0001 -1000 -0001 -1000 -0001 -, // measure 3 -1000 -0001 -1000 -0001 -1000 -0001 -1000 -0001 -, // measure 4 -1000 -0001 -1000 -0001 -1000 -0001 -1000 -0001 -, // measure 5 -1000 -0001 -1000 -0001 -1000 -0001 -1000 -0001 -, // measure 6 -1000 -0001 -1000 -0001 -1000 -0001 -1000 -0001 -, // measure 7 -1000 -0001 -1000 -0001 -1000 -0001 -1000 -0001 -, // measure 8 -1000 -0001 -1000 -0001 -1000 -0001 -1000 -0001 -; diff --git a/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc b/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc new file mode 100644 index 0000000000..a190bf0d9d --- /dev/null +++ b/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc @@ -0,0 +1,169 @@ +#TITLE:Sync; +#SUBTITLE:; +#ARTIST:Unknown artist; +#TITLETRANSLIT:; +#SUBTITLETRANSLIT:; +#ARTISTTRANSLIT:; +#GENRE:; +#CREDIT:; +#BANNER:; +#BACKGROUND:; +#LYRICSPATH:; +#CDTITLE:; +#MUSIC:ScreenGameplaySyncMachine music.ogg; +#OFFSET:-0.012; +#SAMPLESTART:0.000; +#SAMPLELENGTH:12.000; +#SELECTABLE:YES; +#BPMS:0.000=132.000; +#STOPS:; +#BGCHANGES:; +#KEYSOUNDS:; + +#NOTEDATA:; +#STEPSTYPE:dance-single:; +#DESCRIPTION:blank; +#DIFFICULTY:Beginner; +#METER:1; +#RADARVALUES:0.302,0.205,0.000,0.000,0.000; +#NOTES: + // measure 1 +0000 +, // measure 2 +1000 +0001 +1000 +0001 +1000 +0001 +1000 +0001 +, // measure 3 +1000 +0001 +1000 +0001 +1000 +0001 +1000 +0001 +, // measure 4 +1000 +0001 +1000 +0001 +1000 +0001 +1000 +0001 +, // measure 5 +1000 +0001 +1000 +0001 +1000 +0001 +1000 +0001 +, // measure 6 +1000 +0001 +1000 +0001 +1000 +0001 +1000 +0001 +, // measure 7 +1000 +0001 +1000 +0001 +1000 +0001 +1000 +0001 +, // measure 8 +1000 +0001 +1000 +0001 +1000 +0001 +1000 +0001 +; + +#NOTEDATA:; +#STEPSTYPE:pump-single; +#DESCRIPTION:blank; +#DIFFICULTY:Beginner; +#METER:1; +#RADARVALUES:0.302,0.205,0.000,0.000,0.000; +#NOTES: + // measure 1 +00000 +, // measure 2 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 3 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 4 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 5 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 6 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 7 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 8 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +; diff --git a/Themes/_fallback/Other/ScreenHowToPlay steps.sm b/Themes/_fallback/Other/ScreenHowToPlay steps.ssc similarity index 62% rename from Themes/_fallback/Other/ScreenHowToPlay steps.sm rename to Themes/_fallback/Other/ScreenHowToPlay steps.ssc index 5cf0a1c9af..1b43422f65 100644 --- a/Themes/_fallback/Other/ScreenHowToPlay steps.sm +++ b/Themes/_fallback/Other/ScreenHowToPlay steps.ssc @@ -6,44 +6,28 @@ // a song file here. #TITLE:ScreenHowToPlay steps; #ARTIST:foo; -#BPMS:0.000=100.000 +#BPMS:0.000=100.000; #STOPS:16=2,18=2,20=2,22=2; - +#NOTEDATA:; +#STEPSTYPE:dance-single; +#DESCRIPTION:BASIC; +#DIFFICULTY:easy; +#METER:1; +#RADARVALUES:0,0,0,0,0; #NOTES: - dance-single: - BASIC: - easy: - 1: - 0,0,0,0,0: -0000 -0000 -0000 0000 , 0000 -0000 -0000 -0000 , 0000 -0000 -0000 -0000 , 0000 -0000 -0000 -0000 , 0100 -0000 0010 -0000 , 1000 -0000 1001 -0000 , 1000 0100 @@ -79,51 +63,30 @@ 0000 , 0000 -0000 -0000 -0000 , 0000 -0000 -0000 -0000 ,; +#NOTEDATA:; +#STEPSTYPE:pump-single; +#DESCRIPTION:NORMAL; +#DIFFICULTY:easy; +#METER:1; +#RADARVALUES:0,0,0,0,0; #NOTES: - pump-single: - NORMAL: - easy: - 1: - 0,0,0,0,0: -00000 -00000 -00000 00000 , 00000 -00000 -00000 -00000 , 00000 -00000 -00000 -00000 , 00000 -00000 -00000 -00000 , 01000 -00000 00100 -00000 , 10000 -00000 10010 -00000 , 10000 01000 @@ -159,12 +122,6 @@ 00000 , 00000 -00000 -00000 -00000 , 00000 -00000 -00000 -00000 ,; diff --git a/Themes/_fallback/Scripts/02 Actor.lua b/Themes/_fallback/Scripts/02 Actor.lua index 5d0af89602..156a752ab2 100644 --- a/Themes/_fallback/Scripts/02 Actor.lua +++ b/Themes/_fallback/Scripts/02 Actor.lua @@ -133,6 +133,17 @@ function Actor:Center() self:y(SCREEN_CENTER_Y) end +function Actor:bezier(...) + local a = {...} + local b = {} + local c = 0 + assert((a == 9 or a == 5), "bad number of arguments for Actor:bezier()") + for i=3,c do + b[#b+1] = a[i] + end + self:tween(a[2], "TweenMode_Bezier", b) +end + -- (c) 2006 Glenn Maynard -- All rights reserved. -- diff --git a/Themes/_fallback/Scripts/02 Branches.lua b/Themes/_fallback/Scripts/02 Branches.lua index af4e7f1117..d485fbdcb6 100644 --- a/Themes/_fallback/Scripts/02 Branches.lua +++ b/Themes/_fallback/Scripts/02 Branches.lua @@ -26,6 +26,11 @@ function SelectMusicOrCourse() end end +-- functions used for Routine mode +function IsRoutine() + return GAMESTATE:GetCurrentStyle() and GAMESTATE:GetCurrentStyle():GetStyleType() == "StyleType_TwoPlayersSharedSides"; +end + Branch = { Init = function() if GAMESTATE:GetCoinMode() == 'CoinMode_Home' then @@ -155,6 +160,12 @@ Branch = { return "ScreenStageInformation" end end, + GameplayScreen = function() + if IsRoutine() then + return "ScreenGameplayShared" + end + return "ScreenGameplay" + end, AfterGameplay = function() -- pick an evaluation screen based on settings. if IsNetSMOnline() then @@ -181,4 +192,4 @@ Branch = { QuickSetupC = "ScreenQuickSetupPhaseThree", QuickSetupD = "ScreenQuickSetupPhaseFour", QuickSetupFinished = "ScreenQuickSetupFinished" -} \ No newline at end of file +} diff --git a/Themes/_fallback/Scripts/03 Gameplay.lua b/Themes/_fallback/Scripts/03 Gameplay.lua index 464320ad59..d2e3afd17b 100644 --- a/Themes/_fallback/Scripts/03 Gameplay.lua +++ b/Themes/_fallback/Scripts/03 Gameplay.lua @@ -147,6 +147,32 @@ function FailCombo() return Combo[sGame] end +function RoutineSkinP1() + sGame = GAMESTATE:GetCurrentGame():GetName() + local Combo = { + dance = "midi-routine-p1", + pump = "cmd-routine-p1", + beat = "default", + kb7 = "default", + para = "default", + guitar = "default" + } + return Combo[sGame] +end + +function RoutineSkinP2() + sGame = GAMESTATE:GetCurrentGame():GetName() + local Combo = { + dance = "midi-routine-p2", + pump = "cmd-routine-p2", + beat = "default", + kb7 = "retrobar", + para = "default", + guitar = "default" + } + return Combo[sGame] +end + -- todo: use tables for some of these -aj function HoldTiming() if GAMESTATE:GetCurrentGame():GetName() == "pump" then diff --git a/Themes/_fallback/Scripts/03 ThemePrefs.lua b/Themes/_fallback/Scripts/03 ThemePrefs.lua index 0bf146e460..0a61da5741 100644 --- a/Themes/_fallback/Scripts/03 ThemePrefs.lua +++ b/Themes/_fallback/Scripts/03 ThemePrefs.lua @@ -3,12 +3,16 @@ ThemePrefs: handles the underlying structure for ThemePrefs, so any themes built off of this can simply declare their prefs and default values, and access them through this system. -v0.7: Dec. 15, 2010. Initial version. +v0.7.1: Dec. 28, 2010. Added language support. +v0.7.0: Dec. 15, 2010. Initial version. + +vyhd wrote this for sm-ssc. <3 you guys --]] --- If we don't have IniFile, we can't read to or write from disk -if not IniFile then - Warn( "ThemePrefs: IniFile missing. Can't read/write from disk :(" ) +-- local function to handle themed error strings +-- (and to ensure we're getting all of them from the same section) +local function GetString( name ) + return THEME:GetString( "ThemePrefs", name ) end function PrintTable( tbl ) @@ -74,6 +78,9 @@ ThemePrefs = -- Only read from disk once, when _fallback calls this; we just -- need the base set once to add prefs onto. Init = function( prefs, bLoadFromDisk ) + -- If we don't have IniFile, we can't read/write from/to disk + if not IniFile then Warn( GetString("IniFileMissing") ) end + Trace( ("ThemePrefs.Init(prefs, %s)"):format(tostring(bLoadFromDisk)) ) if bLoadFromDisk then Trace( "ThemePrefs.Init: loading from disk" ) @@ -83,20 +90,20 @@ ThemePrefs = Trace( "ThemePrefs.Init: not loading from disk" ) -- create the section if it doesn't exist - local name = GetThemeName() - PrefsTable[name] = PrefsTable[name] and PrefsTable[name] or { } + local section = GetThemeName() + PrefsTable[section] = PrefsTable[section] and PrefsTable[section] or { } - Trace( "Using section " .. name ) + Trace( "Using section " .. section ) -- if the key doesn't exist, add it with our default value for k, tbl in pairs(prefs) do - if not PrefsTable[name][k] then + if not PrefsTable[section][k] then Trace( k .. " doesn't exist, creating" ) - PrefsTable[name][k] = tbl.Default + PrefsTable[section][k] = tbl.Default end end - PrintTable( PrefsTable[name] ) + PrintTable( PrefsTable[section] ) end, Load = function() @@ -117,7 +124,7 @@ ThemePrefs = Trace( ("ThemePrefs.Get(%s)"):format(name) ) local tbl = ResolveTable(name) if tbl then return tbl[name] end - Warn( ("GetThemePref: unknown preference \"%s\""):format(name) ) + Warn( "Get: "..GetString("UnknownPreference"):format(name) ) return nil end, @@ -125,7 +132,7 @@ ThemePrefs = Trace( ("ThemePrefs.Set(%s, %s)"):format(name, tostring(value)) ) local tbl = ResolveTable(name) if tbl then tbl[name] = value; NeedsSaved = true; return end - Warn( ("SetThemePref: unknown preference \"%s\""):format(name) ) + Warn( "Set: "..GetString("UnknownPreference"):format(name) ) end, }; diff --git a/Themes/_fallback/Scripts/03 ThemePrefsRows.lua b/Themes/_fallback/Scripts/03 ThemePrefsRows.lua index 75abf05af8..21ad8973c2 100644 --- a/Themes/_fallback/Scripts/03 ThemePrefsRows.lua +++ b/Themes/_fallback/Scripts/03 ThemePrefsRows.lua @@ -3,7 +3,11 @@ ThemePrefsRows: you give it the choices, values, and params, and it'll generate the rest; quirky behavior to be outlined below. Documentation will be provided once this system is stabilized. -v0.5: Dec. 15, 2010. Initial version. Not very well tested. +v0.5.2: Dec. 28, 2010. Throw an error for default/value type mismatches. +v0.5.1: Dec. 27, 2010. Fix Choices not necessarily being strings. +v0.5.0: Dec. 15, 2010. Initial version. Not very well tested. + +vyhd wrote this for sm-ssc --]] -- unless overridden, these parameters will be used for the OptionsRow @@ -22,7 +26,12 @@ local DefaultParams = SaveSelections = nil, } -local function DefaultLoadSelections( pref, default, choices, values ) +-- local alias to simplify error reporting +local function GetString( name ) + return THEME:GetString( "ThemePrefsRows", name ) +end + +local function DefaultLoad( pref, default, choices, values ) return function(self, list, pn) local val = ThemePrefs.Get( pref ) @@ -36,13 +45,13 @@ local function DefaultLoadSelections( pref, default, choices, values ) if values[i] == default then list[i] = true return end end - -- set to the first value and throw a warning - Warn( ("LoadSelections: preference \"%s\"'s default not in Values"):format(pref) ) + -- set to the first value and output a warning + Warn( GetString("NoDefaultInValues"):format(pref) ) list[1] = true end end -local function DefaultSaveSelections( pref, choices, values ) +local function DefaultSave( pref, choices, values ) local msg = "ThemePrefChanged" local params = { Name = pref } @@ -54,17 +63,48 @@ local function DefaultSaveSelections( pref, choices, values ) end end +-- This function checks for mismatches between the default value and the +-- values table passed to the ThemePrefRow, e.g. it will return false if +-- you have a boolean default and an integer value. I'm somewhat stricter +-- about types than Lua is because I don't like the unpredictability and +-- complexity of coercing values transparently in a bunch of places. +local function TypesMatch( Values, Default ) + local DefaultType = type(Default) + + for i, value in ipairs(Values) do + local ValueType = type(value) + if ValueType ~= DefaultType then + Warn( GetString("TypeMismatch"):format(DefaultType, i, ValueType) ) + return false + end + end + + return true +end local function CreateThemePrefRow( pref, tbl ) - Trace( "CreateThemePrefRow( " .. pref .. " )" ) - -- can't make an option handler without options if not tbl.Choices then return nil end local Choices = tbl.Choices + local Default = tbl.Default local Values = tbl.Values and tbl.Values or Choices local Params = tbl.Params and tbl.Params or { } + -- if the choices aren't strings, make them strings now + for i, str in ipairs(Choices) do + Choices[i] = tostring( Choices[i] ) + end + + -- check to see that Values and Choices have the same length + if #Choices ~= #Values then + Warn( GetString("ChoicesSizeMismatch") ) + return nil + end + + -- check to see that everything in Values matches the type of Default + if not TypesMatch( Values, Default ) then return nil end + -- set the name and choices here; we'll do the rest below local Handler = { Name = pref, Choices = Choices } @@ -77,11 +117,11 @@ local function CreateThemePrefRow( pref, tbl ) -- if we don't have LoadSelections and SaveSelections, make them if not Handler.LoadSelections then - Handler.LoadSelections = DefaultLoadSelections( pref, tbl.Default, Choices, Values ) + Handler.LoadSelections = DefaultLoad( pref, Default, Choices, Values ) end if not Handler.SaveSelections then - Handler.SaveSelections = DefaultSaveSelections( pref, Choices, Values ) + Handler.SaveSelections = DefaultSave( pref, Choices, Values ) end return Handler @@ -119,7 +159,6 @@ ThemePrefRow = ThemePrefsRows.GetRow ThemePrefs.InitAll = function( prefs ) Trace( "ThemePrefs.InitAll( prefs )" ) - -- HACK: for now, don't worry about extraneous file I/O ThemePrefs.Init( prefs, true ) ThemePrefsRows.Init( prefs ) end diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index 87ccb3e72c..c93357f68f 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -108,7 +108,6 @@ CourseGroupColor7=color("1,1,1,1") -- white CourseGroupColor8=color("1,1,1,1") -- white CourseGroupColor9=color("1,1,1,1") -- white CourseGroupColor10=color("1,1,1,1") -- white -# as they say. UnlockColor=color("1,0.5,0,1") ExtraColor=color("#ff0000") -- red @@ -120,7 +119,7 @@ UnlockNames="" # 03 # [ArrowEffects] -# Complicated stuff you probably shouldnt ever mess with or else you'll +# Complicated stuff you probably shouldn't ever mess with or else you'll # destroy mods completely! FrameWidthEffectsPixelsPerSecond=400 FrameWidthEffectsMinMultiplier=0.5 @@ -129,6 +128,42 @@ FrameWidthLockEffectsToOverlapping=false FrameWidthLockEffectsTweenPixels=25 ArrowSpacing=128 DrawHiddenNotesAfterReceptor=true +BlinkModFrequency=0.3333 +BoostModMinClamp=-400 +BoostModMaxClamp=400 +BrakeModMinClamp=-400 +BrakeModMaxClamp=400 +WaveModMagnitude=20 +WaveModHeight=38 +BoomerangPeakPercentage=0.75 +ExpandMultiplierFrequency=3 +ExpandMultiplierScaleFromLow=-1 +ExpandMultiplierScaleFromHigh=1 +ExpandMultiplierScaleToLow=0.75 +ExpandMultiplierScaleToHigh=1.75 +ExpandSpeedScaleFromLow=0 +ExpandSpeedScaleFromHigh=1 +ExpandSpeedScaleToLow=1 +# No need for the high here: that is already calculated in code. +TipsyTimerFrequency=1.2 +TipsyColumnFrequency=1.8 +TipsyArrowMagnitude=0.4 +TipsyOffsetTimerFrequency=1.2 +TipsyOffsetColumnFrequency=2 +TipsyOffsetArrowMagnitude=0.4 +TornadoPositionScaleToLow=-1 +TornadoPositionScaleToHigh=1 +TornadoOffsetFrequency=6 +TornadoOffsetScaleFromLow=-1 +TornadoOffsetScaleFromHigh=1 +DrunkColumnFrequency=0.2 +DrunkOffsetFrequency=10 +DrunkArrowMagnitude=0.5 +BeatOffsetHeight=15 +BeatPIHeight=2 +MiniPercentBase=0.5 +MiniPercentGate=1 +QuantizeArrowYPosition=false [Background] # Background stuff. again, its usually a better idea to leave this alone @@ -179,6 +214,7 @@ RandomCycleSpeed=0.1 Separator="-" # ??? when it cycles. ShowQMarksInRandomCycle=true +QuestionMarksText="???" RandomText="!!!" # xxx: localize me -aj VariousText="000" @@ -230,9 +266,31 @@ SaveScreenshot1="MenuLeft-MenuRight" SaveScreenshot2="" CancelAllPlayerOptions="Left,Right,Left,Right,Left,Right" BackInEventMode="" +[CodeDetectorOnline] +Fallback="CodeDetector" +PrevSteps1="MenuUp,MenuUp" +PrevSteps2="" +NextSteps1="MenuDown,MenuDown" +NextSteps2="" +NextSort3="" +NextSort4="" +ModeMenu1="" +Mirror="" +Left="" +Right="" +Shuffle="" +SuperShuffle="" +NextScrollSpeed="" +PreviousScrollSpeed="" +NextAccel="" +NextEffect="" +NextAppearance="" +Reverse="" +HoldNotes="" +CancelAll="" [CombinedLifeMeterTug] -# We dont use it. +# We don't use it. MeterWidth=0.0 MeterHeight=0.0 @@ -302,7 +360,7 @@ SortLevel5Color=color("0,1,0,1") # something else. Mostly for custom games and game emulation, PIU for example. # The names of which -Names="PumpHard,PumpFreestyle,PumpNightmare,PumpHalfDouble" +Names="PumpHard,PumpFreestyle,PumpNightmare,PumpHalfDouble,PumpRoutine" # Names="DanceCoupleBeginner,DanceCoupleEasy,DanceCoupleMedium,DanceCoupleHard,DanceCoupleExpert,PumpHard" # That get remapped to @@ -350,6 +408,11 @@ 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 @@ -685,6 +748,7 @@ WarningBeepStart=10 # MaxStallSeconds=7.5 MaxStallSeconds=0 # +HurryUpTransition=5.5 Text1OnCommand=stopeffect;stoptweening;shadowlength,0; Text1FormatFunction=function(fSeconds) fSeconds=math.min( 99, math.ceil(fSeconds) ); local digit = math.floor(fSeconds); return ""..digit end Text2OnCommand=stopeffect;stoptweening;shadowlength,0;visible,false @@ -753,6 +817,10 @@ SectionColor1=color("1,1,1,1") # SongRealExtraColor=color("1,0,0,1") SortMenuColor=color("1,1,1,1") +# +RouletteColor=color("1,0,0,1") +RandomColor=color("1,0,0,1") +PortalColor=color("1,0,0,1") SortOrders={ "SortOrder_Preferred", "SortOrder_Group", "SortOrder_Title", "SortOrder_BPM", "SortOrder_Artist", "SortOrder_Genre" } # SortOrders={ "SortOrder_Preferred", "SortOrder_Group", "SortOrder_Title", "SortOrder_BPM", "SortOrder_Popularity", "SortOrder_Artist", "SortOrder_Genre" } @@ -862,14 +930,33 @@ ShowBoard=false ShowBeatBars=false # FadeBeforeTargetsPercent=0 +FadeFailTime=1.5 # BarMeasureAlpha=1 Bar4thAlpha=1 Bar8thAlpha=1 Bar16thAlpha=1 # -RoutineNoteSkinP1="midi-routine-p1" -RoutineNoteSkinP2="midi-routine-p2" +RoutineNoteSkinP1=RoutineSkinP1() +RoutineNoteSkinP2=RoutineSkinP2() +# +BPMColor=color("1,0,0,1") +StopColor=color("0.8,0.8,0,1") +DelayColor=color("0,0.8,0.8,1") +TimeSignatureColor=color("1,0.55,0,1") +TickcountColor=color("0,1,0,1") +# +BPMIsLeftSide=true +StopIsLeftSide=true +DelayIsLeftSide=true +TimeSignatureIsLeftSide=true +TickcountIsLeftSide=false +# +BPMOffsetX=60 +StopOffsetX=10 +DelayOffsetX=10 +TimeSignatureOffsetX=30 +TickcountOffsetX=10 [PlayerStageStats] # Original CVS Grading @@ -915,7 +1002,9 @@ ComboUnderField=ComboUnderField() PenalizeTapScoreNone=false JudgeHoldNotesOnSameRowTogether=(GAMESTATE:GetCurrentGame():GetName() == "pump") HoldCheckpoints=(GAMESTATE:GetCurrentGame():GetName() == "pump") -CheckpointsUseTimeSignatures=(GAMESTATE:GetCurrentGame():GetName() == "pump") +CheckpointsUseTickcounts=(GAMESTATE:GetCurrentGame():GetName() == "pump") +; deprecated? +CheckpointsUseTimeSignatures=false CheckpointsTapsSeparateJudgment=CheckpointsTapsSeparateJudgment() CheckpointsFlashOnHold=false ImmediateHoldLetGo=ImmediateHoldLetGo() @@ -927,6 +1016,18 @@ MaxHoldLife=MaxHoldLife() RollBodyIncrementsCombo=GetGamePrefB("UserPrefComboOnRolls") ScoreMissedHoldsAndRolls=ScoreMissedHoldsAndRolls() PercentUntilColorCombo=0.25 +ComboStoppedAt=50 +AttackRunTimeRandom=6 +AttackRunTimeMine=7 + +[PlayerOptions] +RandomSpeedChance=0.2 +RandomReverseChance=0.2 +RandomDarkChance=0.1 +RandomAccelChance=0.333 +RandomEffectChance=0.667 +RandomHiddenChance=0.05 +RandomSuddenChance=0.1 [PlayerShared] Fallback="Player" @@ -1187,12 +1288,17 @@ AfterSetCommand=%TextBannerAfterSet [WheelNotifyIcon] ShowTraining=false +BlinkPlayersBest=true # 04 # [Screen] ScreenInitCommand= ScreenOnCommand= AllowOperatorMenuButton=true +# This metric is only for people who know what they are doing. If you set this +# to false, you are expected to know how to cancel screens in Lua. (coincidentally, +# that would be SCREENMAN:GetTopScreen():Cancel(), for people who aren't AJ ;) ) +HandleBackButton=true RepeatRate=-1 RepeatDelay=-1 PrepareScreens= @@ -1808,6 +1914,7 @@ Codes="" # TimerSeconds=60 DoRouletteOnMenuTimer=true +RouletteTimerSeconds=15 # DefaultSort=GAMESTATE:IsCourseMode() and "Group" or "AllCourses" # @@ -1948,7 +2055,7 @@ Fallback="StepsDisplay" Class="ScreenSplash" Fallback="ScreenSplash" # -NextScreen="ScreenGameplay" +NextScreen=Branch.GameplayScreen() PrevScreen=Branch.BackOutOfStageInformation() PrepareScreen="ScreenGameplay" # @@ -2550,13 +2657,13 @@ ShowExitRow=true [ScreenTestInput] Class="ScreenTestInput" Fallback="ScreenOptionsServiceChild" -NextScreen="ScreenOptionsService" -PrevScreen="ScreenOptionsService" +NextScreen="ScreenOptionsExtended" +PrevScreen="ScreenOptionsExtended" [ScreenOptionsSystemDirection] Fallback="ScreenOptionsServiceChild" -PrevScreen=Branch.TitleMenu() -NextScreen=Branch.TitleMenu() +PrevScreen="ScreenOptionsService" +NextScreen="ScreenOptionsService" LineNames="1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22" Line1="conf,Windowed" Line2="conf,DisplayResolution" @@ -2583,6 +2690,8 @@ Line22="conf,EventMode" [ScreenOptionsGraphicsSound] Fallback="ScreenOptionsServiceChild" +NextScreen="ScreenOptionsExtended" +PrevScreen="ScreenOptionsExtended" LineNames="1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,18,19,20" Line1="conf,Windowed" Line2="conf,DisplayResolution" @@ -2607,6 +2716,8 @@ Line20="conf,VisualDelaySeconds" [ScreenOptionsAdvanced] Fallback="ScreenOptionsServiceChild" +NextScreen="ScreenOptionsExtended" +PrevScreen="ScreenOptionsExtended" LineNames="2,3,4,8,11,13,14,15,16,28,29,30" Line2="conf,ScoringType" Line3="conf,TimingWindowScale" @@ -2630,6 +2741,8 @@ Line30="conf,FastLoad" [ScreenAppearanceOptions] Fallback="ScreenOptionsServiceChild" +NextScreen="ScreenOptionsExtended" +PrevScreen="ScreenOptionsExtended" LineNames="1,2,3,4,5,14,15,17,18,19" Line1="conf,Language" Line2="conf,Announcer" @@ -2646,6 +2759,8 @@ Line19="conf,NumBackgrounds" # user interface options that aren't related to themes, etc. # (some don't get used/modified too often) Fallback="ScreenOptionsServiceChild" +NextScreen="ScreenOptionsExtended" +PrevScreen="ScreenOptionsExtended" LineNames="1,3,4,6,7,9,10,11,12,14" Line1="conf,Center1Player" Line3="conf,DancePointsForOni" @@ -2665,7 +2780,8 @@ Line14="conf,ShowSongOptions" [ScreenOptionsInput] Fallback="ScreenOptionsServiceChild" -# should we put map/test input in this section too? +NextScreen="ScreenOptionsExtended" +PrevScreen="ScreenOptionsExtended" LineNames="1,2,3,4,5" Line1="conf,AutoMapOnJoyChange" Line2="conf,OnlyDedicatedMenuButtons" @@ -2674,8 +2790,10 @@ Line4="conf,ArcadeOptionsNavigation" Line5="conf,MusicWheelSwitchSpeed" [ScreenOptionsArcade] -# shit that's tied to arcade features Fallback="ScreenOptionsServiceChild" +NextScreen="ScreenOptionsExtended" +PrevScreen="ScreenOptionsExtended" +# stuff tied to arcade features LineNames="1,2,3,4,5,6" Line1="conf,GetRankingName" Line2="conf,CoinMode" @@ -3350,7 +3468,7 @@ Line4="gamecommand;screen,ScreenOptionsManageCourses;name,Edit Courses" EditMode="EditMode_Full" ShowGroups=true -Arrows1X=SCREEN_CENTER_X-130 +Arrows1X=SCREEN_CENTER_X-176 Arrows2X=SCREEN_CENTER_X+270 ArrowsEnabledCommand=diffuse,color("1,1,1,1");shadowlengthy,1;shadowcolor,color("#002740"); ArrowsDisabledCommand=diffuse,color("0.45,0.45,0.45,1");shadowlengthy,1;shadowcolor,color("#002740"); @@ -3364,12 +3482,12 @@ SongBannerY=SCREEN_CENTER_Y-90 SongBannerOnCommand=scaletoclipped,128,40 TextBannerType="TextBannerEditMode" -SongTextBannerX=SCREEN_CENTER_X-64 +SongTextBannerX=SCREEN_CENTER_X-128 SongTextBannerY=SCREEN_CENTER_Y-90 -StepsDisplayX=SCREEN_CENTER_X+170 +StepsDisplayX=SCREEN_CENTER_X+150 StepsDisplayY=SCREEN_CENTER_Y-0 -StepsDisplaySourceX=SCREEN_CENTER_X+170 +StepsDisplaySourceX=SCREEN_CENTER_X+150 StepsDisplaySourceY=SCREEN_CENTER_Y+80 Row1Y=SCREEN_CENTER_Y-140 @@ -3381,60 +3499,60 @@ Row6Y=SCREEN_CENTER_Y+80 Row7Y=SCREEN_CENTER_Y+120 Label1X=SCREEN_CENTER_X-250 -Label1Y=THEME:GetMetric("EditMode","Row1Y") +Label1Y=THEME:GetMetric("EditMenu","Row1Y") Label1OnCommand=shadowlength,1;zoom,0.75 Label1OffCommand= Label2X=SCREEN_CENTER_X-250 -Label2Y=THEME:GetMetric("EditMode","Row2Y") +Label2Y=THEME:GetMetric("EditMenu","Row2Y") Label2OnCommand=shadowlength,1;zoom,0.75 Label2OffCommand= Label3X=SCREEN_CENTER_X-250 -Label3Y=THEME:GetMetric("EditMode","Row3Y") +Label3Y=THEME:GetMetric("EditMenu","Row3Y") Label3OnCommand=shadowlength,1;zoom,0.75 Label3OffCommand= Label4X=SCREEN_CENTER_X-250 -Label4Y=THEME:GetMetric("EditMode","Row4Y") +Label4Y=THEME:GetMetric("EditMenu","Row4Y") Label4OnCommand=shadowlength,1;zoom,0.75 Label4OffCommand= Label5X=SCREEN_CENTER_X-250 -Label5Y=THEME:GetMetric("EditMode","Row5Y") +Label5Y=THEME:GetMetric("EditMenu","Row5Y") Label5OnCommand=shadowlength,1;zoom,0.75 Label5OffCommand= Label6X=SCREEN_CENTER_X-250 -Label6Y=THEME:GetMetric("EditMode","Row6Y") +Label6Y=THEME:GetMetric("EditMenu","Row6Y") Label6OnCommand=shadowlength,1;zoom,0.75 Label6OffCommand= Label7X=SCREEN_CENTER_X-250 -Label7Y=THEME:GetMetric("EditMode","Row7Y") +Label7Y=THEME:GetMetric("EditMenu","Row7Y") Label7OnCommand=shadowlength,1;zoom,0.75 Label7OffCommand= -Value1X=SCREEN_CENTER_X -Value1Y=THEME:GetMetric("EditMode","Row1Y") +Value1X=SCREEN_CENTER_X-24 +Value1Y=THEME:GetMetric("EditMenu","Row1Y") Value1OnCommand=shadowlength,1;zoom,0.75;maxwidth,SCREEN_CENTER_X*0.65 Value1OffCommand= Value2X=SCREEN_CENTER_X+60 -Value2Y=THEME:GetMetric("EditMode","Row2Y") +Value2Y=THEME:GetMetric("EditMenu","Row2Y") Value2OnCommand=shadowlength,1;zoom,0.75;maxwidth,SCREEN_CENTER_X*0.65 Value2OffCommand= Value3X=SCREEN_CENTER_X+60 -Value3Y=THEME:GetMetric("EditMode","Row3Y") +Value3Y=THEME:GetMetric("EditMenu","Row3Y") Value3OnCommand=shadowlength,1;zoom,0.75;maxwidth,SCREEN_CENTER_X*0.65 Value3OffCommand= Value4X=SCREEN_CENTER_X -Value4Y=THEME:GetMetric("EditMode","Row4Y") +Value4Y=THEME:GetMetric("EditMenu","Row4Y") Value4OnCommand=shadowlength,1;zoom,0.75;maxwidth,SCREEN_CENTER_X*0.65 Value4OffCommand= Value5X=SCREEN_CENTER_X+60 -Value5Y=THEME:GetMetric("EditMode","Row5Y") +Value5Y=THEME:GetMetric("EditMenu","Row5Y") Value5OnCommand=shadowlength,1;zoom,0.75;maxwidth,SCREEN_CENTER_X*0.65 Value5OffCommand= Value6X=SCREEN_CENTER_X -Value6Y=THEME:GetMetric("EditMode","Row6Y") +Value6Y=THEME:GetMetric("EditMenu","Row6Y") Value6OnCommand=shadowlength,1;zoom,0.75;maxwidth,SCREEN_CENTER_X*0.65 Value6OffCommand= Value7X=SCREEN_CENTER_X+60 -Value7Y=THEME:GetMetric("EditMode","Row7Y") +Value7Y=THEME:GetMetric("EditMenu","Row7Y") Value7OnCommand=shadowlength,1;zoom,0.75;maxwidth,SCREEN_CENTER_X*0.65 Value7OffCommand= @@ -3445,7 +3563,7 @@ Fallback="TextBanner" Fallback="ScreenWithMenuElements" Class="ScreenEditMenu" NextScreen="ScreenEdit" -PrevScreen=Branch.TitleMenu() +PrevScreen="ScreenOptionsEdit" EditMenuType="EditMenu" ExplanationX=SCREEN_CENTER_X ExplanationY=SCREEN_BOTTOM-56 @@ -3489,6 +3607,7 @@ Fallback="ScreenEditMenu" Class="ScreenEditMenu" # NextScreen="ScreenPractice" +PrevScreen="ScreenOptionsEdit" EditMenuType="PracticeMenu" [PracticeMenu] @@ -3539,6 +3658,26 @@ Fallback="StepsDisplay" Fallback="ScreenMiniMenu" ColorDisabled=color("1,1,1,1") RowInitCommand=halign,0.5;valign,0.5;zoom,0.8;x,75;y,45;shadowlength,1 +OptionRowNormalMetricsGroup="OptionRowMiniMenuEditHelp" + +[OptionRowMiniMenuEditHelp] +Fallback="OptionRowMiniMenu" + +TitleX=SCREEN_CENTER_X-312 +TitleOnCommand=halign,0;strokecolor,color("#222222CC");shadowlength,1;zoom,0.9 + +RowPositionTransformFunction=function(self,offsetFromCenter,itemIndex,numItems) \ + local indexOffset = itemIndex-(numItems-1)/2; \ + self:y(SCREEN_CENTER_Y + indexOffset * 20); \ +end + +ItemsStartX=SCREEN_CENTER_X+260 +ItemsEndX=SCREEN_CENTER_X+260 +ItemsLongRowP1X=SCREEN_CENTER_X+260 +ItemsLongRowP2X=SCREEN_CENTER_X+260 + +ItemOnCommand=x,SCREEN_CENTER_X+176;halign,0;strokecolor,color("#222222CC");shadowlength,1;zoom,0.9 +ColorDisabled=color("1,1,1,1") [ScreenMiniMenuMainMenu] Fallback="ScreenMiniMenu" @@ -3553,6 +3692,9 @@ Fallback="ScreenMiniMenu" [ScreenMiniMenuSongInformation] Fallback="ScreenMiniMenu" +[ScreenMiniMenuTimingDataInformation] +Fallback="ScreenMiniMenu" + [ScreenMiniMenuBackgroundChange] Fallback="ScreenMiniMenu" @@ -3640,8 +3782,8 @@ OptionRowNormalMetricsGroup="OptionRowCourseOverview" [ScreenGameplaySyncMachine] Class="ScreenGameplaySyncMachine" Fallback="ScreenGameplay" -PrevScreen="ScreenOptionsService" -NextScreen="ScreenOptionsService" +PrevScreen="ScreenOptionsExtended" +NextScreen="ScreenOptionsExtended" PlayerType="PlayerSyncMachine" AllowCenter1Player=false @@ -3735,6 +3877,7 @@ PrevScreen="ScreenNetRoom" NextScreen="ScreenStageInformation" NoSongsScreen=Branch.TitleMenu() RoomSelectScreen="ScreenNetRoom" +Codes="CodeDetectorOnline" ShowStyleIcon=false TimerSeconds= @@ -3742,21 +3885,19 @@ TimerStealth=true SampleMusicPreviewMode='SampleMusicPreviewMode_Normal' -# huh? (probably leftovers from the old NetSelectBase) -NumStylesShow=1 -NumSongsShow=4 -NumGroupsShow=3 - +MusicWheelType="OnlineMusicWheel" MusicWheelX=SCREEN_CENTER_X+160 MusicWheelY=SCREEN_CENTER_Y MusicWheelOnCommand= MusicWheelOffCommand= +# todo: move these to Lua bganim BPMDisplayX=SCREEN_CENTER_X-160-90+2 BPMDisplayY=SCREEN_TOP+160+(36/2)+8 BPMDisplayOnCommand= BPMDisplayOffCommand= +# todo: move these to Lua bganim ModIconsP1X=SCREEN_CENTER_X+144 ModIconsP1Y=SCREEN_CENTER_Y-165 ModIconsP1OnCommand=zoomy,0;linear,0.5;zoomy,1 @@ -3766,11 +3907,13 @@ ModIconsP2Y=SCREEN_CENTER_Y-164 ModIconsP2OnCommand=zoomy,0;linear,0.5;zoomy,1 ModIconsP2OffCommand=linear,0.5;zoomy,0 -optionsY=SCREEN_CENTER_Y-170 +# are these used? optionsX=SCREEN_CENTER_X-240 +optionsY=SCREEN_CENTER_Y-170 optionsOnCommand=zoomx,0.0;zoomy,0.0;linear,0.5;zoomy,0.7;zoomx,0.7 optionsOffCommand=linear,0.5;zoomx,0.0;zoomy,0.0 +# uses StepsDisplayNet StepsDisplayP1X=SCREEN_CENTER_X-223 StepsDisplayP1Y=SCREEN_CENTER_Y+150 StepsDisplayP1OnCommand=halign,1;zoomx,0.0;zoomy,0.0;linear,0.5;zoomy,1.0;zoomx,1.0 @@ -3781,24 +3924,8 @@ StepsDisplayP2Y=SCREEN_CENTER_Y+150 StepsDisplayP2OnCommand=halign,1;zoomx,0.0;zoomy,0.0;linear,0.5;zoomy,1.0;zoomx,1.0 StepsDisplayP2OffCommand=linear,0.5;zoomx,0.0;zoomy,0.0 -DiffBGX=SCREEN_CENTER_X-60 -DiffBGY=SCREEN_CENTER_Y+160 -DiffBGOnCommand=zoomz,0.0;zoomy,0.0;linear,0.5;zoomy,1.0;zoomx,1.0 -DiffBGOffCommand=linear,0.5;zoomx,0.0;zoomy,0.0 -DiffBGWidth=0 -DiffBGHeight=0 -DiffBGColor=color("0.7,0.7,0.7,0.7") - -DifficultyIconP1OnCommand=visible,false -DifficultyIconP1OffCommand= -DifficultyIconP2OnCommand=visible,false -DifficultyIconP2OffCommand= -DifficultyIconP1X=SCREEN_CENTER_X+50 -DifficultyIconP1Y=SCREEN_BOTTOM-54 -DifficultyIconP2X=SCREEN_CENTER_X+80 -DifficultyIconP2Y=SCREEN_BOTTOM-50 - -HelpText=Screen.String("HelpTextNetSelectMusic"); +[StepsDisplayNet] +Fallback="StepsDisplay" [ScreenNetRoom] Class="ScreenNetRoom" @@ -3828,14 +3955,13 @@ CreateRoomColor=color("0.0,0.9,0.25,1.0") ScrollBarOnCommand=visible,false [RoomWheelItem] -TextOnCommand=zoom,0.6;strokecolor,color("#000000FF") TextX=-110 TextY=-8 -TextWidth=200 -DescX=-100 -DescY=6 -DescOnCommand=zoom,0.4;strokecolor,color("#000000FF") -DescWidth=400 +TextOnCommand=halign,0;zoom,0.6;maxwidth,200;strokecolor,color("#000000FF"); + +DescriptionX=-100 +DescriptionY=6 +DescriptionOnCommand=halign,0;zoom,0.4;maxwidth,400;strokecolor,color("#000000FF") [RoomInfoDisplay] RoomInfoDisplayOnCommand=diffuse,color("1.0,1.0,1.0,1");x,SCREEN_WIDTH+130;y,250;bounceend,0.5;x,SCREEN_WIDTH-160 @@ -3971,6 +4097,7 @@ LifeMeterBarY=SCREEN_TOP+40 LifeMeterBarOnCommand=addy,-60;sleep,2.4;linear,0.2;addy,60 # UseCharacter=true +CharacterName="" CharacterX=SCREEN_CENTER_X-200 CharacterY=SCREEN_CENTER_Y+160 CharacterOnCommand=zoom,20;addy,-SCREEN_WIDTH;sleep,3.0;decelerate,0.4;addy,SCREEN_WIDTH diff --git a/Themes/default/BGAnimations/ScreenEdit background.lua b/Themes/default/BGAnimations/ScreenEdit background.lua index 3573893d03..c24f3b6ab5 100644 --- a/Themes/default/BGAnimations/ScreenEdit background.lua +++ b/Themes/default/BGAnimations/ScreenEdit background.lua @@ -10,6 +10,22 @@ t[#t+1] = Def.ActorFrame { LoadActor( THEME:GetPathB("ScreenWithMenuElements","background/_bg top") ) .. { InitCommand=cmd(scaletoclipped,SCREEN_WIDTH,SCREEN_HEIGHT); }; + Def.Quad{ + InitCommand=cmd(scaletoclipped,SCREEN_WIDTH,SCREEN_HEIGHT;diffuse,color("0.2,0.2,0.2,0")); + OnCommand=function(self) + local topScreen = SCREENMAN:GetTopScreen() + if topScreen then + local screenName = topScreen:GetName() + if screenName == "ScreenEdit" or screenName == "ScreenPractice" then + self:diffusealpha(0.325) + else + self:diffusealpha(0) + end; + end; + end; + EditorShowMessageCommand=cmd(stoptweening;linear,0.5;diffusealpha,0.75); + EditorHideMessageCommand=cmd(stoptweening;linear,0.5;diffusealpha,0.325); + }; }; return t; diff --git a/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua b/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua index 1fd781998c..896a1e535c 100644 --- a/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua +++ b/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua @@ -165,4 +165,11 @@ t[#t+1] = Def.ActorFrame { }; CreateStops(); }; -return t \ No newline at end of file +if PREFSMAN:GetPreference("ScoringType") == 'ScoringType_Custom' then + t[#t+1] = Def.Actor{ + JudgmentMessageCommand = function(self, params) + SpecialScoring[GetUserPref("UserPrefSpecialScoringMode")](params, STATSMAN:GetCurStageStats():GetPlayerStageStats(params.Player)) + end; + }; +end; +return t diff --git a/Themes/default/Graphics/ScreenEvaluation SongInformation.lua b/Themes/default/Graphics/ScreenEvaluation SongInformation.lua new file mode 100644 index 0000000000..35a84238c7 --- /dev/null +++ b/Themes/default/Graphics/ScreenEvaluation SongInformation.lua @@ -0,0 +1,20 @@ +return Def.ActorFrame { + LoadFont("Common Normal") .. { + Name="TextTitle"; + InitCommand=cmd(y,-16.5;zoom,0.875;maxwidth,256/0.875;); + OnCommand=cmd(shadowlength,1); +-- TickCommand=cmd(finishtweening;diffusealpha,0;addx,-10;zoomx,1.25;zoomy,0;decelerate,0.25;diffusealpha,1;addx,10;zoom,1;sleep,0;glow,Color("White");decelerate,0.275;glow,Color("Invisible")); + }; + LoadFont("Common Normal") .. { + Name="TextSubtitle"; + InitCommand=cmd(zoom,0.5;maxwidth,256/0.5); + OnCommand=cmd(shadowlength,1); +-- TickCommand=cmd(finishtweening;diffusealpha,0;addy,-10;addx,10;decelerate,0.25;diffusealpha,1;addy,10;addx,-10); + }; + LoadFont("Common Normal") .. { + Name="TextArtist"; + InitCommand=cmd(y,18;zoom,0.75;maxwidth,256/0.75); + OnCommand=cmd(shadowlength,1;skewx,-0.2); +-- TickCommand=cmd(finishtweening;diffusealpha,0;addy,10;addx,10;decelerate,0.25;diffusealpha,1;addy,-10;addx,-10); + }; +}; \ No newline at end of file diff --git a/Themes/default/Languages/en.ini b/Themes/default/Languages/en.ini index 1ec0d82f11..1fc98403a2 100644 --- a/Themes/default/Languages/en.ini +++ b/Themes/default/Languages/en.ini @@ -60,6 +60,7 @@ LifeDifficulty=Life Difficulty: %s TimingDifficulty=Timing Difficulty: %s [OptionTitles] GamePrefAutoSetStyle=Auto Set Style +UserPrefSpecialScoringMode=Special Scoring Mode GamePrefNotePosition=Note Positions GamePrefComboOnRolls=Rolls Increment Combo GamePrefComboUnderField=Combo Under Field @@ -78,10 +79,33 @@ GamePrefComboUnderField=Determine if the combo should display under the notes or GamePrefAdjustSpeed=Adjust the default scale for speed modifiers. Normal corresponds to the original StepMania 3.9 speed, Fast is twice that rate. UserPrefGameplayShowScore=Show or Hide the score display in gameplay. +UserPrefSpecialScoringMode=Select the scoring mode to be used if the Special scoring type is selected. UserPrefGameplayShowStepsDisplay=Show or Hide the step information display in gameplay. UserPrefShowLotsaOptions=Choose how many lines/rows of options to choose from. &oq;Few&cq; keeps the list to a minimum. &oq;Many&cq; adds various show-off mods. UserPrefLongFail=Choose between the original sm-ssc fail (Long) or the new sm-ssc fail (Short). UserPrefFlashyCombo=Determine if combo flashes should be shown or not. +ScoringType=Defines which scoring method to use. If Special is selected, you can select a Special Scoring Mode in Theme Options. + +Speed=Adjust the speed at which arrows travel toward the targets. +Accel=Change the way arrows approach the targets. +Effect=Change the size or movement of the arrows and/or targets. +Appearance=Control the visibilty of the arrows. +Turn=Change the step choreography by adjusting the position of arrows. +Insert=Add tap notes to the step choreography. +Holds=Turn some tap notes into hold notes. +Mines=Add or remove mine notes. +PlayerAutoPlay=Have the notefield play by itself. +ScoreDisplay=Change the way your score is shown. +ProTiming=Change the way your judgments are shown. +Scroll=Adjust the direction arrows flow to meet the targets. +NoteSkins=Choose a different appearance for the arrows. +Handicap=Removes notes. Using these will invalidate a high score. +Hide=Adjust the visibility of the targets. +Persp=Change the viewing angle of the arrow stream. +Steps=Adjust the difficulty of the steps. +Characters=Dancing buddies. +SaveToProfileHelp=Requires profile or memory card. +MusicRateHelp=Play the music at a faster rate. [StepsListDisplayRow StepsType] Dance_Single=4 Dance_Double=8 @@ -109,8 +133,8 @@ Maniax_Double=MD Techno_Single4=4 Techno_Single5=5 Techno_Single8=8 -Techno_Double4=4 -Techno_Double5=5 +Techno_Double4=D4 +Techno_Double5=D5 Pnm_Five=5 Pnm_Nine=9 Guitar_Five=5 @@ -129,4 +153,7 @@ Explanation-WhereToFind=Launches a web page with information on finding songs fo Explanation-HowToInstall=Launches a web page with song installation instructions. Explanation-AdditionalFolders=If you have other installs of StepMania, you can use the AdditionalFolders preferences to load it into sm-ssc. Explanation-ReloadSongs=Reload the songs. This is required if you've added/changed/deleted songs while sm-ssc is running. -Explanation-Exit=Return to the title menu. \ No newline at end of file +Explanation-Exit=Return to the title menu. + +[OptionNames] +Custom=Special diff --git a/Themes/default/Other/ScreenGameplaySyncMachine music.sm b/Themes/default/Other/ScreenGameplaySyncMachine music.sm index 04761e58f0..4e31da0de3 100644 --- a/Themes/default/Other/ScreenGameplaySyncMachine music.sm +++ b/Themes/default/Other/ScreenGameplaySyncMachine music.sm @@ -96,3 +96,80 @@ 1000 0001 ; + +//---------------dance-single - blank---------------- +#NOTES: + pump-single: + blank: + Beginner: + 1: + 0.302,0.205,0.000,0.000,0.000: + // measure 1 +00000 +00000 +00000 +00000 +, // measure 2 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 3 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 4 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 5 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 6 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 7 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +, // measure 8 +10000 +00001 +10000 +00001 +10000 +00001 +10000 +00001 +; diff --git a/Themes/default/Other/ScreenHowToPlay steps.sm b/Themes/default/Other/ScreenHowToPlay steps.sm index 5cf0a1c9af..3758bfa8de 100644 --- a/Themes/default/Other/ScreenHowToPlay steps.sm +++ b/Themes/default/Other/ScreenHowToPlay steps.sm @@ -6,7 +6,7 @@ // a song file here. #TITLE:ScreenHowToPlay steps; #ARTIST:foo; -#BPMS:0.000=100.000 +#BPMS:0.000=100.000; #STOPS:16=2,18=2,20=2,22=2; #NOTES: diff --git a/Themes/default/Scripts/03 ThemePrefs.lua b/Themes/default/Scripts/03 ThemePrefs.lua index a5889c1d24..526b6ca897 100644 --- a/Themes/default/Scripts/03 ThemePrefs.lua +++ b/Themes/default/Scripts/03 ThemePrefs.lua @@ -21,6 +21,9 @@ function InitUserPrefs() if GetUserPref("UserPrefGameplayShowScore") == nil then SetUserPref("UserPrefGameplayShowScore", false); end; + if GetUserPref("UserPrefSpecialScoringMode") == nil then + SetUserPref("UserPrefSpecialScoringMode", 'DDR 1st Mix'); + end; if GetUserPrefB("UserPrefShowLotsaOptions") == nil then SetUserPref("UserPrefShowLotsaOptions", true); end; @@ -230,6 +233,34 @@ function UserPrefShowLotsaOptions() return t; end +function UserPrefSpecialScoringMode() + local baseChoices = { 'DDR 1stMIX', 'DDR 4thMIX', 'DDR SuperNOVA', 'DDR SuperNOVA 2', 'MIGS' }; --'[SSC] Radar Master' + local t = { + Name = "UserPrefSpecialScoringMode"; + LayoutType = "ShowAllInRow"; + SelectType = "SelectOne"; + OneChoiceForAllPlayers = true; + ExportOnChange = false; + Choices = baseChoices; + LoadSelections = function(self, list, pn) + if ReadPrefFromFile("UserPrefSpecialScoringMode") ~= nil then + local theValue = ReadPrefFromFile("UserPrefSpecialScoringMode"); + local success = false; + for k,v in ipairs(baseChoices) do if v == theValue then list[k] = true success = true break end end; + if success == false then list[1] = true end; + else + WritePrefToFile("UserPrefSpecialScoringMode", 'DDR 1stMIX'); + list[1] = true; + end; + end; + SaveSelections = function(self, list, pn) + for k,v in ipairs(list) do if v then WritePrefToFile("UserPrefSpecialScoringMode", baseChoices[k]) break end end; + end; + }; + setmetatable( t, t ); + return t; +end + function GetDefaultOptionLines() local LineSets = { "1,8,14,2,3,4,5,6,R,7,9,10,11,12,13,15,16,17,18", -- All diff --git a/Themes/default/Scripts/04 SpecialScoring.lua b/Themes/default/Scripts/04 SpecialScoring.lua new file mode 100644 index 0000000000..2f24ebff05 --- /dev/null +++ b/Themes/default/Scripts/04 SpecialScoring.lua @@ -0,0 +1,157 @@ +--Special Scoring types. +local r = {}; +local DisabledScoringModes = { 'DDR Extreme', '[SSC] Radar Master' }; +--the following metatable makes any missing value in a table 0 instead of nil. +local ZeroIfNotFound = { __index = function() return 0 end; }; + +-- Retrieve the amount of taps/holds/rolls involved. Used for some formulas. +function GetTotalItems(radars) + return radars:GetValue('RadarCategory_TapsAndHolds') + + radars:GetValue('RadarCategory_Holds') + + radars:GetValue('RadarCategory_Rolls'); +end; + +-- Determine whether marvelous timing is to be considered. +function IsW1Allowed(tapScore) + return tapScore == 'TapNoteScore_W2' + and (PREFSMAN:GetPreference("AllowW1") ~= 'AllowW1_Never' + or not (GAMESTATE:IsCourseMode() and + PREFSMAN:GetPreference("AllowW1") == 'AllowW1_CoursesOnly')); +end; + +-- Get the radar values directly. The individual steps aren't used much. +function GetDirectRadar(player) + return GAMESTATE:GetCurrentSteps(player):GetRadarValues(player); +end; + +----------------------------------------------------------- +--DDR 1st Mix and 2nd Mix Scoring +----------------------------------------------------------- +r['DDR 1stMIX'] = function(params, pss) + local dCombo = math.floor((pss:GetCurrentCombo()+1)/4); + local bScore = (dCombo^2+1) * 100; + local multLookup = { ['TapNoteScore_W1']=3, ['TapNoteScore_W2']=3, ['TapNoteScore_W3']=1 }; + setmetatable(multLookup, ZeroIfNotFound); + --if score increases above the boundaries of a 32-bit signed + --(about 2.15 billion), it stops increasing. Conveniently, + --1st Mix clamped score as well. + pss:SetScore(clamp(pss:GetScore()+(bScore*multLookup[params.TapNoteScore]),0,999999999)); +end; +----------------------------------------------------------- +--DDR 4th Mix/Extra Mix/Konamix/GB3/DDRPC Scoring +----------------------------------------------------------- +r['DDR 4thMIX'] = function(params, pss) + local scoreLookupTable = { ['TapNoteScore_W1']=777, ['TapNoteScore_W2']=777, ['TapNoteScore_W3']=555 }; + setmetatable(scoreLookupTable, ZeroIfNotFound); + local comboBonusForThisStep = (pss:GetCurrentCombo()+1)*333; + pss:SetScore(clamp(pss:GetScore()+scoreLookupTable[params.TapNoteScore]+(scoreLookupTable[params.TapNoteScore] and comboBonusForThisStep or 0),0,999999999)); +end; +----------------------------------------------------------- +--DDR MAX2/Extreme Scoring +--This scoring system doesn't work and is locked out. +----------------------------------------------------------- +r['DDR Extreme'] = function(params, pss) + local judgmentBase = { + ['TapNoteScore_W1'] = 10, + ['TapNoteScore_W2'] = 9, + ['TapNoteScore_W3'] = 5 + }; + setmetatable(judgmentBase, ZeroIfNotFound); + local steps = GAMESTATE:GetCurrentSteps(params.Player); + local radarValues = steps:GetRadarValues(params.Player); + local baseScore = (steps:IsAnEdit() and + 5 or steps:GetMeter()) * 10000000; + local currentStep = 0; -- TODO: Get current step/hold. + local totalItems = GetTotalItems(radarValues); + local singleStep = (1 + totalItems) * totalItems / 2; + local stepLast = math.floor(baseScore / singleStep) * currentStep; + local judgeScore = 0; + if (params.HoldNoteScore == 'HoldNoteScore_Held') then + judgeScore = judgmentBase['TapNoteScore_W1']; + else + judgeScore = judgmentBase[params.TapNoteScore]; + if (IsW1Allowed(params.TapNoteScore)) then + judgeScore = judgmentBase['TapNoteScore_W1']; + end; + end; + local stepScore = judgeScore * stepLast; + + pss:SetScore(pss:GetScore() + stepScore); +end; +----------------------------------------------------------- +--DDR SuperNOVA(-esque) scoring +----------------------------------------------------------- +r['DDR SuperNOVA'] = function(params, pss) + local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 }; + setmetatable(multLookup, ZeroIfNotFound); + local radarValues = GetDirectRadar(params.Player); + local totalItems = GetTotalItems(radarValues); + local buildScore = (10000000 / totalItems * multLookup[params.TapNoteScore]) + (10000000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0)); + pss:SetScore(pss:GetScore() + math.round(buildScore)); +end; +----------------------------------------------------------- +--DDR SuperNOVA 2(-esque) scoring +----------------------------------------------------------- +r['DDR SuperNOVA 2'] = function(params, pss) + local multLookup = { ['TapNoteScore_W1'] = 1, ['TapNoteScore_W2'] = 1, ['TapNoteScore_W3'] = 0.5 }; + setmetatable(multLookup, ZeroIfNotFound); + local radarValues = GetDirectRadar(params.Player); + local totalItems = GetTotalItems(radarValues); + local buildScore = (100000 / totalItems * multLookup[params.TapNoteScore] - (IsW1Allowed(params.TapNoteScore) and 10 or 0)) + (100000 / totalItems * (params.HoldNoteScore == 'HoldNoteScore_Held' and 1 or 0)); + pss:SetScore(pss:GetScore() + (math.round(buildScore) * 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. +----------------------------------------------------------- +r['[SSC] Radar Master'] = function(params, pss) + local masterTable = { + ['RadarCategory_Stream'] = 0, + ['RadarCategory_Voltage'] = 0, + ['RadarCategory_Air'] = 0, + ['RadarCategory_Freeze'] = 0, + ['RadarCategory_Chaos'] = 0 + }; + local totalRadar = 0; + local finalScore = 0; + for k,v in pairs(masterTable) do + local firstRadar = GetDirectRadar(params.Player):GetValue(k); + if firstRadar == 0 then + masterTable[k] = nil; + else + masterTable[k] = firstRadar; + totalRadar = totalRadar + firstRadar; + end; + end; + --two loops are needed because we need to calculate totalRadar + --to actually calculate any part of the score + for k,v in pairs(masterTable) do + local curPortion = pss:GetRadarActual():GetValue(k) / v; + finalScore = finalScore + curPortion*(500000000*(v/totalRadar)); + end; + pss:SetScore(finalScore); +end; +------------------------------------------------------------ +--Marvelous Incorporated Grading System (or MIGS for short) +--basically like DP scoring with locked DP values +------------------------------------------------------------ +r['MIGS'] = function(params,pss) + local curScore = 0; + local tapScoreTable = { ['TapNoteScore_W1'] = 3, ['TapNoteScore_W2'] = 2, ['TapNoteScore_W3'] = 1, ['TapNoteScore_W5'] = -4, ['TapNoteScore_Miss'] = -8 }; + for k,v in pairs(tapScoreTable) do + curScore = curScore + ( pss:GetTapNoteScores(k) * v ); + end; + curScore = curScore + ( pss:GetHoldNoteScores('HoldNoteScore_Held') * 6 ); + pss:SetScore(clamp(curScore,0,math.huge)); +end; +SpecialScoring = {}; +setmetatable(SpecialScoring, { + __metatable = { "Letting you change the metatable sort of defeats the purpose." }; + __index = function(tbl, key) + for v in ivalues(DisabledScoringModes) do + if key == v then return r['DDR 1stMIX']; end; + end; + return r[key]; + end; + } +); diff --git a/Themes/default/metrics.ini b/Themes/default/metrics.ini index 7b9a1b9238..a55b777546 100644 --- a/Themes/default/metrics.ini +++ b/Themes/default/metrics.ini @@ -827,10 +827,10 @@ ItemsLongRowSharedX=SCREEN_CENTER_X [ScreenOptionsTheme] Fallback="ScreenOptionsServiceChild" -LineNames="gNotePos,gAuto,gScore,gSDisp,gOpts,gLongFail,gComboUnderField,FlashyCombo,AdjustSpeed" -#,gAuto +LineNames="gNotePos,gAuto,gScore,gSScore,gSDisp,gOpts,gLongFail,gComboUnderField,FlashyCombo,AdjustSpeed" LinegNotePos="lua,GamePrefNotePosition()" LinegScore="lua,UserPrefGameplayShowScore()" +LinegSScore="lua,UserPrefSpecialScoringMode()" LinegSDisp="lua,UserPrefGameplayShowStepsDisplay()" LinegOpts="lua,UserPrefShowLotsaOptions()" LinegAuto="lua,GamePrefAutoSetStyle()" @@ -1755,7 +1755,7 @@ PercentP1Y=SCREEN_TOP+320 PercentP1OnCommand=visible,false PercentP1OffCommand= # -PercentP2X=SCREEN_CENTER_X-160 +PercentP2X=SCREEN_CENTER_X+160 PercentP2Y=SCREEN_TOP+320 PercentP2OnCommand=visible,false PercentP2OffCommand= @@ -1831,6 +1831,7 @@ ComboGraphP2OffCommand= # MachineRecordP1X=SCREEN_CENTER_X-220 #MachineRecordP1Y=SCREEN_BOTTOM-156 + MachineRecordP1Y=SCREEN_TOP+146 MachineRecordP1OnCommand= MachineRecordP1OffCommand= @@ -2056,4 +2057,25 @@ ChoiceExit="screen,"..Branch.TitleMenu()..";text,"..Screen.String("Exit") DefaultChoice="WhereToFind" OptionOrderUp="5:4,4:3,3:2,2:1,1:5" -OptionOrderDown="1:2,2:3,3:4,4:5,5:1" \ No newline at end of file +OptionOrderDown="1:2,2:3,3:4,4:5,5:1" +[CustomScoring] +# So special scoring works properly, we zero this out +ComboAboveThresholdAddsToScoreBonus=0 +ComboScoreBonusThreshold=0 +ComboScoreBonusValue=0 +ComboMultiplier=0 +DoubleNoteScoreMultiplier=0 +TripleNoteScoreMultiplier=0 +QuadOrHigherNoteScoreMultiplier=0 +PointsW1=0 +PointsW2=0 +PointsW3=0 +PointsW4=0 +PointsW5=0 +PointsMiss=0 +PointsHitMine=0 +PointsCheckpointHit=0 +PointsCheckpointMiss=0 +PointsNone=0 +PointsHoldHeld=0 +PointsHoldLetGo=0 diff --git a/Themes/rsr/BGAnimations/ScreenWithMenuElements background/VOL1-29-NTSC.mpg b/Themes/rsr/BGAnimations/ScreenWithMenuElements background/VOL1-29-NTSC.mpg new file mode 100644 index 0000000000..6f579ea520 Binary files /dev/null and b/Themes/rsr/BGAnimations/ScreenWithMenuElements background/VOL1-29-NTSC.mpg differ diff --git a/Themes/rsr/BGAnimations/ScreenWithMenuElements background/default.lua b/Themes/rsr/BGAnimations/ScreenWithMenuElements background/default.lua new file mode 100644 index 0000000000..d3ebaea695 --- /dev/null +++ b/Themes/rsr/BGAnimations/ScreenWithMenuElements background/default.lua @@ -0,0 +1,62 @@ +local t = Def.ActorFrame {}; +-- +--[[ local tGridSizeMajor = { 32, 32 }; +local tGridSizeMinor = { 16, 16 }; +local function CreateDebugGrid() + local t = Def.ActorFrame {}; + local numX = math.ceil(SCREEN_WIDTH/tGridSizeMajor[1]) + local numY = math.ceil(SCREEN_HEIGHT/tGridSizeMajor[2]) + local offset = ( math.ceil(SCREEN_WIDTH/tGridSizeMajor[1]) - SCREEN_WIDTH ) + SCREEN_WIDTH; + for a=1,numY do + for b=1,numX do + t[#t+1] = Def.Quad { + InitCommand=cmd(x,b*tGridSizeMajor[1]-(tGridSizeMajor[1]/2);y,a*tGridSizeMajor[2]-(tGridSizeMajor[2]/2)); + OnCommand=cmd(zoomto,tGridSizeMajor[1]-2,tGridSizeMajor[2]-2;diffuse,color("1,1,1,0.25")); + }; + end; + end; + return t +end --]] + +-- +t[#t+1] = Def.ActorFrame { + InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y); + LoadActor("VOL1-29-NTSC") .. { + InitCommand=cmd(scaletoclipped,SCREEN_WIDTH,SCREEN_HEIGHT); + OnCommand=cmd(diffusealpha,0.75); + }; +}; +-- +local bShow = 0; +t[#t+1] = Def.ActorFrame { + InitCommand=cmd(visible,false); + ToggleConsoleDisplayMessageCommand=function(self) + bShow = 1 - bShow; + self:visible( bShow == 1 ); + end; + -- Grid + LoadActor("_32") .. { + InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;zoomto,SCREEN_WIDTH,SCREEN_HEIGHT;customtexturerect,0,0,SCREEN_WIDTH/32,SCREEN_HEIGHT/32); + OnCommand=cmd(diffuse,color("0,0,0,0.5")); + }; + LoadActor("_16") .. { + InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;zoomto,SCREEN_WIDTH,SCREEN_HEIGHT;customtexturerect,0,0,SCREEN_WIDTH/16,SCREEN_HEIGHT/16); + OnCommand=cmd(diffuse,color("1,1,1,0.125")); + }; +--[[ LoadActor("_8") .. { + InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y;zoomto,SCREEN_WIDTH,SCREEN_HEIGHT;customtexturerect,0,0,SCREEN_WIDTH/8,SCREEN_HEIGHT/8); + OnCommand=cmd(diffuse,color("#00BFE833")); + }; --]] + -- Left + Def.Quad { + InitCommand=cmd(horizalign,left;x,SCREEN_LEFT;y,SCREEN_CENTER_Y;zoomto,16,SCREEN_HEIGHT); + OnCommand=cmd(diffuse,color("0,0,0,0.5")); + }; + -- Right + Def.Quad { + InitCommand=cmd(horizalign,right;x,SCREEN_RIGHT;y,SCREEN_CENTER_Y;zoomto,16,SCREEN_HEIGHT); + OnCommand=cmd(diffuse,color("0,0,0,0.5")); + }; +}; +-- +return t \ No newline at end of file diff --git a/Themes/rsr/BGAnimations/ScreenWithMenuElements decorations/default.lua b/Themes/rsr/BGAnimations/ScreenWithMenuElements decorations/default.lua new file mode 100644 index 0000000000..d69d08b791 --- /dev/null +++ b/Themes/rsr/BGAnimations/ScreenWithMenuElements decorations/default.lua @@ -0,0 +1,7 @@ +-- Loads up a slew of objects to load into the screen, like how 3.9 does. +-- I prefer to keep these optional, incase another screen wants to hide +-- these elements. +local t = Def.ActorFrame {}; +t[#t+1] = StandardDecorationFromFileOptional("Header","Header"); +t[#t+1] = StandardDecorationFromFileOptional("Footer","Footer"); +return t \ No newline at end of file diff --git a/Themes/rsr/Graphics/MusicWheelItem Song ColorPart.lua b/Themes/rsr/Graphics/MusicWheelItem Song ColorPart.lua new file mode 100644 index 0000000000..edfa6611f8 --- /dev/null +++ b/Themes/rsr/Graphics/MusicWheelItem Song ColorPart.lua @@ -0,0 +1,14 @@ +return Def.ActorFrame { + Def.Quad { + InitCommand=cmd(x,-128+4;zoomto,4,46); +-- OnCommand=cmd(diffuse,color("0,0,0,0.5")); + }; +--[[ Def.Quad { + InitCommand=cmd(x,-128+16+6;zoomto,32,46); +-- OnCommand=cmd(faderight,1;diffusealpha,0.5); + }; --]] +--[[ Def.Quad { + InitCommand=cmd(x,2;y,23;zoomto,320,1); +-- OnCommand=cmd(diffuse,color("0,0,0,0.5")); + }; --]] +}; \ No newline at end of file diff --git a/Themes/rsr/Graphics/MusicWheelItem Song NormalPart.lua b/Themes/rsr/Graphics/MusicWheelItem Song NormalPart.lua new file mode 100644 index 0000000000..60de25400c --- /dev/null +++ b/Themes/rsr/Graphics/MusicWheelItem Song NormalPart.lua @@ -0,0 +1,6 @@ +return Def.ActorFrame { + Def.Quad { + InitCommand=cmd(x,4;zoomto,256-4,46); + OnCommand=cmd(diffuse,color("0,0,0,0.5")); + }; +}; \ No newline at end of file diff --git a/Themes/rsr/Graphics/ScreenTitleMenu scroll.lua b/Themes/rsr/Graphics/ScreenTitleMenu scroll.lua new file mode 100644 index 0000000000..84e2da8460 --- /dev/null +++ b/Themes/rsr/Graphics/ScreenTitleMenu scroll.lua @@ -0,0 +1,11 @@ +local gc = Var("GameCommand"); + +local t = Def.ActorFrame {}; + +t[#t+1] = LoadFont("Common Normal") .. { + Text=gc:GetText(); +}; + +t.GainFocusCommand=cmd(diffusealpha,1); +t.LoseFocusCommand=cmd(diffusealpha,0.5); +return t; \ No newline at end of file diff --git a/Themes/rsr/Graphics/ScreenWithMenuElements footer/default.lua b/Themes/rsr/Graphics/ScreenWithMenuElements footer/default.lua new file mode 100644 index 0000000000..5dae6eeb87 --- /dev/null +++ b/Themes/rsr/Graphics/ScreenWithMenuElements footer/default.lua @@ -0,0 +1,9 @@ +local t = Def.ActorFrame {}; +t[#t+1] = Def.ActorFrame { + InitCommand=cmd(y,-64); + Def.Quad { + InitCommand=cmd(vertalign,top;zoomto,SCREEN_WIDTH-32,2); + OnCommand=cmd(diffusealpha,0.5); + }; +}; +return t \ No newline at end of file diff --git a/Themes/rsr/Graphics/ScreenWithMenuElements header/default.lua b/Themes/rsr/Graphics/ScreenWithMenuElements header/default.lua new file mode 100644 index 0000000000..1795dc8c31 --- /dev/null +++ b/Themes/rsr/Graphics/ScreenWithMenuElements header/default.lua @@ -0,0 +1,35 @@ +local t = Def.ActorFrame {}; +t[#t+1] = Def.ActorFrame { + InitCommand=cmd(y,48); + Def.Quad { + InitCommand=cmd(vertalign,bottom;zoomto,SCREEN_WIDTH-32,2); + OnCommand=cmd(diffusealpha,0.5); + }; +}; +t[#t+1] = Def.ActorFrame { Name="MenuTimerDecoration"; + InitCommand=cmd(y,48); + LoadFont("Common Normal") .. { + Text="TIME"; + InitCommand=cmd(vertalign,bottom;horizalign,right;x,SCREEN_CENTER_X-16;y,-4.5); + OnCommand=cmd(zoom,0.5); + }; +--[[ LoadFont("Common Normal") .. { + Text="99"; + InitCommand=cmd(vertalign,bottom;horizalign,right;x,SCREEN_CENTER_X-64;y,-4.5); + OnCommand=cmd(); + }; --]] +}; +t[#t+1] = Def.ActorFrame { Name="HeaderTextDecoration"; + InitCommand=cmd(y,48); + LoadFont("Common Normal") .. { + Text="SELECT"; + InitCommand=cmd(vertalign,bottom;horizalign,left;x,-SCREEN_CENTER_X+16;y,-4.5); + OnCommand=cmd(zoom,0.5); + }; + LoadFont("Common Normal") .. { + Text="OPTIONS"; + InitCommand=cmd(vertalign,bottom;horizalign,left;x,-SCREEN_CENTER_X+64;y,-4.5); + OnCommand=cmd(); + }; +}; +return t \ No newline at end of file diff --git a/Themes/rsr/Sounds/_Music menu.redir b/Themes/rsr/Sounds/_Music menu.redir new file mode 100644 index 0000000000..c29cb1da10 --- /dev/null +++ b/Themes/rsr/Sounds/_Music menu.redir @@ -0,0 +1 @@ +_Music title \ No newline at end of file diff --git a/Themes/rsr/Sounds/_Music title (loop).ogg b/Themes/rsr/Sounds/_Music title (loop).ogg new file mode 100644 index 0000000000..d1ff738f07 Binary files /dev/null and b/Themes/rsr/Sounds/_Music title (loop).ogg differ diff --git a/Themes/rsr/Sounds/_Music title (loop).sm b/Themes/rsr/Sounds/_Music title (loop).sm new file mode 100644 index 0000000000..283865a6c9 --- /dev/null +++ b/Themes/rsr/Sounds/_Music title (loop).sm @@ -0,0 +1,5 @@ +#TITLE:Break The Sabbath; +#OFFSET:0.000; +#BPMS:0.000=140.000; +#STOPS:; + diff --git a/Themes/rsr/ThemeInfo.ini b/Themes/rsr/ThemeInfo.ini new file mode 100644 index 0000000000..9215ef43e2 --- /dev/null +++ b/Themes/rsr/ThemeInfo.ini @@ -0,0 +1,3 @@ +[ThemeInfo] +DisplayName=Real Stepping Roots +Author=Midiman \ No newline at end of file diff --git a/Themes/rsr/library.txt b/Themes/rsr/library.txt new file mode 100644 index 0000000000..1b6b60c1e1 --- /dev/null +++ b/Themes/rsr/library.txt @@ -0,0 +1,11 @@ +=== +COLORS +==== + BACKGROUND +==== + Clear #000000 (Black) + Light #646464 (Grey) + Primary #007cd4 (Slate Blue) + Secondary #a4005d (Slate Purple) + the base is black (#000000) +=== \ No newline at end of file diff --git a/Themes/rsr/metrics.ini b/Themes/rsr/metrics.ini new file mode 100644 index 0000000000..d46f998386 --- /dev/null +++ b/Themes/rsr/metrics.ini @@ -0,0 +1,39 @@ +[Global] +FallbackTheme=_fallback +[ScreenWithMenuElements] +ShowHeader=true +HeaderX=SCREEN_CENTER_X +HeaderY=SCREEN_TOP +HeaderOnCommand= +HeaderOffCommand= +# +ShowFooter=true +FooterX=SCREEN_CENTER_X +FooterY=SCREEN_BOTTOM +FooterOnCommand= +FooterOffCommand= +# +TimerX=SCREEN_WIDTH-64 +TimerY=SCREEN_TOP+48-4.5 +TimerOnCommand= +TimerOffCommand= +[MenuTimer] +Text1OnCommand=stopeffect;stoptweening;vertalign,bottom;horizalign,right +Text1FormatFunction=function(fSeconds) \ + return string.format("%0.1f", fSeconds); \ +end +FrameOnCommand= +Warning10Command=diffuseshift;effectperiod,1;effectcolor2,Color("Red");effectcolor1,color("0.5,0,0,1"); +#~ Warning10Command=%function(self) \ + #~ MESSAGEMAN:Broadcast("TimerWarning"); \ + #~ cmd(diffuseshift;effectperiod,1;effectcolor2,Color("Red");effectcolor1,color("0.5,0,0,1"))(self); \ +#~ end; +[ScreenTitleMenu] +ShowHeader=true +ShowFooter=true +[ScreenSelectMusic] +MusicWheelX=SCREEN_RIGHT-128-18 +MusicWheelOnCommand=draworder,-1 +[MusicWheel] +ItemTransformFunction=function(self,offsetFromCenter,itemIndex,numItems) self:x( (1-math.cos(offsetFromCenter/math.pi))*0 ); self:y( offsetFromCenter*48 ); end +NumWheelItems=13 \ No newline at end of file diff --git a/Themes/rsr/todo.txt b/Themes/rsr/todo.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Themes/themekit/Graphics/ScreenTitleMenu scroll.lua b/Themes/themekit/Graphics/ScreenTitleMenu scroll.lua index 0e5fbb4711..13448248c9 100644 --- a/Themes/themekit/Graphics/ScreenTitleMenu scroll.lua +++ b/Themes/themekit/Graphics/ScreenTitleMenu scroll.lua @@ -4,8 +4,10 @@ local t = Def.ActorFrame {}; t[#t+1] = LoadFont("Common Normal") .. { Text=gc:GetText(); + InitCommand=THEME:GetMetric(Var "LoadingScreen","ScrollerItemInitCommand"); + GainFocusCommand=THEME:GetMetric(Var "LoadingScreen","ScrollerItemGainFocusCommand"); + LoseFocusCommand=THEME:GetMetric(Var "LoadingScreen","ScrollerItemGainFocusCommand"); }; -t.GainFocusCommand=cmd(visible,true); -t.LoseFocusCommand=cmd(visible,false); + return t; \ No newline at end of file diff --git a/Themes/themekit/metrics.ini b/Themes/themekit/metrics.ini index 2798416bf2..0606f0540b 100644 --- a/Themes/themekit/metrics.ini +++ b/Themes/themekit/metrics.ini @@ -42,9 +42,18 @@ FooterOffCommand= [ScreenTitleMenu] ScrollerY=SCREEN_CENTER_Y*1.5 ScrollerOnCommand= +# New: Load ScrollerItem SpacingX/Y ScrollerTransform=function(self,offset,itemIndex,numItems) \ - self:y((0)*(itemIndex-(numItems-1)/2)); \ + local fSpaceX = THEME:GetMetric( Var "LoadingScreen","ScrollerItemSpacingX"); \ + local fSpaceY = THEME:GetMetric( Var "LoadingScreen","ScrollerItemSpacingY"); \ + self:x( (i-1) * fSpaceX ); \ + self:y( (i-1) * fSpaceY ); \ end; - +# New: Adjust menu items +ScrollerItemSpacingX=0 +ScrollerItemSpacingY=24 +ScrollerItemInitCommand=zoom,1;shadowlength,1 +ScrollerItemGainFocusCommand=finishtweening;linear,0.125;zoom,1.25 +ScrollerItemLoseFocusCommand=finishtweening;linear,0.125;zoom,1 [ScreenSelectMusic] diff --git a/Utils/build.sh b/Utils/build.sh index f896306a91..a670f1a799 100755 --- a/Utils/build.sh +++ b/Utils/build.sh @@ -2,6 +2,12 @@ verbose=0 msg= +notify=0 +if which notify-send >/dev/null 2>&1; then + #Comment the following line out to disable notify. + notify=1 +fi + message () { msg=$1 if [ $verbose -gt 0 ]; then @@ -9,6 +15,9 @@ message () { else echo -n "$msg..." fi + if [ $notify -gt 0 ]; then + notify-send "sm-ssc build script" "$msg..." + fi } success () { @@ -17,6 +26,9 @@ success () { else echo okay. fi + if [ $notify -gt 0 ]; then + notify send "sm-ssc build script" "$msg...okay." + fi } failure () { @@ -30,6 +42,9 @@ failure () { else echo failed$error fi + if [ $notify -gt 0 ]; then + notify-send "sm-ssc build script failed" "$msg...failed$error" + fi; echo "Consider passing --verbose to $0. Pass --help for details." exit 1 } @@ -64,10 +79,10 @@ usage () { } version () { - echo 'build.sh (StepMania) 2.61a' + echo 'build.sh (StepMania) 2.62' echo 'Copyright (C) 2006-2009 Steve Checkoway' echo 'StepMania is Copyright (C) 2001-2009 Chris Danford et al.' - echo 'sm-ssc is Copyright (C) 2009-2010 the spinal shark collective' + echo 'sm-ssc is Copyright (C) 2009-2011 the spinal shark collective' exit 0 } @@ -103,7 +118,7 @@ while [ $# -gt 0 ]; do *) usage 1 ;; esac done -version=0.6 +version=0.6.1 ffmpeg=ffmpeg-$version directory=http://ffmpeg.org/releases if [ ! -d $ffmpeg ]; then diff --git a/Xcode/stepmania.xcodeproj/project.pbxproj b/Xcode/stepmania.xcodeproj/project.pbxproj index afcc62122b..178717c95a 100644 --- a/Xcode/stepmania.xcodeproj/project.pbxproj +++ b/Xcode/stepmania.xcodeproj/project.pbxproj @@ -23,6 +23,10 @@ /* Begin PBXBuildFile section */ 1215D7A208C6559A00B87D8B /* ScreenGameplayNormal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1215D7A008C6559A00B87D8B /* ScreenGameplayNormal.cpp */; }; + 2BA7925E1304F20D002BD8E1 /* NotesLoaderSSC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2BA7925A1304F20D002BD8E1 /* NotesLoaderSSC.cpp */; }; + 2BA7925F1304F20D002BD8E1 /* NotesLoaderSSC.h in Headers */ = {isa = PBXBuildFile; fileRef = 2BA7925B1304F20D002BD8E1 /* NotesLoaderSSC.h */; }; + 2BA792601304F20D002BD8E1 /* NotesWriterSSC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2BA7925C1304F20D002BD8E1 /* NotesWriterSSC.cpp */; }; + 2BA792611304F20D002BD8E1 /* NotesWriterSSC.h in Headers */ = {isa = PBXBuildFile; fileRef = 2BA7925D1304F20D002BD8E1 /* NotesWriterSSC.h */; }; 3659B56F0F902143002B6B68 /* CommandLineActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3659B56D0F902143002B6B68 /* CommandLineActions.cpp */; }; 3659B5700F902143002B6B68 /* CommandLineActions.h in Headers */ = {isa = PBXBuildFile; fileRef = 3659B56E0F902143002B6B68 /* CommandLineActions.h */; }; 367D575B0EDE56F200B46814 /* ScreenHighScores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 367D57590EDE56F200B46814 /* ScreenHighScores.cpp */; }; @@ -157,11 +161,9 @@ AA29CD810558741A00961A51 /* FadingBanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE8A04770E7C005F316C /* FadingBanner.cpp */; }; AA29CD820558741A00961A51 /* GradeDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE8C04770E7C005F316C /* GradeDisplay.cpp */; }; AA29CD840558741A00961A51 /* GrooveRadar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9004770E7C005F316C /* GrooveRadar.cpp */; }; - AA29CD850558741A00961A51 /* GroupList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9204770E7C005F316C /* GroupList.cpp */; }; AA29CD860558741A00961A51 /* HelpDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9404770E7C005F316C /* HelpDisplay.cpp */; }; AA29CD890558741A00961A51 /* MenuTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9A04770E7C005F316C /* MenuTimer.cpp */; }; AA29CD8A0558741A00961A51 /* MeterDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9C04770E7C005F316C /* MeterDisplay.cpp */; }; - AA29CD8C0558741A00961A51 /* MusicList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFEA004770E7C005F316C /* MusicList.cpp */; }; AA29CD8E0558741A00961A51 /* MusicWheel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFEA404770E7C005F316C /* MusicWheel.cpp */; }; AA29CD8F0558741A00961A51 /* MusicWheelItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFEA604770E7C005F316C /* MusicWheelItem.cpp */; }; AA29CD920558741A00961A51 /* OptionsCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFEAC04770E7C005F316C /* OptionsCursor.cpp */; }; @@ -373,11 +375,9 @@ AA40D1F809A08D650068C0D5 /* FadingBanner.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFE8B04770E7C005F316C /* FadingBanner.h */; }; AA40D1F909A08D650068C0D5 /* GradeDisplay.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFE8D04770E7C005F316C /* GradeDisplay.h */; }; AA40D1FA09A08D650068C0D5 /* GrooveRadar.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFE9104770E7C005F316C /* GrooveRadar.h */; }; - AA40D1FB09A08D650068C0D5 /* GroupList.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFE9304770E7C005F316C /* GroupList.h */; }; AA40D1FC09A08D650068C0D5 /* HelpDisplay.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFE9504770E7C005F316C /* HelpDisplay.h */; }; AA40D1FD09A08D650068C0D5 /* MenuTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFE9B04770E7C005F316C /* MenuTimer.h */; }; AA40D1FE09A08D650068C0D5 /* MeterDisplay.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFE9D04770E7C005F316C /* MeterDisplay.h */; }; - AA40D20009A08D650068C0D5 /* MusicList.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFEA104770E7C005F316C /* MusicList.h */; }; AA40D20209A08D650068C0D5 /* MusicWheel.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFEA504770E7C005F316C /* MusicWheel.h */; }; AA40D20309A08D650068C0D5 /* MusicWheelItem.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFEA704770E7C005F316C /* MusicWheelItem.h */; }; AA40D20609A08D650068C0D5 /* OptionsCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = AA6EFEAD04770E7C005F316C /* OptionsCursor.h */; }; @@ -711,11 +711,9 @@ AA40D3BA09A08D650068C0D5 /* FadingBanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE8A04770E7C005F316C /* FadingBanner.cpp */; }; AA40D3BB09A08D650068C0D5 /* GradeDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE8C04770E7C005F316C /* GradeDisplay.cpp */; }; AA40D3BC09A08D650068C0D5 /* GrooveRadar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9004770E7C005F316C /* GrooveRadar.cpp */; }; - AA40D3BD09A08D650068C0D5 /* GroupList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9204770E7C005F316C /* GroupList.cpp */; }; AA40D3BE09A08D650068C0D5 /* HelpDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9404770E7C005F316C /* HelpDisplay.cpp */; }; AA40D3BF09A08D650068C0D5 /* MenuTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9A04770E7C005F316C /* MenuTimer.cpp */; }; AA40D3C009A08D650068C0D5 /* MeterDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFE9C04770E7C005F316C /* MeterDisplay.cpp */; }; - AA40D3C209A08D650068C0D5 /* MusicList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFEA004770E7C005F316C /* MusicList.cpp */; }; AA40D3C409A08D650068C0D5 /* MusicWheel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFEA404770E7C005F316C /* MusicWheel.cpp */; }; AA40D3C509A08D650068C0D5 /* MusicWheelItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFEA604770E7C005F316C /* MusicWheelItem.cpp */; }; AA40D3C809A08D650068C0D5 /* OptionsCursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA6EFEAC04770E7C005F316C /* OptionsCursor.cpp */; }; @@ -1633,6 +1631,19 @@ AAFF41A60F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h in Headers */ = {isa = PBXBuildFile; fileRef = AAFF41A20F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.h */; }; EE2153A910A75BEE0074B01B /* NotesLoaderPMS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE2153A710A75BEE0074B01B /* NotesLoaderPMS.cpp */; }; EE2153AA10A75BEE0074B01B /* NotesLoaderPMS.h in Headers */ = {isa = PBXBuildFile; fileRef = EE2153A810A75BEE0074B01B /* NotesLoaderPMS.h */; }; + EE906F6612BF3A1B00146C96 /* ScreenInstallOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE906F6412BF3A1B00146C96 /* ScreenInstallOverlay.cpp */; }; + EE906F6712BF3A1B00146C96 /* ScreenInstallOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = EE906F6512BF3A1B00146C96 /* ScreenInstallOverlay.h */; }; + EE906F7712BF3A6900146C96 /* json_batchallocator.h in Headers */ = {isa = PBXBuildFile; fileRef = EE906F7012BF3A6900146C96 /* json_batchallocator.h */; }; + EE906F7812BF3A6900146C96 /* json_internalarray.inl in Resources */ = {isa = PBXBuildFile; fileRef = EE906F7112BF3A6900146C96 /* json_internalarray.inl */; }; + EE906F7912BF3A6900146C96 /* json_internalmap.inl in Resources */ = {isa = PBXBuildFile; fileRef = EE906F7212BF3A6900146C96 /* json_internalmap.inl */; }; + EE906F7A12BF3A6900146C96 /* json_reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE906F7312BF3A6900146C96 /* json_reader.cpp */; }; + EE906F7B12BF3A6900146C96 /* json_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE906F7412BF3A6900146C96 /* json_value.cpp */; }; + EE906F7C12BF3A6900146C96 /* json_valueiterator.inl in Resources */ = {isa = PBXBuildFile; fileRef = EE906F7512BF3A6900146C96 /* json_valueiterator.inl */; }; + EE906F7D12BF3A6900146C96 /* json_writer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE906F7612BF3A6900146C96 /* json_writer.cpp */; }; + EE906F8212BF3AF800146C96 /* JsonUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE906F8012BF3AF800146C96 /* JsonUtil.cpp */; }; + EE906F8312BF3AF800146C96 /* JsonUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = EE906F8112BF3AF800146C96 /* JsonUtil.h */; }; + EE906F8A12BF3C7C00146C96 /* FileDownload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EE906F8812BF3C7C00146C96 /* FileDownload.cpp */; }; + EE906F8B12BF3C7C00146C96 /* FileDownload.h in Headers */ = {isa = PBXBuildFile; fileRef = EE906F8912BF3C7C00146C96 /* FileDownload.h */; }; EEA7C84310A805A300082E7B /* ScreenPackagesSSC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EEA7C84110A805A300082E7B /* ScreenPackagesSSC.cpp */; }; EEA7C84410A805A300082E7B /* ScreenPackagesSSC.h in Headers */ = {isa = PBXBuildFile; fileRef = EEA7C84210A805A300082E7B /* ScreenPackagesSSC.h */; }; EEC7863F0E58208B00F559BC /* StepsDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EEC7863D0E58208B00F559BC /* StepsDisplay.cpp */; }; @@ -1761,6 +1772,10 @@ 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 = ""; }; + 2BA7925A1304F20D002BD8E1 /* NotesLoaderSSC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NotesLoaderSSC.cpp; path = ../src/NotesLoaderSSC.cpp; sourceTree = SOURCE_ROOT; }; + 2BA7925B1304F20D002BD8E1 /* NotesLoaderSSC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NotesLoaderSSC.h; path = ../src/NotesLoaderSSC.h; sourceTree = SOURCE_ROOT; }; + 2BA7925C1304F20D002BD8E1 /* NotesWriterSSC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NotesWriterSSC.cpp; path = ../src/NotesWriterSSC.cpp; sourceTree = SOURCE_ROOT; }; + 2BA7925D1304F20D002BD8E1 /* NotesWriterSSC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NotesWriterSSC.h; path = ../src/NotesWriterSSC.h; sourceTree = SOURCE_ROOT; }; 3659B56D0F902143002B6B68 /* CommandLineActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommandLineActions.cpp; sourceTree = ""; }; 3659B56E0F902143002B6B68 /* CommandLineActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommandLineActions.h; sourceTree = ""; }; 367D57590EDE56F200B46814 /* ScreenHighScores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScreenHighScores.cpp; path = ../src/ScreenHighScores.cpp; sourceTree = SOURCE_ROOT; }; @@ -2152,16 +2167,12 @@ AA6EFE8D04770E7C005F316C /* GradeDisplay.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = GradeDisplay.h; path = ../src/GradeDisplay.h; sourceTree = ""; }; AA6EFE9004770E7C005F316C /* GrooveRadar.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = GrooveRadar.cpp; path = ../src/GrooveRadar.cpp; sourceTree = ""; }; AA6EFE9104770E7C005F316C /* GrooveRadar.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = GrooveRadar.h; path = ../src/GrooveRadar.h; sourceTree = ""; }; - AA6EFE9204770E7C005F316C /* GroupList.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = GroupList.cpp; path = ../src/GroupList.cpp; sourceTree = ""; }; - AA6EFE9304770E7C005F316C /* GroupList.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = GroupList.h; path = ../src/GroupList.h; sourceTree = ""; }; AA6EFE9404770E7C005F316C /* HelpDisplay.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = HelpDisplay.cpp; path = ../src/HelpDisplay.cpp; sourceTree = ""; }; AA6EFE9504770E7C005F316C /* HelpDisplay.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = HelpDisplay.h; path = ../src/HelpDisplay.h; sourceTree = ""; }; AA6EFE9A04770E7C005F316C /* MenuTimer.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = MenuTimer.cpp; path = ../src/MenuTimer.cpp; sourceTree = ""; }; AA6EFE9B04770E7C005F316C /* MenuTimer.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = MenuTimer.h; path = ../src/MenuTimer.h; sourceTree = ""; }; AA6EFE9C04770E7C005F316C /* MeterDisplay.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = MeterDisplay.cpp; path = ../src/MeterDisplay.cpp; sourceTree = ""; }; AA6EFE9D04770E7C005F316C /* MeterDisplay.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = MeterDisplay.h; path = ../src/MeterDisplay.h; sourceTree = ""; }; - AA6EFEA004770E7C005F316C /* MusicList.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = MusicList.cpp; path = ../src/MusicList.cpp; sourceTree = ""; }; - AA6EFEA104770E7C005F316C /* MusicList.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = MusicList.h; path = ../src/MusicList.h; sourceTree = ""; }; AA6EFEA404770E7C005F316C /* MusicWheel.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = MusicWheel.cpp; path = ../src/MusicWheel.cpp; sourceTree = ""; }; AA6EFEA504770E7C005F316C /* MusicWheel.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = MusicWheel.h; path = ../src/MusicWheel.h; sourceTree = ""; }; AA6EFEA604770E7C005F316C /* MusicWheelItem.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; name = MusicWheelItem.cpp; path = ../src/MusicWheelItem.cpp; sourceTree = ""; }; @@ -2959,6 +2970,19 @@ AAFF5542054E736D00D02EE9 /* Attack.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; name = Attack.h; path = ../src/Attack.h; sourceTree = ""; }; EE2153A710A75BEE0074B01B /* NotesLoaderPMS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NotesLoaderPMS.cpp; path = ../src/NotesLoaderPMS.cpp; sourceTree = SOURCE_ROOT; }; EE2153A810A75BEE0074B01B /* NotesLoaderPMS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NotesLoaderPMS.h; path = ../src/NotesLoaderPMS.h; sourceTree = SOURCE_ROOT; }; + EE906F6412BF3A1B00146C96 /* ScreenInstallOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScreenInstallOverlay.cpp; path = ../src/ScreenInstallOverlay.cpp; sourceTree = SOURCE_ROOT; }; + EE906F6512BF3A1B00146C96 /* ScreenInstallOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenInstallOverlay.h; path = ../src/ScreenInstallOverlay.h; sourceTree = SOURCE_ROOT; }; + EE906F7012BF3A6900146C96 /* json_batchallocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = json_batchallocator.h; path = ../src/jsoncpp/src/lib_json/json_batchallocator.h; sourceTree = SOURCE_ROOT; }; + EE906F7112BF3A6900146C96 /* json_internalarray.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = json_internalarray.inl; path = ../src/jsoncpp/src/lib_json/json_internalarray.inl; sourceTree = SOURCE_ROOT; }; + EE906F7212BF3A6900146C96 /* json_internalmap.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = json_internalmap.inl; path = ../src/jsoncpp/src/lib_json/json_internalmap.inl; sourceTree = SOURCE_ROOT; }; + EE906F7312BF3A6900146C96 /* json_reader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json_reader.cpp; path = ../src/jsoncpp/src/lib_json/json_reader.cpp; sourceTree = SOURCE_ROOT; }; + EE906F7412BF3A6900146C96 /* json_value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json_value.cpp; path = ../src/jsoncpp/src/lib_json/json_value.cpp; sourceTree = SOURCE_ROOT; }; + EE906F7512BF3A6900146C96 /* json_valueiterator.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = json_valueiterator.inl; path = ../src/jsoncpp/src/lib_json/json_valueiterator.inl; sourceTree = SOURCE_ROOT; }; + EE906F7612BF3A6900146C96 /* json_writer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = json_writer.cpp; path = ../src/jsoncpp/src/lib_json/json_writer.cpp; sourceTree = SOURCE_ROOT; }; + EE906F8012BF3AF800146C96 /* JsonUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JsonUtil.cpp; path = ../src/JsonUtil.cpp; sourceTree = SOURCE_ROOT; }; + EE906F8112BF3AF800146C96 /* JsonUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JsonUtil.h; path = ../src/JsonUtil.h; sourceTree = SOURCE_ROOT; }; + EE906F8812BF3C7C00146C96 /* FileDownload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileDownload.cpp; path = ../src/FileDownload.cpp; sourceTree = SOURCE_ROOT; }; + EE906F8912BF3C7C00146C96 /* FileDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileDownload.h; path = ../src/FileDownload.h; sourceTree = SOURCE_ROOT; }; EEA7C84110A805A300082E7B /* ScreenPackagesSSC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScreenPackagesSSC.cpp; path = ../src/ScreenPackagesSSC.cpp; sourceTree = SOURCE_ROOT; }; EEA7C84210A805A300082E7B /* ScreenPackagesSSC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenPackagesSSC.h; path = ../src/ScreenPackagesSSC.h; sourceTree = SOURCE_ROOT; }; EEC7863D0E58208B00F559BC /* StepsDisplay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StepsDisplay.cpp; path = ../src/StepsDisplay.cpp; sourceTree = ""; }; @@ -3113,6 +3137,7 @@ 29B97314FDCFA39411CA2CEA /* SDL App */ = { isa = PBXGroup; children = ( + EE906F6F12BF3A5B00146C96 /* json */, AAA070B20CE7B3AD005A3060 /* mad-0.15.1b */, AA7C8B920B67467C00FD9940 /* libtomcrypt */, AA7C8A7F0B6744F600FD9940 /* libtommath */, @@ -3185,8 +3210,6 @@ AA6E00090477103E005F316C /* Screens */ = { isa = PBXGroup; children = ( - 36CA531E0F9156860063D59D /* ScreenOptionsEditCourse.cpp */, - 36CA531F0F9156860063D59D /* ScreenOptionsEditCourse.h */, AA6E000A047711F3005F316C /* Screen.cpp */, AA6E000B047711F3005F316C /* Screen.h */, AA6E0010047711F3005F316C /* ScreenAttract.cpp */, @@ -3225,6 +3248,8 @@ 367D575A0EDE56F200B46814 /* ScreenHighScores.h */, AA6E002F047711F3005F316C /* ScreenHowToPlay.cpp */, AA6E0030047711F3005F316C /* ScreenHowToPlay.h */, + EE906F6412BF3A1B00146C96 /* ScreenInstallOverlay.cpp */, + EE906F6512BF3A1B00146C96 /* ScreenInstallOverlay.h */, AA6E0033047711F3005F316C /* ScreenInstructions.cpp */, AA6E0034047711F3005F316C /* ScreenInstructions.h */, AA6E0037047711F3005F316C /* ScreenJukebox.cpp */, @@ -3251,6 +3276,10 @@ AA42F5E7067068D30013509E /* ScreenNetworkOptions.h */, AA6E004B047711F3005F316C /* ScreenOptions.cpp */, AA6E004C047711F3005F316C /* ScreenOptions.h */, + 36CA531A0F91564A0063D59D /* ScreenOptionsCourseOverview.cpp */, + 36CA531B0F91564A0063D59D /* ScreenOptionsCourseOverview.h */, + 36CA531E0F9156860063D59D /* ScreenOptionsEditCourse.cpp */, + 36CA531F0F9156860063D59D /* ScreenOptionsEditCourse.h */, AAFAB5BB0889098600767BF7 /* ScreenOptionsEditProfile.cpp */, AAFAB5BC0889098600767BF7 /* ScreenOptionsEditProfile.h */, AAFF41A10F5BD4AD00FFDB67 /* ScreenOptionsExportPackage.cpp */, @@ -3320,8 +3349,6 @@ AA6E0079047711F3005F316C /* ScreenTestFonts.cpp */, AA6E007A047711F3005F316C /* ScreenTestFonts.h */, AAC622FA05389A0500D02EE9 /* ScreenTestInput.cpp */, - 36CA531A0F91564A0063D59D /* ScreenOptionsCourseOverview.cpp */, - 36CA531B0F91564A0063D59D /* ScreenOptionsCourseOverview.h */, AAC622FB05389A0500D02EE9 /* ScreenTestInput.h */, AAF7435906110E8D00B19AD1 /* ScreenTestLights.cpp */, AAF7435A06110E8D00B19AD1 /* ScreenTestLights.h */, @@ -3702,6 +3729,8 @@ AA8F136F0624BAB200C6A467 /* EnumHelper.h */, AAE7808506081A000034E65F /* ezsockets.cpp */, AAE7808606081A000034E65F /* ezsockets.h */, + EE906F8812BF3C7C00146C96 /* FileDownload.cpp */, + EE906F8912BF3C7C00146C96 /* FileDownload.h */, AA6EFDD104770C79005F316C /* Font.cpp */, AA6EFDD204770C79005F316C /* Font.h */, AA6EFDD304770C79005F316C /* FontCharAliases.cpp */, @@ -3727,6 +3756,8 @@ AABBD80605D8E9FC00B44FC2 /* HighScore.cpp */, AABBD80705D8E9FC00B44FC2 /* HighScore.h */, AACFBE3908E7D832005087FC /* InputEventPlus.h */, + EE906F8012BF3AF800146C96 /* JsonUtil.cpp */, + EE906F8112BF3AF800146C96 /* JsonUtil.h */, AA2FB638091212AF000FD574 /* LifeMeter.cpp */, AADD1CC2095C233E0088C9DF /* LocalizedString.cpp */, AADD1CC3095C233F0088C9DF /* LocalizedString.h */, @@ -3756,10 +3787,14 @@ EE2153A810A75BEE0074B01B /* NotesLoaderPMS.h */, AA6EFDF504770C79005F316C /* NotesLoaderSM.cpp */, AA6EFDF604770C79005F316C /* NotesLoaderSM.h */, + 2BA7925A1304F20D002BD8E1 /* NotesLoaderSSC.cpp */, + 2BA7925B1304F20D002BD8E1 /* NotesLoaderSSC.h */, AA6EFDF704770C79005F316C /* NotesWriterDWI.cpp */, AA6EFDF804770C79005F316C /* NotesWriterDWI.h */, AA6EFDF904770C79005F316C /* NotesWriterSM.cpp */, AA6EFDFA04770C79005F316C /* NotesWriterSM.h */, + 2BA7925C1304F20D002BD8E1 /* NotesWriterSSC.cpp */, + 2BA7925D1304F20D002BD8E1 /* NotesWriterSSC.h */, AA6EFDFB04770C79005F316C /* NoteTypes.cpp */, AA6EFDFC04770C79005F316C /* NoteTypes.h */, AA80C75707F20D6600C99272 /* OptionRowHandler.cpp */, @@ -3887,8 +3922,6 @@ AAFF551E0549F39700D02EE9 /* GraphDisplay.h */, AA6EFE9004770E7C005F316C /* GrooveRadar.cpp */, AA6EFE9104770E7C005F316C /* GrooveRadar.h */, - AA6EFE9204770E7C005F316C /* GroupList.cpp */, - AA6EFE9304770E7C005F316C /* GroupList.h */, AA6EFE9404770E7C005F316C /* HelpDisplay.cpp */, AA6EFE9504770E7C005F316C /* HelpDisplay.h */, AA729C460599B54D00779F33 /* MemoryCardDisplay.cpp */, @@ -3901,8 +3934,6 @@ AA11A20C0DC5A1B0006BD8AC /* ModIcon.h */, AA11A20D0DC5A1B0006BD8AC /* ModIconRow.cpp */, AA11A20E0DC5A1B0006BD8AC /* ModIconRow.h */, - AA6EFEA004770E7C005F316C /* MusicList.cpp */, - AA6EFEA104770E7C005F316C /* MusicList.h */, AA6EFEA404770E7C005F316C /* MusicWheel.cpp */, AA6EFEA504770E7C005F316C /* MusicWheel.h */, AA6EFEA604770E7C005F316C /* MusicWheelItem.cpp */, @@ -4862,6 +4893,20 @@ path = "../src/lua-5.1"; sourceTree = ""; }; + EE906F6F12BF3A5B00146C96 /* json */ = { + isa = PBXGroup; + children = ( + EE906F7012BF3A6900146C96 /* json_batchallocator.h */, + EE906F7112BF3A6900146C96 /* json_internalarray.inl */, + EE906F7212BF3A6900146C96 /* json_internalmap.inl */, + EE906F7312BF3A6900146C96 /* json_reader.cpp */, + EE906F7412BF3A6900146C96 /* json_value.cpp */, + EE906F7512BF3A6900146C96 /* json_valueiterator.inl */, + EE906F7612BF3A6900146C96 /* json_writer.cpp */, + ); + name = json; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -4877,6 +4922,12 @@ EEA7C84410A805A300082E7B /* ScreenPackagesSSC.h in Headers */, 36C6888411297FFE00453295 /* RageFileDriverReadAhead.h in Headers */, 36C6888611297FFE00453295 /* RageFileManager_ReadAhead.h in Headers */, + EE906F6712BF3A1B00146C96 /* ScreenInstallOverlay.h in Headers */, + EE906F7712BF3A6900146C96 /* json_batchallocator.h in Headers */, + EE906F8312BF3AF800146C96 /* JsonUtil.h in Headers */, + EE906F8B12BF3C7C00146C96 /* FileDownload.h in Headers */, + 2BA7925F1304F20D002BD8E1 /* NotesLoaderSSC.h in Headers */, + 2BA792611304F20D002BD8E1 /* NotesWriterSSC.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4944,11 +4995,9 @@ AA40D1F809A08D650068C0D5 /* FadingBanner.h in Headers */, AA40D1F909A08D650068C0D5 /* GradeDisplay.h in Headers */, AA40D1FA09A08D650068C0D5 /* GrooveRadar.h in Headers */, - AA40D1FB09A08D650068C0D5 /* GroupList.h in Headers */, AA40D1FC09A08D650068C0D5 /* HelpDisplay.h in Headers */, AA40D1FD09A08D650068C0D5 /* MenuTimer.h in Headers */, AA40D1FE09A08D650068C0D5 /* MeterDisplay.h in Headers */, - AA40D20009A08D650068C0D5 /* MusicList.h in Headers */, AA40D20209A08D650068C0D5 /* MusicWheel.h in Headers */, AA40D20309A08D650068C0D5 /* MusicWheelItem.h in Headers */, AA40D20609A08D650068C0D5 /* OptionsCursor.h in Headers */, @@ -5597,6 +5646,9 @@ AA29CD3E0558741A00961A51 /* smicon.icns in Resources */, AAF6A2F909B695BA00D5C614 /* Localizable.strings in Resources */, AA1DE9580C5468CE00D59F20 /* Hardware.plist in Resources */, + EE906F7812BF3A6900146C96 /* json_internalarray.inl in Resources */, + EE906F7912BF3A6900146C96 /* json_internalmap.inl in Resources */, + EE906F7C12BF3A6900146C96 /* json_valueiterator.inl in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5770,11 +5822,9 @@ AA29CD810558741A00961A51 /* FadingBanner.cpp in Sources */, AA29CD820558741A00961A51 /* GradeDisplay.cpp in Sources */, AA29CD840558741A00961A51 /* GrooveRadar.cpp in Sources */, - AA29CD850558741A00961A51 /* GroupList.cpp in Sources */, AA29CD860558741A00961A51 /* HelpDisplay.cpp in Sources */, AA29CD890558741A00961A51 /* MenuTimer.cpp in Sources */, AA29CD8A0558741A00961A51 /* MeterDisplay.cpp in Sources */, - AA29CD8C0558741A00961A51 /* MusicList.cpp in Sources */, AA29CD8E0558741A00961A51 /* MusicWheel.cpp in Sources */, AA29CD8F0558741A00961A51 /* MusicWheelItem.cpp in Sources */, AA29CD920558741A00961A51 /* OptionsCursor.cpp in Sources */, @@ -6113,6 +6163,14 @@ EEA7C84310A805A300082E7B /* ScreenPackagesSSC.cpp in Sources */, 36C6888311297FFE00453295 /* RageFileDriverReadAhead.cpp in Sources */, 36C6888511297FFE00453295 /* RageFileManager_ReadAhead.cpp in Sources */, + EE906F6612BF3A1B00146C96 /* ScreenInstallOverlay.cpp in Sources */, + EE906F7A12BF3A6900146C96 /* json_reader.cpp in Sources */, + EE906F7B12BF3A6900146C96 /* json_value.cpp in Sources */, + EE906F7D12BF3A6900146C96 /* json_writer.cpp in Sources */, + EE906F8212BF3AF800146C96 /* JsonUtil.cpp in Sources */, + EE906F8A12BF3C7C00146C96 /* FileDownload.cpp in Sources */, + 2BA7925E1304F20D002BD8E1 /* NotesLoaderSSC.cpp in Sources */, + 2BA792601304F20D002BD8E1 /* NotesWriterSSC.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -6175,11 +6233,9 @@ AA40D3BA09A08D650068C0D5 /* FadingBanner.cpp in Sources */, AA40D3BB09A08D650068C0D5 /* GradeDisplay.cpp in Sources */, AA40D3BC09A08D650068C0D5 /* GrooveRadar.cpp in Sources */, - AA40D3BD09A08D650068C0D5 /* GroupList.cpp in Sources */, AA40D3BE09A08D650068C0D5 /* HelpDisplay.cpp in Sources */, AA40D3BF09A08D650068C0D5 /* MenuTimer.cpp in Sources */, AA40D3C009A08D650068C0D5 /* MeterDisplay.cpp in Sources */, - AA40D3C209A08D650068C0D5 /* MusicList.cpp in Sources */, AA40D3C409A08D650068C0D5 /* MusicWheel.cpp in Sources */, AA40D3C509A08D650068C0D5 /* MusicWheelItem.cpp in Sources */, AA40D3C809A08D650068C0D5 /* OptionsCursor.cpp in Sources */, @@ -7075,6 +7131,7 @@ SHARED_PRECOMPS_DIR = "/Library/Caches/com.apple.Xcode.$(UID)/SharedPrecompiledHeaders/$(PRODUCT_NAME)/$(CONFIGURATION)"; STRIP_INSTALLED_PRODUCT = NO; STRIP_STYLE = "non-global"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../src/jsoncpp/include"; }; name = Debug; }; @@ -7606,6 +7663,7 @@ SHARED_PRECOMPS_DIR = "/Library/Caches/com.apple.Xcode.$(UID)/SharedPrecompiledHeaders/$(PRODUCT_NAME)/$(CONFIGURATION)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../src/jsoncpp/include"; }; name = PerformanceDebug; }; @@ -7936,6 +7994,7 @@ SHARED_PRECOMPS_DIR = "/Library/Caches/com.apple.Xcode.$(UID)/SharedPrecompiledHeaders/$(PRODUCT_NAME)/$(CONFIGURATION)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../src/jsoncpp/include"; }; name = Native; }; @@ -8061,6 +8120,7 @@ SHARED_PRECOMPS_DIR = "/Library/Caches/com.apple.Xcode.$(UID)/SharedPrecompiledHeaders/$(PRODUCT_NAME)/$(CONFIGURATION)"; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; + USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../src/jsoncpp/include"; }; name = Universal; }; diff --git a/sm-ssc.nsi b/sm-ssc.nsi index fcf4aadd2a..d2f30820c2 100644 --- a/sm-ssc.nsi +++ b/sm-ssc.nsi @@ -78,9 +78,8 @@ !insertmacro MUI_PAGE_WELCOME - ; we need to warn people on Windows Vista and 7 not to install in - ; Program Files - !insertmacro MUI_PAGE_LICENSE ".\Docs\Windows7.txt" + ; include various Windows-only notices + !insertmacro MUI_PAGE_LICENSE ".\Docs\WindowsNotes.txt" ;!insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY @@ -294,7 +293,14 @@ Section "Main Section" SecMain RMDir /r "$INSTDIR\NoteSkins\dance\retrobar" RMDir /r "$INSTDIR\NoteSkins\dance\retrobar-splithand_whiteblue" ; pump + 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" ; kb7 RMDir /r "$INSTDIR\NoteSkins\kb7\default" @@ -332,8 +338,13 @@ Section "Main Section" SecMain ; install pump noteskins SetOutPath "$INSTDIR\NoteSkins\pump" File /r /x CVS /x .svn "NoteSkins\pump\cmd" + File /r /x CVS /x .svn "NoteSkins\pump\cmd-routine-p1" + File /r /x CVS /x .svn "NoteSkins\pump\cmd-routine-p2" File /r /x CVS /x .svn "NoteSkins\pump\complex" File /r /x CVS /x .svn "NoteSkins\pump\default" + File /r /x CVS /x .svn "NoteSkins\pump\frame5p" + File /r /x CVS /x .svn "NoteSkins\pump\newextra" + File /r /x CVS /x .svn "NoteSkins\pump\rhythm" File /r /x CVS /x .svn "NoteSkins\pump\simple" SetOutPath "$INSTDIR" diff --git a/src/ActorFrame.cpp b/src/ActorFrame.cpp index b2b43ccc39..0f83865b3c 100644 --- a/src/ActorFrame.cpp +++ b/src/ActorFrame.cpp @@ -338,8 +338,6 @@ void ActorFrame::UpdateInternal( float fDeltaTime ) pActor->Update(fDeltaTime); } - // todo: update lighting? -aj - if( unlikely(!m_UpdateFunction.IsNil()) ) { Lua *L = LUA->Get(); diff --git a/src/ArrowEffects.cpp b/src/ArrowEffects.cpp index f01b8bd2d0..f19cf6f40f 100644 --- a/src/ArrowEffects.cpp +++ b/src/ArrowEffects.cpp @@ -16,6 +16,41 @@ static ThemeMetric ARROW_SPACING( "ArrowEffects", "ArrowSpacing" ); static ThemeMetric HIDDEN_SUDDEN_PAST_RECEPTOR( "ArrowEffects", "DrawHiddenNotesAfterReceptor"); +static ThemeMetric BLINK_MOD_FREQUENCY( "ArrowEffects", "BlinkModFrequency" ); +static ThemeMetric BOOST_MOD_MIN_CLAMP( "ArrowEffects", "BoostModMinClamp" ); +static ThemeMetric BOOST_MOD_MAX_CLAMP( "ArrowEffects", "BoostModMaxClamp" ); +static ThemeMetric BRAKE_MOD_MIN_CLAMP( "ArrowEffects", "BrakeModMinClamp" ); +static ThemeMetric BRAKE_MOD_MAX_CLAMP( "ArrowEffects", "BrakeModMaxClamp" ); +static ThemeMetric WAVE_MOD_MAGNITUDE( "ArrowEffects", "WaveModMagnitude" ); +static ThemeMetric WAVE_MOD_HEIGHT( "ArrowEffects", "WaveModHeight" ); +static ThemeMetric BOOMERANG_PEAK_PERCENTAGE( "ArrowEffects", "BoomerangPeakPercentage" ); +static ThemeMetric EXPAND_MULTIPLIER_FREQUENCY( "ArrowEffects", "ExpandMultiplierFrequency" ); +static ThemeMetric EXPAND_MULTIPLIER_SCALE_FROM_LOW( "ArrowEffects", "ExpandMultiplierScaleFromLow" ); +static ThemeMetric EXPAND_MULTIPLIER_SCALE_FROM_HIGH( "ArrowEffects", "ExpandMultiplierScaleFromHigh" ); +static ThemeMetric EXPAND_MULTIPLIER_SCALE_TO_LOW( "ArrowEffects", "ExpandMultiplierScaleToLow" ); +static ThemeMetric EXPAND_MULTIPLIER_SCALE_TO_HIGH( "ArrowEffects", "ExpandMultiplierScaleToHigh" ); +static ThemeMetric EXPAND_SPEED_SCALE_FROM_LOW( "ArrowEffects", "ExpandSpeedScaleFromLow" ); +static ThemeMetric EXPAND_SPEED_SCALE_FROM_HIGH( "ArrowEffects", "ExpandSpeedScaleFromHigh" ); +static ThemeMetric EXPAND_SPEED_SCALE_TO_LOW( "ArrowEffects", "ExpandSpeedScaleToLow" ); +static ThemeMetric TIPSY_TIMER_FREQUENCY( "ArrowEffects", "TipsyTimerFrequency" ); +static ThemeMetric TIPSY_COLUMN_FREQUENCY( "ArrowEffects", "TipsyColumnFrequency" ); +static ThemeMetric TIPSY_ARROW_MAGNITUDE( "ArrowEffects", "TipsyArrowMagnitude" ); +static ThemeMetric TIPSY_OFFSET_TIMER_FREQUENCY( "ArrowEffects", "TipsyOffsetTimerFrequency" ); +static ThemeMetric TIPSY_OFFSET_COLUMN_FREQUENCY( "ArrowEffects", "TipsyOffsetColumnFrequency" ); +static ThemeMetric TIPSY_OFFSET_ARROW_MAGNITUDE( "ArrowEffects", "TipsyOffsetArrowMagnitude" ); +static ThemeMetric TORNADO_POSITION_SCALE_TO_LOW( "ArrowEffects", "TornadoPositionScaleToLow" ); +static ThemeMetric TORNADO_POSITION_SCALE_TO_HIGH( "ArrowEffects", "TornadoPositionScaleToHigh" ); +static ThemeMetric TORNADO_OFFSET_FREQUENCY( "ArrowEffects", "TornadoOffsetFrequency" ); +static ThemeMetric TORNADO_OFFSET_SCALE_FROM_LOW( "ArrowEffects", "TornadoOffsetScaleFromLow" ); +static ThemeMetric TORNADO_OFFSET_SCALE_FROM_HIGH( "ArrowEffects", "TornadoOffsetScaleFromHigh" ); +static ThemeMetric DRUNK_COLUMN_FREQUENCY( "ArrowEffects", "DrunkColumnFrequency" ); +static ThemeMetric DRUNK_OFFSET_FREQUENCY( "ArrowEffects", "DrunkOffsetFrequency" ); +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 QUANTIZE_ARROW_Y( "ArrowEffects", "QuantizeArrowYPosition"); static float GetNoteFieldHeight( const PlayerState* pPlayerState ) { @@ -213,7 +248,7 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float float fNewYOffset = fYOffset * 1.5f / ((fYOffset+fEffectHeight/1.2f)/fEffectHeight); float fAccelYAdjust = fAccels[PlayerOptions::ACCEL_BOOST] * (fNewYOffset - fYOffset); // TRICKY: Clamp this value, or else BOOST+BOOMERANG will draw a ton of arrows on the screen. - CLAMP( fAccelYAdjust, -400.f, 400.f ); + CLAMP( fAccelYAdjust, BOOST_MOD_MIN_CLAMP, BOOST_MOD_MAX_CLAMP ); fYAdjust += fAccelYAdjust; } if( fAccels[PlayerOptions::ACCEL_BRAKE] != 0 ) @@ -223,18 +258,18 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float float fNewYOffset = fYOffset * fScale; float fBrakeYAdjust = fAccels[PlayerOptions::ACCEL_BRAKE] * (fNewYOffset - fYOffset); // TRICKY: Clamp this value the same way as BOOST so that in BOOST+BRAKE, BRAKE doesn't overpower BOOST - CLAMP( fBrakeYAdjust, -400.f, 400.f ); + CLAMP( fBrakeYAdjust, BRAKE_MOD_MIN_CLAMP, BRAKE_MOD_MAX_CLAMP ); fYAdjust += fBrakeYAdjust; } if( fAccels[PlayerOptions::ACCEL_WAVE] != 0 ) - fYAdjust += fAccels[PlayerOptions::ACCEL_WAVE] * 20.0f*RageFastSin( fYOffset/38.0f ); + fYAdjust += fAccels[PlayerOptions::ACCEL_WAVE] * WAVE_MOD_MAGNITUDE *RageFastSin( fYOffset/WAVE_MOD_HEIGHT ); fYOffset += fYAdjust; // Factor in boomerang if( fAccels[PlayerOptions::ACCEL_BOOMERANG] != 0 ) { - float fPeakAtYOffset = SCREEN_HEIGHT * 0.75f; // zero point of boomerang function + float fPeakAtYOffset = SCREEN_HEIGHT * BOOMERANG_PEAK_PERCENTAGE; // zero point of boomerang function fPeakYOffsetOut = (-1*fPeakAtYOffset*fPeakAtYOffset/SCREEN_HEIGHT) + 1.5f*fPeakAtYOffset; bIsPastPeakOut = fYOffset < fPeakAtYOffset; @@ -262,8 +297,12 @@ float ArrowEffects::GetYOffset( const PlayerState* pPlayerState, int iCol, float if( fAccels[PlayerOptions::ACCEL_EXPAND] != 0 ) { - float fExpandMultiplier = SCALE( RageFastCos(g_fExpandSeconds*3), -1, 1, 0.75f, 1.75f ); - fScrollSpeed *= SCALE( fAccels[PlayerOptions::ACCEL_EXPAND], 0.f, 1.f, 1.f, fExpandMultiplier ); + float fExpandMultiplier = SCALE( RageFastCos(g_fExpandSeconds*EXPAND_MULTIPLIER_FREQUENCY), + EXPAND_MULTIPLIER_SCALE_FROM_LOW, EXPAND_MULTIPLIER_SCALE_FROM_HIGH, + EXPAND_MULTIPLIER_SCALE_TO_LOW, EXPAND_MULTIPLIER_SCALE_TO_HIGH ); + fScrollSpeed *= SCALE( fAccels[PlayerOptions::ACCEL_EXPAND], + EXPAND_SPEED_SCALE_FROM_LOW, EXPAND_SPEED_SCALE_FROM_HIGH, + EXPAND_SPEED_SCALE_TO_LOW, fExpandMultiplier ); } fYOffset *= fScrollSpeed; @@ -306,14 +345,15 @@ float ArrowEffects::GetYPos( const PlayerState* pPlayerState, int iCol, float fY const float* fEffects = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects; if( fEffects[PlayerOptions::EFFECT_TIPSY] != 0 ) - f += fEffects[PlayerOptions::EFFECT_TIPSY] * ( RageFastCos( RageTimer::GetTimeSinceStartFast()*1.2f + iCol*1.8f) * ARROW_SIZE*0.4f ); + f += fEffects[PlayerOptions::EFFECT_TIPSY] + * ( RageFastCos( RageTimer::GetTimeSinceStartFast()*TIPSY_TIMER_FREQUENCY + + iCol*TIPSY_COLUMN_FREQUENCY) * ARROW_SIZE*TIPSY_ARROW_MAGNITUDE ); // In beware's DDR Extreme-focused fork of StepMania 3.9, this value is // floored, making arrows show on integer Y coordinates. Supposedly it makes // the arrows look better, but testing needs to be done. - // todo: make this a noteskin metric ("QuantizeArrowYPosition") -aj - return f; - //return floor(f); + // todo: make this a noteskin metric instead of a theme metric? -aj + return QUANTIZE_ARROW_Y ? floor(f) : f; } float ArrowEffects::GetYOffsetFromYPos( const PlayerState* pPlayerState, int iCol, float YPos, float fYReverseOffsetPixels ) @@ -322,7 +362,9 @@ float ArrowEffects::GetYOffsetFromYPos( const PlayerState* pPlayerState, int iCo const float* fEffects = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects; if( fEffects[PlayerOptions::EFFECT_TIPSY] != 0 ) - f -= fEffects[PlayerOptions::EFFECT_TIPSY] * ( RageFastCos( RageTimer::GetTimeSinceStartFast()*1.2f + iCol*2.f) * ARROW_SIZE*0.4f ); + f -= fEffects[PlayerOptions::EFFECT_TIPSY] + * ( RageFastCos( RageTimer::GetTimeSinceStartFast()*TIPSY_OFFSET_TIMER_FREQUENCY + + iCol*TIPSY_OFFSET_COLUMN_FREQUENCY) * ARROW_SIZE*TIPSY_OFFSET_ARROW_MAGNITUDE ); float fShift, fScale; ArrowGetReverseShiftAndScale( pPlayerState, iCol, fYReverseOffsetPixels, fShift, fScale ); @@ -348,17 +390,21 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float if( fEffects[PlayerOptions::EFFECT_TORNADO] != 0 ) { const float fRealPixelOffset = pCols[iColNum].fXOffset; - const float fPositionBetween = SCALE( fRealPixelOffset, data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum], -1, 1 ); + const float fPositionBetween = SCALE( fRealPixelOffset, data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum], + TORNADO_POSITION_SCALE_TO_LOW, TORNADO_POSITION_SCALE_TO_HIGH ); float fRads = acosf( fPositionBetween ); - fRads += fYOffset * 6 / SCREEN_HEIGHT; + fRads += fYOffset * TORNADO_OFFSET_FREQUENCY / SCREEN_HEIGHT; - const float fAdjustedPixelOffset = SCALE( RageFastCos(fRads), -1, 1, data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum] ); + const float fAdjustedPixelOffset = SCALE( RageFastCos(fRads), TORNADO_OFFSET_SCALE_FROM_LOW, TORNADO_OFFSET_SCALE_FROM_HIGH, + data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum] ); fPixelOffsetFromCenter += (fAdjustedPixelOffset - fRealPixelOffset) * fEffects[PlayerOptions::EFFECT_TORNADO]; } if( fEffects[PlayerOptions::EFFECT_DRUNK] != 0 ) - fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_DRUNK] * ( RageFastCos( RageTimer::GetTimeSinceStartFast() + iColNum*0.2f + fYOffset*10/SCREEN_HEIGHT) * ARROW_SIZE*0.5f ); + fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_DRUNK] * + ( RageFastCos( RageTimer::GetTimeSinceStartFast() + iColNum*DRUNK_COLUMN_FREQUENCY + + fYOffset*DRUNK_OFFSET_FREQUENCY/SCREEN_HEIGHT) * ARROW_SIZE*DRUNK_ARROW_MAGNITUDE ); if( fEffects[PlayerOptions::EFFECT_FLIP] != 0 ) { const int iFirstCol = 0; @@ -374,7 +420,7 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float if( fEffects[PlayerOptions::EFFECT_BEAT] != 0 ) { - const float fShift = data.m_fBeatFactor*RageFastSin( fYOffset / 15.0f + PI/2.0f ); + const float fShift = data.m_fBeatFactor*RageFastSin( fYOffset / BEAT_OFFSET_HEIGHT + PI/BEAT_PI_HEIGHT ); fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_BEAT] * fShift; } @@ -406,9 +452,7 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float fPixelOffsetFromCenter += fEffects[PlayerOptions::EFFECT_XMODE]*fYOffset; } break; - default: - ASSERT("What the hell kind of styletype are you passing me anyways?"); - break; + DEFAULT_FAIL(pStyle->m_StyleType); } } @@ -418,7 +462,7 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float { // Allow Mini to pull tracks together, but not to push them apart. float fMiniPercent = fEffects[PlayerOptions::EFFECT_MINI]; - fMiniPercent = min( powf(0.5f, fMiniPercent), 1.0f ); + fMiniPercent = min( powf(MINI_PERCENT_BASE, fMiniPercent), (float)MINI_PERCENT_GATE ); fPixelOffsetFromCenter *= fMiniPercent; } @@ -572,7 +616,7 @@ float ArrowGetPercentVisible( const PlayerState* pPlayerState, float fYPosWithou if( fAppearances[PlayerOptions::APPEARANCE_BLINK] != 0 ) { float f = RageFastSin(RageTimer::GetTimeSinceStartFast()*10); - f = Quantize( f, 0.3333f ); + f = Quantize( f, BLINK_MOD_FREQUENCY ); fVisibleAdjust += SCALE( f, 0, 1, -1, 0 ); } if( fAppearances[PlayerOptions::APPEARANCE_RANDOMVANISH] != 0 ) diff --git a/src/BPMDisplay.cpp b/src/BPMDisplay.cpp index 83d19aecd9..b079cf9f93 100644 --- a/src/BPMDisplay.cpp +++ b/src/BPMDisplay.cpp @@ -35,7 +35,7 @@ void BPMDisplay::Load() SEPARATOR.Load( m_sName, "Separator" ); SHOW_QMARKS.Load( m_sName, "ShowQMarksInRandomCycle" ); NO_BPM_TEXT.Load( m_sName, "NoBpmText" ); - //QUESTIONMARKS_TEXT.Load( m_sName, "QuestionMarksText" ); + QUESTIONMARKS_TEXT.Load( m_sName, "QuestionMarksText" ); RANDOM_TEXT.Load( m_sName, "RandomText" ); VARIOUS_TEXT.Load( m_sName, "VariousText" ); @@ -75,10 +75,8 @@ void BPMDisplay::Update( float fDeltaTime ) if(m_fBPMTo == -1) { m_fBPMFrom = -1; - - // todo: allow themer to customize "xxx" string -aj if( (bool)SHOW_QMARKS ) - SetText( (RandomFloat(0,1)>0.90f) ? RString("xxx") : ssprintf("%03.0f",RandomFloat(0,999)) ); + SetText( (RandomFloat(0,1)>0.90f) ? (RString)QUESTIONMARKS_TEXT : ssprintf("%03.0f",RandomFloat(0,999)) ); else SetText( ssprintf("%03.0f",RandomFloat(0,999)) ); } @@ -291,6 +289,7 @@ void SongBPMDisplay::Update( float fDeltaTime ) REGISTER_ACTOR_CLASS( SongBPMDisplay ) #include "LuaBinding.h" +/** @brief Allow Lua to have access to the BPMDisplay. */ class LunaBPMDisplay: public Luna { public: diff --git a/src/BPMDisplay.h b/src/BPMDisplay.h index 726101430b..d6fb4f5e71 100644 --- a/src/BPMDisplay.h +++ b/src/BPMDisplay.h @@ -1,4 +1,4 @@ -/* BPMDisplay - displays a BPM or a range of BPMs. */ +/** @brief BPMDisplay - displays a BPM or a range of BPMs. */ #ifndef BPM_DISPLAY_H #define BPM_DISPLAY_H @@ -11,54 +11,109 @@ class Song; class Course; struct DisplayBpms; +/** @brief Display the BPM/range of them as requested. */ class BPMDisplay : public BitmapText { public: + /** @brief Set up the BPM Display with default values. */ BPMDisplay(); + /** @brief Copy the BPMDisplay to another. */ virtual BPMDisplay *Copy() const; + /** @brief Load the various metrics needed. */ void Load(); + /** + * @brief Update the display as required. + * @param fDeltaTime the changed time. + */ virtual void Update( float fDeltaTime ); void LoadFromNode( const XNode *pNode ); - + /** + * @brief Use the BPM[s] from a song. + * @param pSong the song in question. + */ void SetBpmFromSong( const Song* pSong ); + /** + * @brief Use the BPM[s] from a course. + * @param pCourse the course in question. + */ void SetBpmFromCourse( const Course* pCourse ); + /** + * @brief Use a specified, constant BPM. + * @param fBPM the constant BPM. + */ void SetConstantBpm( float fBPM ); + /** + * @brief Have the BPMDisplay cycle between various BPMs. + */ void CycleRandomly(); + /** @brief Don't use a BPM at all. */ void NoBPM(); + /** @brief Have the BPMDisplay use various BPMs. */ void SetVarious(); + /** @brief Have the GameState determine which BPMs to display. */ void SetFromGameState(); // Lua virtual void PushSelf( lua_State *L ); protected: + /** + * @brief Retrieve the active BPM on display. + * @return the active BPM on display. + */ float GetActiveBPM() const; + /** + * @brief Set the range to be used for the display. + * @param bpms the set of BPMs to be used. + */ void SetBPMRange( const DisplayBpms &bpms ); + /** @brief The commands to use when there is no BPM. */ ThemeMetric SET_NO_BPM_COMMAND; + /** @brief The commands to use when there is a normal BPM. */ ThemeMetric SET_NORMAL_COMMAND; + /** @brief The commands to use when the BPM can change between 2 or more values. */ ThemeMetric SET_CHANGING_COMMAND; + /** @brief The commands to use when the BPM is random. */ ThemeMetric SET_RANDOM_COMMAND; + /** @brief The commands to use if it is an extra stage. */ ThemeMetric SET_EXTRA_COMMAND; + /** @brief A flag to determine if the BPMs cycle from low to high or just display both. */ ThemeMetric CYCLE; + /** @brief A flag to determine if QUESTIONMARKS_TEXT is shown. */ ThemeMetric SHOW_QMARKS; + /** @brief How often the random BPMs cycle themselves. */ ThemeMetric RANDOM_CYCLE_SPEED; + /** @brief The text used to separate the low and high BPMs. */ ThemeMetric SEPARATOR; + /** @brief The text used when there is no BPM. */ ThemeMetric NO_BPM_TEXT; + /** @brief The text used when there are various BPMs for the song. */ ThemeMetric VARIOUS_TEXT; + /** @brief The text used when it is a random BPM. */ ThemeMetric RANDOM_TEXT; + /** @brief The text used as one possible option for random BPM. */ + ThemeMetric QUESTIONMARKS_TEXT; - float m_fBPMFrom, m_fBPMTo; + /** @brief The lowest valued BPM. */ + float m_fBPMFrom; + /** @brief The highest valued BPM. */ + float m_fBPMTo; + /** @brief The current BPM index used. */ int m_iCurrentBPM; + /** @brief The list of BPMs. */ vector m_BPMS; float m_fPercentInState; + /** @brief How long it takes to cycle the various BPMs. */ float m_fCycleTime; }; #endif -/* - * (c) 2001-2002 Chris Danford +/** + * @file + * @author Chris Danford (c) 2001-2002 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/Banner.cpp b/src/Banner.cpp index 5bf67f7d7b..c3ee65fab7 100644 --- a/src/Banner.cpp +++ b/src/Banner.cpp @@ -15,7 +15,7 @@ REGISTER_ACTOR_CLASS( Banner ) -ThemeMetric SCROLL_RANDOM ("Banner","ScrollRandom"); +ThemeMetric SCROLL_RANDOM ("Banner","ScrollRandom"); ThemeMetric SCROLL_ROULETTE ("Banner","ScrollRoulette"); Banner::Banner() @@ -24,7 +24,7 @@ Banner::Banner() m_fPercentScrolling = 0; } -/* Ugly: if sIsBanner is false, we're actually loading something other than a banner. */ +// Ugly: if sIsBanner is false, we're actually loading something other than a banner. void Banner::Load( RageTextureID ID, bool bIsBanner ) { if( ID.filename == "" ) @@ -86,10 +86,10 @@ void Banner::Update( float fDeltaTime ) float fTexCoords[8] = { - 0+m_fPercentScrolling, pTextureRect->top, // top left + 0+m_fPercentScrolling, pTextureRect->top, // top left 0+m_fPercentScrolling, pTextureRect->bottom, // bottom left 1+m_fPercentScrolling, pTextureRect->bottom, // bottom right - 1+m_fPercentScrolling, pTextureRect->top, // top right + 1+m_fPercentScrolling, pTextureRect->top, // top right }; Sprite::SetCustomTextureCoords( fTexCoords ); } @@ -100,25 +100,19 @@ void Banner::SetScrolling( bool bScroll, float Percent) m_bScrolling = bScroll; m_fPercentScrolling = Percent; - /* Set up the texture coord rects for the current state. */ + // Set up the texture coord rects for the current state. Update(0); } -void Banner::LoadFromSong( Song* pSong ) // NULL means no song +void Banner::LoadFromSong( Song* pSong ) // NULL means no song { - if( pSong == NULL ) LoadFallback(); - else if( pSong->HasBanner() ) Load( pSong->GetBannerPath() ); - else LoadFallback(); + if( pSong == NULL ) LoadFallback(); + else if( pSong->HasBanner() ) Load( pSong->GetBannerPath() ); + else LoadFallback(); m_bScrolling = false; } -void Banner::LoadAllMusic() -{ - Load( THEME->GetPathG("Banner","All") ); - m_bScrolling = false; -} - void Banner::LoadMode() { Load( THEME->GetPathG("Banner","Mode") ); @@ -211,13 +205,28 @@ void Banner::LoadFallbackCharacterIcon() void Banner::LoadRoulette() { Load( THEME->GetPathG("Banner","roulette") ); - m_bScrolling = (bool)SCROLL_RANDOM; + m_bScrolling = (bool)SCROLL_ROULETTE; } void Banner::LoadRandom() { Load( THEME->GetPathG("Banner","random") ); - m_bScrolling = (bool)SCROLL_ROULETTE; + m_bScrolling = (bool)SCROLL_RANDOM; +} + +void Banner::LoadFromSortOrder( SortOrder so ) +{ + // TODO: See if the check for NULL/PREFERRED(?) is needed. + if( so == SortOrder_Invalid ) + { + LoadFallback(); + } + else + { + if( so != SORT_GROUP && so != SORT_RECENT ) + Load( THEME->GetPathG("Banner",ssprintf("%s",SortOrderToString(so).c_str())) ); + } + m_bScrolling = false; } // lua start @@ -274,6 +283,19 @@ public: p->LoadFromSongGroup( SArg(1) ); return 0; } + static int LoadFromSortOrder( T* p, lua_State *L ) + { + if( lua_isnil(L,1) ) { p->LoadFromSortOrder( SortOrder_Invalid ); } + else + { + SortOrder so = Enum::Check(L, 1); + p->LoadFromSortOrder( so ); + } + return 0; + } + static int GetScrolling( T* p, lua_State *L ){ lua_pushboolean( L, p->GetScrolling() ); return 1; } + static int SetScrolling( T* p, lua_State *L ){ p->SetScrolling( BArg(1), FArg(2) ); return 0; } + static int GetPercentScrolling( T* p, lua_State *L ){ lua_pushnumber( L, p->ScrollingPercent() ); return 1; } LunaBanner() { @@ -287,6 +309,10 @@ public: ADD_METHOD( LoadBannerFromUnlockEntry ); ADD_METHOD( LoadBackgroundFromUnlockEntry ); ADD_METHOD( LoadFromSongGroup ); + ADD_METHOD( LoadFromSortOrder ); + ADD_METHOD( GetScrolling ); + ADD_METHOD( SetScrolling ); + ADD_METHOD( GetPercentScrolling ); } }; diff --git a/src/Banner.h b/src/Banner.h index 7fe790559c..a7c717bc76 100644 --- a/src/Banner.h +++ b/src/Banner.h @@ -1,15 +1,17 @@ -/* Banner - The song/course's banner displayed in SelectMusic/Course. */ +/** @brief Banner - The song/course's banner displayed in SelectMusic/Course. */ #ifndef BANNER_H #define BANNER_H #include "Sprite.h" #include "RageTextureID.h" +#include "GameConstantsAndTypes.h" class Song; class Course; class Character; class UnlockEntry; +/** @brief The characteristics of a Banner */ class Banner : public Sprite { public: @@ -23,8 +25,11 @@ public: virtual void Update( float fDeltaTime ); - void LoadFromSong( Song* pSong ); // NULL means no song - void LoadAllMusic(); + /** + * @brief Attempt to load the banner from a song. + * @param pSong the song in question. If NULL, there is no song. + */ + void LoadFromSong( Song* pSong ); void LoadMode(); void LoadFromSongGroup( RString sSongGroup ); void LoadFromCourse( const Course *pCourse ); @@ -34,12 +39,14 @@ public: void LoadBackgroundFromUnlockEntry( const UnlockEntry* pUE ); void LoadRoulette(); void LoadRandom(); + void LoadFromSortOrder( SortOrder so ); void LoadFallback(); void LoadFallbackBG(); void LoadCourseFallback(); void LoadFallbackCharacterIcon(); void SetScrolling( bool bScroll, float Percent = 0 ); + bool GetScrolling() const { return m_bScrolling; } float ScrollingPercent() const { return m_fPercentScrolling; } // Lua @@ -52,8 +59,10 @@ protected: #endif -/* - * (c) 2001-2004 Chris Danford +/** + * @file + * @author Chris Danford (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/BitmapText.cpp b/src/BitmapText.cpp index 08b0fcb1bf..141a661c75 100644 --- a/src/BitmapText.cpp +++ b/src/BitmapText.cpp @@ -136,7 +136,6 @@ void BitmapText::LoadFromNode( const XNode* pNode ) Actor::LoadFromNode( pNode ); } - bool BitmapText::LoadFromFont( const RString& sFontFilePath ) { CHECKPOINT_M( ssprintf("BitmapText::LoadFromFont(%s)", sFontFilePath.c_str()) ); @@ -156,7 +155,6 @@ bool BitmapText::LoadFromFont( const RString& sFontFilePath ) return true; } - bool BitmapText::LoadFromTextureAndChars( const RString& sTexturePath, const RString& sChars ) { CHECKPOINT_M( ssprintf("BitmapText::LoadFromTextureAndChars(\"%s\",\"%s\")", sTexturePath.c_str(), sChars.c_str()) ); @@ -345,7 +343,7 @@ void BitmapText::DrawChars( bool bUseStrokeTexture ) else DISPLAY->SetTexture( TextureUnit_1, m_vpFontPageTextures[start]->m_pTextureMain->GetTexHandle() ); - /* Don't bother setting texture render states for text. We never go outside of 0..1. */ + /* Don't bother setting texture render states for text. We never go outside of 0..1. */ /* We should call SetTextureRenderStates because it does more than just setting * the texture wrapping state. If setting the wrapping state is found to be slow, * there should probably be a "don't care" texture wrapping mode set in Actor. -Chris */ @@ -360,8 +358,8 @@ void BitmapText::DrawChars( bool bUseStrokeTexture ) } } -/* sText is UTF-8. If not all of the characters in sText are available in the - * font, sAlternateText will be used instead. If there are unavailable characters +/* sText is UTF-8. If not all of the characters in sText are available in the + * font, sAlternateText will be used instead. If there are unavailable characters * in sAlternateText, too, just use sText. */ void BitmapText::SetText( const RString& _sText, const RString& _sAlternateText, int iWrapWidthPixels ) { @@ -396,13 +394,13 @@ void BitmapText::SetTextInternal() } else { - // Break sText into lines that don't exceed iWrapWidthPixels - // (if only one word fits on the line, it may be larger than iWrapWidthPixels). + // Break sText into lines that don't exceed iWrapWidthPixels. (if only + // one word fits on the line, it may be larger than iWrapWidthPixels). // This does not work in all languages: /* "...I can add Japanese wrapping, at least. We could handle hyphens * and soft hyphens and pretty easily, too." -glenn */ - // TODO: Move this wrapping logic into Font + // TODO: Move this wrapping logic into Font. vector asLines; split( m_sText, "\n", asLines, false ); @@ -695,15 +693,9 @@ void BitmapText::DrawPrimitives() /* Draw glow using the base texture and the glow texture. Otherwise, * glow looks too tame on BitmapText that has a stroke. - Chris Danford */ /* This doesn't work well if the font is using an invisible stroke, as - * the invisible stroke will glow as well. Time for TextGlowMode. -aj */ - if(m_TextGlowMode == TextGlowMode_Inner || m_TextGlowMode == TextGlowMode_Both) - { - DrawChars( false ); - } - if(m_TextGlowMode == TextGlowMode_Stroke || m_TextGlowMode == TextGlowMode_Both) - { - DrawChars( true ); - } + * the invisible stroke will glow as well. Time for TextGlowMode. + * Only draw the strokes if the glow mode is not inner only. -aj */ + DrawChars(m_TextGlowMode != TextGlowMode_Inner); } } @@ -813,11 +805,11 @@ public: { RString s = SArg(1); RString sAlt; - // XXX: Lua strings should simply use "\n" natively. However, some - // settext calls may be made from GetMetric() calls to other strings, - // and it's confusing for :: to work in some strings and not others. - // Eventually, all strings should be Lua expressions, but until then - // continue to support this. + /* XXX: Lua strings should simply use "\n" natively. However, some + * settext calls may be made from GetMetric() calls to other strings, and + * it's confusing for :: to work in some strings and not others. + * Eventually, all strings should be Lua expressions, but until then, + * continue to support this. */ s.Replace("::","\n"); FontCharAliases::ReplaceMarkers( s ); @@ -863,6 +855,8 @@ public: ADD_METHOD( strokecolor ); ADD_METHOD( uppercase ); ADD_METHOD( textglowmode ); + //ADD_METHOD( LoadFromFont ); + //ADD_METHOD( LoadFromTextureAndChars ); } }; diff --git a/src/Character.cpp b/src/Character.cpp index e158089ffc..ac8a8da14d 100644 --- a/src/Character.cpp +++ b/src/Character.cpp @@ -17,7 +17,6 @@ bool Character::Load( RString sCharDir ) sCharDir += "/"; m_sCharDir = sCharDir; - // save ID { vector as; @@ -61,7 +60,7 @@ bool Character::Load( RString sCharDir ) // get optional display name ini.GetValue( "Character", "DisplayName", m_sDisplayName ); - + // get optional InitCommand RString s; ini.GetValue( "Character", "InitCommand", s ); @@ -70,7 +69,6 @@ bool Character::Load( RString sCharDir ) return true; } - RString GetRandomFileInDir( RString sDir ) { vector asFiles; @@ -81,7 +79,6 @@ RString GetRandomFileInDir( RString sDir ) return asFiles[RandomInt(asFiles.size())]; } - RString Character::GetModelPath() const { RString s = m_sCharDir + "model.txt"; @@ -214,6 +211,7 @@ public: static int GetDanceAnimationPath( T* p, lua_State *L ) { lua_pushstring(L, p->GetDanceAnimationPath() ); return 1; } static int GetCharacterDir( T* p, lua_State *L ) { lua_pushstring(L, p->m_sCharDir ); return 1; } static int GetCharacterID( T* p, lua_State *L ) { lua_pushstring(L, p->m_sCharacterID ); return 1; } + static int GetDisplayName( T* p, lua_State *L ) { lua_pushstring(L, p->GetDisplayName() ); return 1; } LunaCharacter() { @@ -228,6 +226,7 @@ public: ADD_METHOD( GetDanceAnimationPath ); ADD_METHOD( GetCharacterDir ); ADD_METHOD( GetCharacterID ); + ADD_METHOD( GetDisplayName ); } }; diff --git a/src/Command.h b/src/Command.h index cce86734a9..0a0b6b8da0 100644 --- a/src/Command.h +++ b/src/Command.h @@ -9,8 +9,7 @@ public: void Load( const RString &sCommand ); RString GetOriginalCommandString() const; // used when reporting an error in number of args - - RString GetName() const; // the command name is the first argument in all-lowercase + RString GetName() const; // the command name is the first argument in all-lowercase void Clear() { m_vsArgs.clear(); } @@ -32,10 +31,9 @@ public: }; // Take a command list string and return pointers to each of the tokens in the -// string. sCommand list is a list of commands separated by ';'. -// TODO: This is expensive to do during the game. Eventually, -// move all calls to ParseCommands to happen during load, then execute -// from the parsed Command structures. +// string. sCommand list is a list of commands separated by ';'. +// TODO: This is expensive to do during the game. Eventually, move all calls to +// ParseCommands to happen during load, then execute from the parsed Command structures. void ParseCommands( const RString &sCmds, Commands &vCmdsOut ); Commands ParseCommands( const RString &sCmds ); diff --git a/src/CommandLineActions.cpp b/src/CommandLineActions.cpp index e073afb7df..7d852d1f76 100644 --- a/src/CommandLineActions.cpp +++ b/src/CommandLineActions.cpp @@ -24,6 +24,7 @@ #include #endif +/** @brief The directory where languages should be installed. */ const RString INSTALLER_LANGUAGES_DIR = "Themes/_Installer/Languages/"; vector CommandLineActions::ToProcess; @@ -82,11 +83,14 @@ extern const char *const version_date; extern const char *const version_time; #endif +/** + * @brief Print out version information. + * + * HACK: This function is primarily needed for Windows users. + * Mac OS X and Linux print out version information on the command line + * regardless of any preferences (tested by shakesoda on Mac). -aj */ static void Version() { - /* HACK: This is only needed on Windows. - Mac and Linux print out version information on the command line regardless - of any preferences (tested by shakesoda on Mac). -aj */ #if defined(WIN32) RString sProductID = ssprintf("%s", PRODUCT_ID_VER); RString sVersion = "(sm-ssc was built without HAVE_VERSION_INFO)"; diff --git a/src/CommandLineActions.h b/src/CommandLineActions.h index 805508912e..fdbaef8919 100644 --- a/src/CommandLineActions.h +++ b/src/CommandLineActions.h @@ -3,25 +3,34 @@ class LoadingWindow; +/** @brief The collection of command line actions. */ namespace CommandLineActions { - void Handle(LoadingWindow* pLW); // perform a utility action, then exit + /** + * @brief Perform a utility function, then exit. + * @param pLW the LoadingWindow that is presently not used? */ + void Handle(LoadingWindow* pLW); + /** @brief The housing for the command line arguments. */ class CommandLineArgs { public: + /** @brief the arguments in question. */ vector argv; }; - // a list of command line arguemnts to process while the game is running. - // These args could have come from this process or passed to this process - // from another process. + /** + * @brief A list of command line arguemnts to process while the game is running. + * These args could have come from this process or passed to this process + * from another process. */ extern vector ToProcess; } #endif -/* - * (c) 2006 Chris Danford, Steve Checkoway +/** + * @file + * @author Chris Danford, Steve Checkoway (c) 2006 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/CommonMetrics.h b/src/CommonMetrics.h index 378257ab75..2c9db444bf 100644 --- a/src/CommonMetrics.h +++ b/src/CommonMetrics.h @@ -1,4 +1,4 @@ -/* CommonMetrics - Definitions of metrics that are in the "Common" group */ +/** @brief CommonMetrics - Definitions of metrics that are in the "Common" group */ #ifndef COMMON_METRICS_H #define COMMON_METRICS_H @@ -42,19 +42,25 @@ private: }; -// Metrics +/** @brief The common metrics that are used throughout. */ namespace CommonMetrics { extern ThemeMetric FIRST_ATTRACT_SCREEN; extern ThemeMetric DEFAULT_MODIFIERS; - extern LocalizedString WINDOW_TITLE; + /** @brief the phrase that appears on the title bar. */ + extern LocalizedString WINDOW_TITLE; extern ThemeMetric MAX_COURSE_ENTRIES_BEFORE_VARIOUS; - extern ThemeMetric TICK_EARLY_SECONDS; + extern ThemeMetric TICK_EARLY_SECONDS; + /** @brief the name of the default noteskin. */ extern ThemeMetric DEFAULT_NOTESKIN_NAME; - extern ThemeMetricDifficultiesToShow DIFFICULTIES_TO_SHOW; + /** @brief Which difficulties are to be shown? */ + extern ThemeMetricDifficultiesToShow DIFFICULTIES_TO_SHOW; + /** @brief Which course difficulties are to be shown? */ extern ThemeMetricCourseDifficultiesToShow COURSE_DIFFICULTIES_TO_SHOW; + /** @brief Which step types are to be shown? */ extern ThemeMetricStepsTypesToShow STEPS_TYPES_TO_SHOW; - extern ThemeMetric AUTO_SET_STYLE; + extern ThemeMetric AUTO_SET_STYLE; + /** @brief How many decimal places are used? */ extern ThemeMetric PERCENT_SCORE_DECIMAL_PLACES; RString LocalizeOptionItem( const RString &s, bool bOptional ); @@ -62,8 +68,10 @@ namespace CommonMetrics #endif -/* - * (c) 2003-2004 Chris Danford +/** + * @file + * @author Chris Danford (c) 2003-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/CourseContentsList.cpp b/src/CourseContentsList.cpp index 0c73ab5053..98dfa1d61f 100644 --- a/src/CourseContentsList.cpp +++ b/src/CourseContentsList.cpp @@ -42,10 +42,6 @@ void CourseContentsList::SetFromGameState() { RemoveAllChildren(); - // FIXME: Is there a better way to handle when players don't have - // the same number of TrailEntries? - // They have to have the same number, and of the same songs, or gameplay - // isn't going to line up. if( GAMESTATE->m_MasterPlayerNumber == PlayerNumber_Invalid ) return; const Trail *pMasterTrail = GAMESTATE->m_pCurTrail[GAMESTATE->m_MasterPlayerNumber]; diff --git a/src/CourseLoaderCRS.cpp b/src/CourseLoaderCRS.cpp index 7f380cbf80..e780b7b0d1 100644 --- a/src/CourseLoaderCRS.cpp +++ b/src/CourseLoaderCRS.cpp @@ -16,8 +16,10 @@ #include "CourseUtil.h" #include +/** @brief Edit courses can only be so big before they are rejected. */ const int MAX_EDIT_COURSE_SIZE_BYTES = 32*1024; // 32KB +/** @brief The list of difficulty names for courses. */ const char *g_CRSDifficultyNames[] = { "Beginner", @@ -28,6 +30,11 @@ const char *g_CRSDifficultyNames[] = "Edit", }; +/** + * @brief Retrieve the course difficulty based on the string name. + * @param s the name of the difficulty. + * @return the course difficulty. + */ static CourseDifficulty CRSStringToDifficulty( const RString& s ) { FOREACH_ENUM( Difficulty,i) @@ -99,6 +106,7 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou out.m_iCustomMeter[cd] = max( atoi(sParams[2]), 0 ); } } + // todo: add COMBO and COMBOMODE from DWI CRS files? -aj else if( 0 == stricmp(sValueName, "MODS") ) { diff --git a/src/CourseLoaderCRS.h b/src/CourseLoaderCRS.h index 574a87bbf8..e03081a3f4 100644 --- a/src/CourseLoaderCRS.h +++ b/src/CourseLoaderCRS.h @@ -1,4 +1,4 @@ -/* CourseLoaderCRS - Reads a Course from an .CRS file. */ +/** @brief CourseLoaderCRS - Reads a Course from an .CRS file. */ #ifndef COURSE_LOADER_CRS_H #define COURSE_LOADER_CRS_H @@ -7,19 +7,56 @@ class Course; class MsdFile; +/** @brief The Course Loader handles parsing the .crs files. */ namespace CourseLoaderCRS { + /** + * @brief Attempt to load a course file from a particular path. + * @param sPath the path to the file. + * @param out the course file. + * @return its success or failure. + */ bool LoadFromCRSFile( const RString &sPath, Course &out ); + /** + * @brief Attempt to load the course information from the msd context. + * @param sPath the path to the file. + * @param msd the MSD context. + * @param out the course file. + * @param bFromCache true if loading from the cache area. + * @return its success or failure. + */ bool LoadFromMsd( const RString &sPath, const MsdFile &msd, Course &out, bool bFromCache ); + /** + * @brief Attempt to load the course file from the buffer. + * @param sPath the path to the file. + * @param sBuffer the path to the buffer. + * @param out the course file. + * @return its success or failure. + */ bool LoadFromBuffer( const RString &sPath, const RString &sBuffer, Course &out ); + /** + * @brief Attempt to load an edit course from the hard drive. + * @param sEditFilePath a path on the hard drive to check. + * @param slot the Profile of the user with the edit course. + * @return its success or failure. + */ bool LoadEditFromFile( const RString &sEditFilePath, ProfileSlot slot ); + /** + * @brief Attempt to load an edit course from the buffer. + * @param sBuffer the path to the buffer. + * @param sPath the path to the file. + * @param slot the individual's profile. + * @return its success or failure. + */ bool LoadEditFromBuffer( const RString &sBuffer, const RString &sPath, ProfileSlot slot ); } #endif -/* - * (c) 2001-2004 Chris Danford +/** + * @file + * @author Chris Danford (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/CourseUtil.h b/src/CourseUtil.h index 80bf355c6f..d0c4738cef 100644 --- a/src/CourseUtil.h +++ b/src/CourseUtil.h @@ -1,4 +1,4 @@ -/* CourseUtil - Utility functions that deal with Course. */ +/** @brief CourseUtil - Utility functions that deal with Course. */ #ifndef COURSEUTIL_H #define COURSEUTIL_H @@ -93,8 +93,10 @@ private: #endif -/* - * (c) 2001-2004 Chris Danford +/** + * @file + * @author Chris Danford (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/CourseWriterCRS.cpp b/src/CourseWriterCRS.cpp index c69b405a7b..390fa45367 100644 --- a/src/CourseWriterCRS.cpp +++ b/src/CourseWriterCRS.cpp @@ -7,8 +7,14 @@ #include "Song.h" #include "RageFileDriverMemory.h" +/** @brief Load the difficulty names from CourseLoaderCRS. */ extern const char *g_CRSDifficultyNames[]; // in CourseLoaderCRS +/** + * @brief Get the string of the course difficulty. + * @param iVal the course difficulty. + * @return the string. + */ static RString DifficultyToCRSString( CourseDifficulty iVal ) { return g_CRSDifficultyNames[iVal]; diff --git a/src/CourseWriterCRS.h b/src/CourseWriterCRS.h index 3896e4ce99..9b2887c809 100644 --- a/src/CourseWriterCRS.h +++ b/src/CourseWriterCRS.h @@ -1,4 +1,4 @@ -/* CourseWriterCRS - Writes a Course to an .CRS file. */ +/** @brief CourseWriterCRS - Writes a Course to an .CRS file. */ #ifndef COURSE_WRITER_CRS_H #define COURSE_WRITER_CRS_H @@ -6,18 +6,44 @@ class Course; class RageFileBasic; +/** @brief The Course Writer handles writing the .crs files. */ namespace CourseWriterCRS { + /** + * @brief Write the course to a file. + * @param course the course contents. + * @param f the file being built. + * @param bSavingCache is true if cache information is being saved as well. + * @return its success or failure. + */ bool Write( const Course &course, RageFileBasic &f, bool bSavingCache ); + /** + * @brief Write the course to a file. + * @param course the course contents. + * @param sPath the path to the file. + * @param bSavingCache is true if cache information is being saved as well. + * @return its success or failure. + */ bool Write( const Course &course, const RString &sPath, bool bSavingCache ); + /** + * @brief Retrieve course information from a file for eventual writing. + * @param pCourse the course file. + * @param sOut the path to the file. + */ void GetEditFileContents( const Course *pCourse, RString &sOut ); + /** + * @brief Write the custom course to the machine's hard drive. + * @param pCourse the course file. + */ void WriteEditFileToMachine( const Course *pCourse ); } #endif -/* - * (c) 2001-2005 Chris Danford +/** + * @file + * @author Chris Danford (c) 2001-2005 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/DateTime.cpp b/src/DateTime.cpp index 3ad458b1d3..ba69d02f03 100644 --- a/src/DateTime.cpp +++ b/src/DateTime.cpp @@ -42,6 +42,20 @@ bool DateTime::operator==( const DateTime& other ) const return true; } +bool DateTime::operator>( const DateTime& other ) const +{ +#define COMPARE( v ) if(v!=other.v) return v>other.v; + COMPARE( tm_year ); + COMPARE( tm_mon ); + COMPARE( tm_mday ); + COMPARE( tm_hour ); + COMPARE( tm_min ); + COMPARE( tm_sec ); +#undef COMPARE + // they're equal + return false; +} + DateTime DateTime::GetNowDateTime() { time_t now = time(NULL); @@ -73,9 +87,7 @@ void DateTime::StripTime() tm_sec = 0; } -// // Common SQL/XML format: "YYYY-MM-DD HH:MM:SS" -// RString DateTime::GetString() const { RString s = ssprintf( "%d-%02d-%02d", diff --git a/src/DateTime.h b/src/DateTime.h index c0d0fac6d6..3fa1735bd0 100644 --- a/src/DateTime.h +++ b/src/DateTime.h @@ -45,6 +45,7 @@ struct DateTime void Init(); bool operator<( const DateTime& other ) const; + bool operator>( const DateTime& other ) const; bool operator==( const DateTime& other ) const; bool operator!=( const DateTime& other ) const { return !operator==(other); } diff --git a/src/Difficulty.cpp b/src/Difficulty.cpp index 0a4cf2d244..1fc675b7db 100644 --- a/src/Difficulty.cpp +++ b/src/Difficulty.cpp @@ -21,37 +21,35 @@ XToString( Difficulty ); StringToX( Difficulty ); LuaXType( Difficulty ); -/* We prefer the above names; recognize a number of others, too. (They'll - * get normalized when written to SMs, etc.) */ -/* TODO: Format specific hacks should be moved into the file loader for - * that format. We don't want to carry these hacks forward to file - * formats that don't need them. */ +/* We prefer the above names; recognize a number of others, too. (They'll get + * normalized when written to SMs, etc.) TODO: Format specific hacks should be + * moved into the file loader for that format. We don't want to carry these + * hacks forward to file formats that don't need them. */ Difficulty DwiCompatibleStringToDifficulty( const RString& sDC ) { RString s2 = sDC; s2.MakeLower(); - if( s2 == "beginner" ) return Difficulty_Beginner; + if( s2 == "beginner" ) return Difficulty_Beginner; else if( s2 == "easy" ) return Difficulty_Easy; - else if( s2 == "basic" ) return Difficulty_Easy; - else if( s2 == "light" ) return Difficulty_Easy; - else if( s2 == "medium" ) return Difficulty_Medium; - else if( s2 == "another" ) return Difficulty_Medium; - else if( s2 == "trick" ) return Difficulty_Medium; + else if( s2 == "basic" ) return Difficulty_Easy; + else if( s2 == "light" ) return Difficulty_Easy; + else if( s2 == "medium" ) return Difficulty_Medium; + else if( s2 == "another" ) return Difficulty_Medium; + else if( s2 == "trick" ) return Difficulty_Medium; else if( s2 == "standard" ) return Difficulty_Medium; else if( s2 == "difficult") return Difficulty_Medium; else if( s2 == "hard" ) return Difficulty_Hard; - else if( s2 == "ssr" ) return Difficulty_Hard; - else if( s2 == "maniac" ) return Difficulty_Hard; - else if( s2 == "heavy" ) return Difficulty_Hard; - else if( s2 == "smaniac" ) return Difficulty_Challenge; + else if( s2 == "ssr" ) return Difficulty_Hard; + else if( s2 == "maniac" ) return Difficulty_Hard; + else if( s2 == "heavy" ) return Difficulty_Hard; + else if( s2 == "smaniac" ) return Difficulty_Challenge; else if( s2 == "challenge" ) return Difficulty_Challenge; - else if( s2 == "expert" ) return Difficulty_Challenge; - else if( s2 == "oni" ) return Difficulty_Challenge; + else if( s2 == "expert" ) return Difficulty_Challenge; + else if( s2 == "oni" ) return Difficulty_Challenge; else if( s2 == "edit" ) return Difficulty_Edit; - else return Difficulty_Invalid; + else return Difficulty_Invalid; } - const RString &CourseDifficultyToLocalizedString( CourseDifficulty x ) { static auto_ptr g_CourseDifficultyName[NUM_Difficulty]; @@ -86,6 +84,8 @@ RString GetCustomDifficulty( StepsType st, Difficulty dc, CourseType ct ) * sure what the correct behavior in this case should be. Should we still * allow custom difficulties? Why do we not allow custom difficulties for * Couple, Routine, or Edit? - Steve */ + // CustomDifficulty for Edit defeats the purpose of the edit's name. + // I don't know the other two. -aj if( st == StepsType_Invalid ) { /* This is not totally necessary since DifficultyToString() will @@ -161,13 +161,11 @@ RString TrailToCustomDifficulty( const Trail *pTrail ) return GetCustomDifficulty( pTrail->m_StepsType, pTrail->m_CourseDifficulty, pTrail->m_CourseType ); } - #include "LuaBinding.h" LuaFunction( StepsToCustomDifficulty, StepsToCustomDifficulty(Luna::check(L, 1)) ); LuaFunction( TrailToCustomDifficulty, TrailToCustomDifficulty(Luna::check(L, 1)) ); - /* * (c) 2001-2004 Chris Danford * All rights reserved. diff --git a/src/DifficultyList.cpp b/src/DifficultyList.cpp index 87eb1a2268..668061d8c8 100644 --- a/src/DifficultyList.cpp +++ b/src/DifficultyList.cpp @@ -78,6 +78,7 @@ void StepsDisplayList::LoadFromNode( const XNode* pNode ) for( unsigned m = 0; m < m_Lines.size(); ++m ) { + // todo: Use Row1, Row2 for names? also m_sName+"Row" -aj m_Lines[m].m_Meter.SetName( "Row" ); m_Lines[m].m_Meter.Load( "StepsDisplayListRow", NULL ); this->AddChild( &m_Lines[m].m_Meter ); diff --git a/src/FadingBanner.cpp b/src/FadingBanner.cpp index c8609ab192..b3bbe3e81a 100644 --- a/src/FadingBanner.cpp +++ b/src/FadingBanner.cpp @@ -181,12 +181,6 @@ void FadingBanner::LoadFromSong( const Song* pSong ) LoadFromCachedBanner( sPath ); } -void FadingBanner::LoadAllMusic() -{ - BeforeChange(); - m_Banner[m_iIndexLatest].LoadAllMusic(); -} - void FadingBanner::LoadMode() { BeforeChange(); @@ -240,6 +234,12 @@ void FadingBanner::LoadRandom() m_Banner[m_iIndexLatest].LoadRandom(); } +void FadingBanner::LoadFromSortOrder( SortOrder so ) +{ + BeforeChange(); + m_Banner[m_iIndexLatest].LoadFromSortOrder(so); +} + void FadingBanner::LoadFallback() { BeforeChange(); @@ -252,7 +252,6 @@ void FadingBanner::LoadCourseFallback() m_Banner[m_iIndexLatest].LoadCourseFallback(); } - // lua start #include "LuaBinding.h" @@ -286,6 +285,7 @@ public: return 0; } static int LoadFromSongGroup( T* p, lua_State *L ) { p->LoadFromSongGroup( SArg(1) ); return 0; } + static int GetLatestIndex( T* p, lua_State *L ){ lua_pushnumber( L, p->GetLatestIndex() ); return 1; } LunaFadingBanner() { @@ -296,6 +296,7 @@ public: ADD_METHOD( LoadFromCourse ); ADD_METHOD( LoadIconFromCharacter ); ADD_METHOD( LoadCardFromCharacter ); + ADD_METHOD( GetLatestIndex ); } }; diff --git a/src/FadingBanner.h b/src/FadingBanner.h index f86198110f..8d46fcaf78 100644 --- a/src/FadingBanner.h +++ b/src/FadingBanner.h @@ -19,7 +19,6 @@ public: * resolution banner, set bLowResToHighRes to true. */ void Load( RageTextureID ID, bool bLowResToHighRes=false ); void LoadFromSong( const Song* pSong ); // NULL means no song - void LoadAllMusic(); void LoadMode(); void LoadFromSongGroup( RString sSongGroup ); void LoadFromCourse( const Course* pCourse ); @@ -27,6 +26,7 @@ public: void LoadBannerFromUnlockEntry( const UnlockEntry* pUE ); void LoadRoulette(); void LoadRandom(); + void LoadFromSortOrder( SortOrder so ); void LoadFallback(); void LoadCourseFallback(); @@ -37,6 +37,8 @@ public: virtual void UpdateInternal( float fDeltaTime ); virtual void DrawPrimitives(); + int GetLatestIndex(){ return m_iIndexLatest; } + // Lua void PushSelf( lua_State *L ); @@ -44,11 +46,11 @@ protected: void BeforeChange( bool bLowResToHighRes=false ); static const int NUM_BANNERS = 5; - Banner m_Banner[NUM_BANNERS]; + Banner m_Banner[NUM_BANNERS]; int m_iIndexLatest; - bool m_bMovingFast; - bool m_bSkipNextBannerUpdate; + bool m_bMovingFast; + bool m_bSkipNextBannerUpdate; }; #endif diff --git a/src/FileDownload.cpp b/src/FileDownload.cpp index a9a9678f4a..9a643f2195 100644 --- a/src/FileDownload.cpp +++ b/src/FileDownload.cpp @@ -201,7 +201,7 @@ void FileTransfer::StartTransfer( TransferType type, const RString &sURL, const } */ - vsHeaders.push_back( "Content-Length: " + ssprintf("%d",sRequestPayload.size()) ); + vsHeaders.push_back( "Content-Length: " + ssprintf("%zd",sRequestPayload.size()) ); RString sHeader; FOREACH_CONST( RString, vsHeaders, h ) diff --git a/src/Font.cpp b/src/Font.cpp index e012dcb898..ec00195979 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -202,7 +202,7 @@ FontPage::~FontPage() int Font::GetLineWidthInSourcePixels( const wstring &szLine ) const { int iLineWidth = 0; - + for( unsigned i=0; iTrace( "Font::LoadFromFontName(%s)", sASCIITexturePath.c_str() ); - m_iRefCount = 1; m_pDefault = NULL; m_bRightToLeft = false; @@ -239,10 +237,11 @@ Font::~Font() void Font::Unload() { + LOG->Trace("Font:Unload '%s'",path.c_str()); for( unsigned i = 0; i < m_apPages.size(); ++i ) delete m_apPages[i]; m_apPages.clear(); - + m_iCharToGlyph.clear(); m_pDefault = NULL; @@ -656,6 +655,8 @@ void Font::Load( const RString &sIniPath, RString sChars ) { ASSERT_M( !GetExtension(sIniPath).CompareNoCase("ini"), sIniPath ); + LOG->Trace( "Font: Loading new font '%s'",sIniPath.c_str()); + // Check for recursion (recursive imports). for( unsigned i = 0; i < LoadStack.size(); ++i ) { @@ -725,9 +726,9 @@ void Font::Load( const RString &sIniPath, RString sChars ) continue; } - Font subfont; - subfont.Load(path, ""); - MergeFont(subfont); + Font *subfont=FONT->LoadFont(path,""); + MergeFont(*subfont); + FONT->UnloadFont(subfont); } } diff --git a/src/FontManager.cpp b/src/FontManager.cpp index 7830f60675..837a5d5aa1 100644 --- a/src/FontManager.cpp +++ b/src/FontManager.cpp @@ -22,7 +22,9 @@ FontManager::~FontManager() { const FontName &fn = i->first; Font* pFont = i->second; - LOG->Trace( "FONT LEAK: '%s', RefCount = %d.", fn.first.c_str(), pFont->m_iRefCount ); + if(pFont->m_iRefCount>0) { + LOG->Trace( "FONT LEAK: '%s', RefCount = %d.", fn.first.c_str(), pFont->m_iRefCount ); + } delete pFont; } } @@ -38,6 +40,9 @@ void FontManager::ReloadFonts() Font* FontManager::LoadFont( const RString &sFontOrTextureFilePath, RString sChars ) { + PruneFonts(); + + Font *pFont; // Convert the path to lowercase so that we don't load duplicates. // Really, this does not solve the duplicate problem. We could have two copies // of the same bitmap if there are equivalent but different paths @@ -48,15 +53,16 @@ Font* FontManager::LoadFont( const RString &sFontOrTextureFilePath, RString sCha map::iterator p = g_mapPathToFont.find( NewName ); if( p != g_mapPathToFont.end() ) { - Font *pFont=p->second; - pFont->m_iRefCount++; - return pFont; + pFont=p->second; + } + else { + pFont= new Font; + pFont->Load(sFontOrTextureFilePath, sChars); + g_mapPathToFont[NewName] = pFont; } - Font *f = new Font; - f->Load(sFontOrTextureFilePath, sChars); - g_mapPathToFont[NewName] = f; - return f; + ++pFont->m_iRefCount; + return pFont; } Font *FontManager::CopyFont( Font *pFont ) @@ -75,19 +81,29 @@ void FontManager::UnloadFont( Font *fp ) if(i->second != fp) continue; + ASSERT_M(fp->m_iRefCount>0,"Attempting to unload a font with zero ref count!"); + i->second->m_iRefCount--; - if( fp->m_iRefCount == 0 ) - { - delete i->second; // free the texture - g_mapPathToFont.erase( i ); // and remove the key in the map - } return; } - + FAIL_M( ssprintf("Unloaded an unknown font (%p)", fp) ); } +void FontManager::PruneFonts() { + for( std::map::iterator i = g_mapPathToFont.begin();i != g_mapPathToFont.end();) { + Font *fp=i->second; + if(fp->m_iRefCount==0) { + delete fp; + g_mapPathToFont.erase(i); + i = g_mapPathToFont.end(); + } else { + ++i; + } + } +} + /* * (c) 2001-2003 Chris Danford, Glenn Maynard * All rights reserved. diff --git a/src/FontManager.h b/src/FontManager.h index 1aad869ce7..9124d694f9 100644 --- a/src/FontManager.h +++ b/src/FontManager.h @@ -15,6 +15,7 @@ public: Font* LoadFont( const RString &sFontOrTextureFilePath, RString sChars = "" ); Font *CopyFont( Font *pFont ); void UnloadFont( Font *fp ); + void PruneFonts(); /* Warning: This reloads fonts completely, so all BitmapTexts need to be * reset, too. If this isn't done, best case they end up with old font diff --git a/src/GameCommand.cpp b/src/GameCommand.cpp index dc474abed7..b6717b8fb6 100644 --- a/src/GameCommand.cpp +++ b/src/GameCommand.cpp @@ -852,6 +852,8 @@ bool GameCommand::IsZero() const // lua start #include "LuaBinding.h" #include "Game.h" +#include "Steps.h" +#include "Character.h" class LunaGameCommand: public Luna { @@ -861,8 +863,13 @@ public: static int GetIndex( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iIndex ); return 1; } static int GetMultiPlayer( T* p, lua_State *L ) { lua_pushnumber(L, p->m_MultiPlayer); return 1; } static int GetStyle( T* p, lua_State *L ) { if(p->m_pStyle==NULL) lua_pushnil(L); else {Style *pStyle = (Style*)p->m_pStyle; pStyle->PushSelf(L);} return 1; } + static int GetScreen( T* p, lua_State *L ) { lua_pushstring(L, p->m_sScreen ); return 1; } static int GetProfileID( T* p, lua_State *L ) { lua_pushstring(L, p->m_sProfileID ); return 1; } static int GetSong( T* p, lua_State *L ) { if(p->m_pSong==NULL) lua_pushnil(L); else p->m_pSong->PushSelf(L); return 1; } + static int GetSteps( T* p, lua_State *L ) { if(p->m_pSteps==NULL) lua_pushnil(L); else p->m_pSteps->PushSelf(L); return 1; } + static int GetCourse( T* p, lua_State *L ) { if(p->m_pCourse==NULL) lua_pushnil(L); else p->m_pCourse->PushSelf(L); return 1; } + static int GetTrail( T* p, lua_State *L ) { if(p->m_pTrail==NULL) lua_pushnil(L); else p->m_pTrail->PushSelf(L); return 1; } + static int GetCharacter( T* p, lua_State *L ) { if(p->m_pCharacter==NULL) lua_pushnil(L); else p->m_pCharacter->PushSelf(L); return 1; } static int GetSongGroup( T* p, lua_State *L ) { lua_pushstring(L, p->m_sSongGroup ); return 1; } static int GetUrl( T* p, lua_State *L ) { lua_pushstring(L, p->m_sUrl ); return 1; } @@ -873,9 +880,18 @@ public: ADD_METHOD( GetIndex ); ADD_METHOD( GetMultiPlayer ); ADD_METHOD( GetStyle ); + //ADD_METHOD( GetDifficulty ); + //ADD_METHOD( GetCourseDifficulty ); + ADD_METHOD( GetScreen ); + //ADD_METHOD( GetPlayMode ); ADD_METHOD( GetProfileID ); ADD_METHOD( GetSong ); + ADD_METHOD( GetSteps ); + ADD_METHOD( GetCourse ); + ADD_METHOD( GetTrail ); + ADD_METHOD( GetCharacter ); ADD_METHOD( GetSongGroup ); + //ADD_METHOD( GetSortOrder ); ADD_METHOD( GetUrl ); } }; diff --git a/src/GameConstantsAndTypes.h b/src/GameConstantsAndTypes.h index 8889bc0752..9bd115b913 100644 --- a/src/GameConstantsAndTypes.h +++ b/src/GameConstantsAndTypes.h @@ -6,49 +6,66 @@ #include "EnumHelper.h" // Note definitions -// Use 1-35 instead of 1-13. -aj -/* 35 is used because we have to be mindful of Profile data. - * See Profile::InitGeneralData() for how MAX_METER is used. -aj */ +/** @brief Define the mininum difficulty value allowed. */ const int MIN_METER = 1; +/** + * @brief Define the maximum difficulty value allowed. + * + * 35 is used rather than 13 due to a variety of Profile data. + * For more examples, see Profile::InitGeneralData(). -aj + */ const int MAX_METER = 35; -// Credits +/** @brief The maximum number of credits for coin mode. */ const int MAX_NUM_CREDITS = 20; -/* This is just cached song data. Not all of it may actually be displayed +/** + * @brief The various radar categories available. + * + * This is just cached song data. Not all of it may actually be displayed * in the radar. */ enum RadarCategory { - RadarCategory_Stream = 0, - RadarCategory_Voltage, - RadarCategory_Air, - RadarCategory_Freeze, - RadarCategory_Chaos, - RadarCategory_TapsAndHolds, - RadarCategory_Jumps, - RadarCategory_Holds, - RadarCategory_Mines, - RadarCategory_Hands, - RadarCategory_Rolls, - RadarCategory_Lifts, - NUM_RadarCategory, // leave this at the end + RadarCategory_Stream = 0, /**< How much stream is in the song? */ + RadarCategory_Voltage, /**< How much voltage is in the song? */ + RadarCategory_Air, /**< How much air is in the song? */ + RadarCategory_Freeze, /**< How much freeze (holds) is in the song? */ + RadarCategory_Chaos, /**< How much chaos is in the song? */ + RadarCategory_TapsAndHolds, /**< How many taps and holds are in the song? */ + RadarCategory_Jumps, /**< How many jumps are in the song? */ + RadarCategory_Holds, /**< How many holds are in the song? */ + RadarCategory_Mines, /**< How many mines are in the song? */ + RadarCategory_Hands, /**< How many hands are in the song? */ + RadarCategory_Rolls, /**< How many rolls are in the song? */ + RadarCategory_Lifts, /**< How many lifts are in the song? */ + NUM_RadarCategory, /**< The number of radar categories. */ RadarCategory_Invalid }; +/** + * @brief Turn the radar category into a proper string. + * @param cat the radar category. + * @return the string version of the radar category. + */ const RString& RadarCategoryToString( RadarCategory cat ); +/** + * @brief Turn the radar category into a proper localized string. + * @param cat the radar category. + * @return the localized string version of the radar category. + */ const RString& RadarCategoryToLocalizedString( RadarCategory cat ); LuaDeclareType( RadarCategory ); - +/** @brief The different game categories available to play. */ enum StepsTypeCategory { - StepsTypeCategory_Single, - StepsTypeCategory_Double, - StepsTypeCategory_Couple, - StepsTypeCategory_Routine, + StepsTypeCategory_Single, /**< One person plays on one side. */ + StepsTypeCategory_Double, /**< One person plays on both sides. */ + StepsTypeCategory_Couple, /**< Two players play on their own side. */ + StepsTypeCategory_Routine, /**< Two players share both sides together. */ }; - +/** @brief The different steps types for playing. */ enum StepsType { StepsType_dance_single = 0, @@ -79,6 +96,7 @@ enum StepsType StepsType_techno_single8, StepsType_techno_double4, StepsType_techno_double5, + StepsType_techno_double8, StepsType_popn_five, StepsType_popn_nine, StepsType_guitar_five, @@ -88,24 +106,43 @@ enum StepsType }; LuaDeclareType( StepsType ); -// Play mode stuff +/** @brief The various play modes available. */ enum PlayMode { - PLAY_MODE_REGULAR, - PLAY_MODE_NONSTOP, - PLAY_MODE_ONI, - PLAY_MODE_ENDLESS, - PLAY_MODE_BATTLE, // manually launched attacks - PLAY_MODE_RAVE, // automatically launched attacks + PLAY_MODE_REGULAR, /**< The normal game mode, often with a set number of stages. */ + PLAY_MODE_NONSTOP, /**< Play a set of songs without stopping. */ + PLAY_MODE_ONI, /**< Similar to Nonstop, only there is also the danger of lives or a clock. */ + PLAY_MODE_ENDLESS, /**< Keep playing until you get a game over. */ + PLAY_MODE_BATTLE, /**< Choose when to send attacks to your opponent. */ + PLAY_MODE_RAVE, /**< Have attacks launched during play automatically. */ NUM_PlayMode, PlayMode_Invalid }; +/** + * @brief Turn the play mode into a proper string. + * @param pm the play mode. + * @return the string version of the play mode. + */ const RString& PlayModeToString( PlayMode pm ); +/** + * @brief Turn the play mode into a proper localized string. + * @param pm the play mode. + * @return the localized string version of the play mode. + */ const RString& PlayModeToLocalizedString( PlayMode pm ); +/** + * @brief Turn the string into the proper play mode. + * @param s the string. + * @return the play mode based on the string. + */ PlayMode StringToPlayMode( const RString& s ); LuaDeclareType( PlayMode ); -// ziup2 has SortOrder_PinnedMeter (¿qef?) +/** + * @brief The list of ways to sort songs and courses. + * + * All song sorts should be listed before course sorts. + */ enum SortOrder { // song sorts @@ -139,48 +176,100 @@ enum SortOrder NUM_SortOrder, SortOrder_Invalid }; +/** @brief Only allow certain sort modes to be selectable. */ const SortOrder MAX_SELECTABLE_SORT = (SortOrder)(SORT_ROULETTE-1); +/** + * @brief Turn the sort order into a proper string. + * @param so the sort order. + * @return the string version of the sort order. + */ const RString& SortOrderToString( SortOrder so ); +/** + * @brief Turn the sort order into a proper localized string. + * @param so the sort order. + * @return the localized string version of the sort order. + */ const RString& SortOrderToLocalizedString( SortOrder so ); +/** + * @brief Turn the string into the proper sort order. + * @param str the string. + * @return the sort order based on the string. + */ SortOrder StringToSortOrder( const RString& str ); LuaDeclareType( SortOrder ); -// IsSongSort is only used for saving sort order to the profile. -aj +/** + * @brief Determine if the sort order in question is for songs or not. + * + * This function is mainly used for saving sort order to the profile. -aj + */ inline bool IsSongSort( SortOrder so ) { return so >= SORT_PREFERRED && so <= SORT_DOUBLE_CHALLENGE_METER; } -// Scoring stuff +/** @brief The list of tap note scores available during play. */ enum TapNoteScore { - TNS_None, - TNS_HitMine, - TNS_AvoidMine, - TNS_CheckpointMiss, - TNS_Miss, - TNS_W5, - TNS_W4, - TNS_W3, - TNS_W2, - TNS_W1, - TNS_CheckpointHit, - NUM_TapNoteScore, + TNS_None, /**< There is no score involved with this one. */ + TNS_HitMine, /**< A mine was hit successfully. */ + TNS_AvoidMine, /**< A mine was avoided successfully. */ + TNS_CheckpointMiss, /**< A checkpoint was missed during a hold. */ + TNS_Miss, /**< A note was missed entirely. */ + TNS_W5, /**< A note was almost missed, but not quite. */ + TNS_W4, /**< A note was hit either a bit early or a bit late. */ + TNS_W3, /**< A note was hit with decent accuracy, but not the best. */ + TNS_W2, /**< A note was hit off by just a miniscule amount. This used to be the best rating. */ + TNS_W1, /**< A note was hit perfectly. */ + TNS_CheckpointHit, /**< A checkpoint was held during a hold. */ + NUM_TapNoteScore, /**< The number of Tap Note Scores available. */ TapNoteScore_Invalid, }; +/** + * @brief Turn the tap note score into a proper string. + * @param tns the tap note score. + * @return the string version of the tap note score. + */ const RString& TapNoteScoreToString( TapNoteScore tns ); +/** + * @brief Turn the tap note score into a proper localized string. + * @param tns the tap note score. + * @return the localized string version of the tap note score. + */ const RString& TapNoteScoreToLocalizedString( TapNoteScore tns ); +/** + * @brief Turn the string into the proper tap note score. + * @param str the string. + * @return the tap note score based on the string. + */ TapNoteScore StringToTapNoteScore( const RString& str ); LuaDeclareType( TapNoteScore ); +/** @brief The list of hold note scores available during play. */ enum HoldNoteScore { - HNS_None, // HoldNote not scored yet - HNS_LetGo, // HoldNote has passed, missed it - HNS_Held, // HoldNote has passed, successfully held all the way - NUM_HoldNoteScore, + HNS_None, /**< The HoldNote was not scored yet. */ + HNS_LetGo, /**< The HoldNote has passed, but the player missed it. */ + HNS_Held, /**< The HoldNote has passed, and was successfully held all the way. */ + NUM_HoldNoteScore, /**< The number of hold note scores. */ HoldNoteScore_Invalid, }; +/** + * @brief Turn the hold note score into a proper string. + * @param hns the hold note score. + * @return the string version of the hold note score. + */ const RString& HoldNoteScoreToString( HoldNoteScore hns ); +/** + * @brief Turn the hold note score into a proper localized string. + * @param hns the hold note score. + * @return the localized string version of the hold note score. + */ const RString& HoldNoteScoreToLocalizedString( HoldNoteScore hns ); +/** + * @brief Turn the string into the proper hold note score. + * @param str the string. + * @return the hold note score based on the string. + */ HoldNoteScore StringToHoldNoteScore( const RString& str ); LuaDeclareType( HoldNoteScore ); +/** @brief The list of timing windows to deal with when playing. */ enum TimingWindow { TW_W1, @@ -196,6 +285,7 @@ enum TimingWindow }; const RString& TimingWindowToString( TimingWindow tw ); +/** @brief The list of score events that can take place while playing. */ enum ScoreEvent { SE_CheckpointHit, @@ -213,6 +303,7 @@ enum ScoreEvent }; const RString& ScoreEventToString( ScoreEvent se ); +/** @brief The list of game button types available for all game modes. */ enum GameButtonType { GameButtonType_Step, @@ -221,6 +312,7 @@ enum GameButtonType GameButtonType_INVALID }; +/** @brief The list of judge types for the tap note scores. */ enum TapNoteScoreJudgeType { TapNoteScoreJudgeType_MinimumScore, @@ -232,7 +324,7 @@ const RString& TapNoteScoreJudgeTypeToString( TapNoteScoreJudgeType jt ); LuaDeclareType( TapNoteScoreJudgeType ); -// Profile and MemCard stuff +/** @brief The profile slots available. This is mainly for Profiles and Memory Cards. */ enum ProfileSlot { ProfileSlot_Player1, @@ -244,7 +336,7 @@ enum ProfileSlot const RString& ProfileSlotToString( ProfileSlot ps ); LuaDeclareType( ProfileSlot ); - +/** @brief The states of the memory card during play. */ enum MemoryCardState { MemoryCardState_Ready, @@ -260,14 +352,14 @@ enum MemoryCardState const RString& MemoryCardStateToString( MemoryCardState mcs ); LuaDeclareType( MemoryCardState ); -// Ranking stuff +/** @brief The different ranking categories based on difficulty meter average. */ enum RankingCategory { - RANKING_A, // 1-3 meter per song avg. - RANKING_B, // 4-6 meter per song avg. - RANKING_C, // 7-9 meter per song avg. - RANKING_D, // 10+ meter per song avg. // doesn't count extra stage! - NUM_RankingCategory, + RANKING_A, /**< 1-3 meter per song avg. */ + RANKING_B, /**< 4-6 meter per song avg. */ + RANKING_C, /**< 7-9 meter per song avg. */ + RANKING_D, /**< 10+ meter per song avg, not counting extra stages. */ + NUM_RankingCategory, /**< The number of ranking categories. */ RankingCategory_Invalid }; const RString& RankingCategoryToString( RankingCategory rc ); @@ -282,7 +374,7 @@ RankingCategory AverageMeterToRankingCategory( int iAverageMeter ); extern const RString GROUP_ALL; -// +/** @brief The different types of players in the game. */ enum PlayerController { PC_HUMAN, @@ -295,22 +387,24 @@ enum PlayerController const RString& PlayerControllerToString( PlayerController pc ); LuaDeclareType( PlayerController ); +/** @brief The different health bar states. */ enum HealthState { - HealthState_Hot, - HealthState_Alive, - HealthState_Danger, - HealthState_Dead, + HealthState_Hot, /**< The health bar is very full. */ + HealthState_Alive, /**< The health bar is at a decent size. */ + HealthState_Danger, /**< The health bar is about to run out. */ + HealthState_Dead, /**< The health bar is drained completely. */ NUM_HealthState, HealthState_Invalid }; LuaDeclareType( HealthState ); +/** @brief The different stage results during battle. */ enum StageResult { - RESULT_WIN, - RESULT_LOSE, - RESULT_DRAW + RESULT_WIN, /**< The player has won the battle. */ + RESULT_LOSE, /**< The player has lost the battle. */ + RESULT_DRAW /**< The player has tied with the competitor. */ }; @@ -328,11 +422,12 @@ const int ITEM_NONE = -1; // Coin stuff +/** @brief The different coin modes to determine how one can play. */ enum CoinMode { - CoinMode_Home, - CoinMode_Pay, - CoinMode_Free, + CoinMode_Home, /**< The full range of options are available. */ + CoinMode_Pay, /**< Coins must be inserted before a game can begin. */ + CoinMode_Free, /**< It costs no money to play, but otherwise is similar to Pay mode. */ NUM_CoinMode, CoinMode_Invalid }; @@ -340,12 +435,12 @@ const RString& CoinModeToString( CoinMode cm ); LuaDeclareType( CoinMode ); -// Premium +/** @brief The different types of premiums available to take advantage of. */ enum Premium { - Premium_Off, - Premium_DoubleFor1Credit, - Premium_2PlayersFor1Credit, + Premium_Off, /**< It will cost one credit per side of the machine. */ + Premium_DoubleFor1Credit, /**< It will cost one credit per player of the machine. */ + Premium_2PlayersFor1Credit, /**< One credit gives one or both players full access. */ NUM_Premium, Premium_Invalid }; @@ -354,7 +449,7 @@ const RString& PremiumToLocalizedString( Premium p ); LuaDeclareType( Premium ); -// Award stuff +/** @brief The various stage awards that can be given based on excellent play. */ enum StageAward { StageAward_FullComboW3, @@ -375,7 +470,7 @@ const RString& StageAwardToLocalizedString( StageAward pma ); StageAward StringToStageAward( const RString& pma ); LuaDeclareType( StageAward ); - +/** @brief The various peak combo awards should such a combo be attained during play. */ enum PeakComboAward { PeakComboAward_1000, @@ -396,23 +491,47 @@ const RString& PeakComboAwardToLocalizedString( PeakComboAward pma ); PeakComboAward StringToPeakComboAward( const RString& pma ); LuaDeclareType( PeakComboAward ); - +/** @brief The list of BPMs to display */ struct DisplayBpms { + /** + * @brief Add a BPM to the list. + * @param f the BPM to add. + */ void Add( float f ); + /** + * @brief Retrieve the minimum BPM of the set. + * @return the minimum BPM. + */ float GetMin() const; + /** + * @brief Retrieve the maximum BPM of the set. + * @return the maximum BPM. + */ float GetMax() const; + /** + * @brief Determine if the BPM is really constant. + * @return Whether the BPM is constant or not. + */ bool BpmIsConstant() const; + /** + * @brief Determine if the BPM is meant to be a secret. + * @return Whether the BPM is a secret or not. + */ bool IsSecret() const; + /** + * @brief The list of the BPMs for the song or course. + */ vector vfBpms; }; +/** @brief The various style types available. */ enum StyleType { - StyleType_OnePlayerOneSide, // e.g. single - StyleType_TwoPlayersTwoSides, // e.g. versus - StyleType_OnePlayerTwoSides, // e.g. double - StyleType_TwoPlayersSharedSides, // e.g. routine + StyleType_OnePlayerOneSide, /**< Single style */ + StyleType_TwoPlayersTwoSides, /**< Versus style */ + StyleType_OnePlayerTwoSides, /**< Double style */ + StyleType_TwoPlayersSharedSides, /**< Routine style */ NUM_StyleType, StyleType_Invalid }; @@ -420,7 +539,7 @@ const RString& StyleTypeToString( StyleType s ); StyleType StringToStyleType( const RString& s ); LuaDeclareType( StyleType ); - +/** @brief The different goal types, mainly meant for fitness modes. */ enum GoalType { GoalType_Calories, @@ -433,7 +552,7 @@ const RString& GoalTypeToString( GoalType gt ); GoalType StringToGoalType( const RString& s ); LuaDeclareType( GoalType ); - +/** @brief The different types of Edit modes available. */ enum EditMode { EditMode_Practice, @@ -447,22 +566,24 @@ const RString& EditModeToString( EditMode em ); EditMode StringToEditMode( const RString& s ); LuaDeclareType( EditMode ); -/* -original options from ScreenEz2SelectMusic: -(if no confirm type is mentioned, there is none.) - -0 = play music as you select; SampleMusicPreviewMode_Normal -1 = no music plays, select 1x to play preview music, select again to confirm -2 = no music plays at all (SampleMusicPreviewMode_ScreenMusic + redir to silent) -3 = play music as select, 2x to confirm (SampleMusicPreviewMode_Normal + [SSMusic] TwoPartConfirmsOnly) -4 = screen music plays; SampleMusicPreviewMode_ScreenMusic -*/ +/** + * @brief The different types of sample music previews available. + * + * These were originally from the deleted screen ScreenEz2SelectMusic. + * (if no confirm type is mentioned, there is none.) + * + * 0 = play music as you select; SampleMusicPreviewMode_Normal + * 1 = no music plays, select 1x to play preview music, select again to confirm + * 2 = no music plays at all (SampleMusicPreviewMode_ScreenMusic + redir to silent) + * 3 = play music as select, 2x to confirm (SampleMusicPreviewMode_Normal + [SSMusic] TwoPartConfirmsOnly) + * 4 = screen music plays; SampleMusicPreviewMode_ScreenMusic + */ enum SampleMusicPreviewMode { - SampleMusicPreviewMode_Normal, - SampleMusicPreviewMode_StartToPreview, - SampleMusicPreviewMode_ScreenMusic, - SampleMusicPreviewMode_LastSong, // continue playing the last song + SampleMusicPreviewMode_Normal, /**< Music is played as the song is highlighted. */ + SampleMusicPreviewMode_StartToPreview, + SampleMusicPreviewMode_ScreenMusic, /**< No music plays. Select it once to preview the music, then once more to select the song. */ + SampleMusicPreviewMode_LastSong, /**< continue playing the last song */ NUM_SampleMusicPreviewMode, SampleMusicPreviewMode_Invalid, }; @@ -470,31 +591,36 @@ const RString& SampleMusicPreviewModeToString( SampleMusicPreviewMode ); SampleMusicPreviewMode StringToSampleMusicPreviewMode( const RString& s ); LuaDeclareType( SampleMusicPreviewMode ); -enum Stage // Shared stage values (not per-player) that are shown in StageDisplay +/** + * @brief The different kinds of Stages available. + * + * These are shared stage values shown in StageDisplay. These are not per-player. + */ +enum Stage { - Stage_1st, - Stage_2nd, - Stage_3rd, - Stage_4th, - Stage_5th, - Stage_6th, - Stage_Next, // after Stage_6th but not Final. This won't normally happen because 7 stages is the max in the UI. - Stage_Final, - Stage_Extra1, - Stage_Extra2, - Stage_Nonstop, - Stage_Oni, - Stage_Endless, - Stage_Event, - Stage_Demo, - NUM_Stage, + Stage_1st, /**< The first stage. */ + Stage_2nd, /**< The second stage. */ + Stage_3rd, /**< The third stage. */ + Stage_4th, /**< The fourth stage. */ + Stage_5th, /**< The fifth stage. */ + Stage_6th, /**< The sixth stage. */ + Stage_Next, /**< Somewhere between the sixth and final stage. This won't normally happen because 7 stages is the max in the UI. */ + Stage_Final, /**< The last stage. */ + Stage_Extra1, /**< The first bonus stage, AKA the extra stage. */ + Stage_Extra2, /**< The last bonus stage, AKA the encore extra stage. */ + Stage_Nonstop, /**< Playing a nonstop course. */ + Stage_Oni, /**< Playing an oni or survival course. */ + Stage_Endless, /**< Playing an endless course. */ + Stage_Event, /**< Playing in event mode. */ + Stage_Demo, /**< Playing the demonstration. */ + NUM_Stage, /**< The number of stage types. */ Stage_Invalid, }; const RString& StageToString( Stage s ); LuaDeclareType( Stage ); const RString& StageToLocalizedString( Stage i ); - +/** @brief The different possibilities of earning an extra stage. */ enum EarnedExtraStage { EarnedExtraStage_No, @@ -506,7 +632,7 @@ enum EarnedExtraStage const RString& EarnedExtraStageToString( EarnedExtraStage s ); LuaDeclareType( EarnedExtraStage ); - +/** @brief The different results of loading a profile. */ enum ProfileLoadResult { ProfileLoadResult_Success, @@ -514,7 +640,7 @@ enum ProfileLoadResult ProfileLoadResult_FailedTampered }; - +/** @brief The different statuses for multiplayer. */ enum MultiPlayerStatus { MultiPlayerStatus_Joined, @@ -526,13 +652,13 @@ enum MultiPlayerStatus }; const RString& MultiPlayerStatusToString( MultiPlayerStatus i ); - +/** @brief The different course types. */ enum CourseType { - COURSE_TYPE_NONSTOP, // if life meter type is BAR - COURSE_TYPE_ONI, // if life meter type is BATTERY - COURSE_TYPE_ENDLESS, // if set to REPEAT - COURSE_TYPE_SURVIVAL, // if life meter type is TIME + COURSE_TYPE_NONSTOP, /**< The life meter type is set to BAR. */ + COURSE_TYPE_ONI, /**< The life meter type is set to BATTERY. */ + COURSE_TYPE_ENDLESS, /**< The life meter type is set to REPEAT. */ + COURSE_TYPE_SURVIVAL, /**< The life meter type is set to TIME. */ NUM_CourseType, CourseType_Invalid }; diff --git a/src/GameManager.cpp b/src/GameManager.cpp index 29d229df79..c904915665 100644 --- a/src/GameManager.cpp +++ b/src/GameManager.cpp @@ -32,7 +32,7 @@ enum TRACK_14, TRACK_15, TRACK_16, - // BMS reader needs 16 tracks for beat-double7 + // 16 tracks needed for beat-double7 and techno-double8 }; RString StepsTypeInfo::GetLocalizedString() const @@ -81,6 +81,7 @@ static const StepsTypeInfo g_StepsTypeInfos[] = { { "techno-single8", 8, true, StepsTypeCategory_Single }, { "techno-double4", 8, true, StepsTypeCategory_Double }, { "techno-double5", 10, true, StepsTypeCategory_Double }, + { "techno-double8", 16, true, StepsTypeCategory_Double }, // pop'n music { "pnm-five", 5, true, StepsTypeCategory_Single }, // called "pnm" for backward compat { "pnm-nine", 9, true, StepsTypeCategory_Single }, // called "pnm" for backward compat @@ -814,28 +815,28 @@ static const Style g_Style_Pump_Routine = 10, // m_iColsPerPlayer { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; { // PLAYER_1 - { TRACK_1, -PUMP_COL_SPACING*4.6f-4, NULL }, - { TRACK_2, -PUMP_COL_SPACING*3.6f-4, NULL }, - { TRACK_3, -PUMP_COL_SPACING*2.6f-4, NULL }, - { TRACK_4, -PUMP_COL_SPACING*1.6f-4, NULL }, - { TRACK_5, -PUMP_COL_SPACING*0.6f-4, NULL }, - { TRACK_6, +PUMP_COL_SPACING*0.6f+4, NULL }, - { TRACK_7, +PUMP_COL_SPACING*1.6f+4, NULL }, - { TRACK_8, +PUMP_COL_SPACING*2.6f+4, NULL }, - { TRACK_9, +PUMP_COL_SPACING*3.6f+4, NULL }, - { TRACK_10, +PUMP_COL_SPACING*4.6f+4, NULL }, + { TRACK_1, -PUMP_COL_SPACING*4.5f-4, NULL }, + { TRACK_2, -PUMP_COL_SPACING*3.5f-4, NULL }, + { TRACK_3, -PUMP_COL_SPACING*2.5f-4, NULL }, + { TRACK_4, -PUMP_COL_SPACING*1.5f-4, NULL }, + { TRACK_5, -PUMP_COL_SPACING*0.5f-4, NULL }, + { TRACK_6, +PUMP_COL_SPACING*0.5f+4, NULL }, + { TRACK_7, +PUMP_COL_SPACING*1.5f+4, NULL }, + { TRACK_8, +PUMP_COL_SPACING*2.5f+4, NULL }, + { TRACK_9, +PUMP_COL_SPACING*3.5f+4, NULL }, + { TRACK_10, +PUMP_COL_SPACING*4.5f+4, NULL }, }, { // PLAYER_2 - { TRACK_1, -PUMP_COL_SPACING*4.6f-4, NULL }, - { TRACK_2, -PUMP_COL_SPACING*3.6f-4, NULL }, - { TRACK_3, -PUMP_COL_SPACING*2.6f-4, NULL }, - { TRACK_4, -PUMP_COL_SPACING*1.6f-4, NULL }, - { TRACK_5, -PUMP_COL_SPACING*0.6f-4, NULL }, - { TRACK_6, +PUMP_COL_SPACING*0.6f+4, NULL }, - { TRACK_7, +PUMP_COL_SPACING*1.6f+4, NULL }, - { TRACK_8, +PUMP_COL_SPACING*2.6f+4, NULL }, - { TRACK_9, +PUMP_COL_SPACING*3.6f+4, NULL }, - { TRACK_10, +PUMP_COL_SPACING*4.6f+4, NULL }, + { TRACK_1, -PUMP_COL_SPACING*4.5f-4, NULL }, + { TRACK_2, -PUMP_COL_SPACING*3.5f-4, NULL }, + { TRACK_3, -PUMP_COL_SPACING*2.5f-4, NULL }, + { TRACK_4, -PUMP_COL_SPACING*1.5f-4, NULL }, + { TRACK_5, -PUMP_COL_SPACING*0.5f-4, NULL }, + { TRACK_6, +PUMP_COL_SPACING*0.5f+4, NULL }, + { TRACK_7, +PUMP_COL_SPACING*1.5f+4, NULL }, + { TRACK_8, +PUMP_COL_SPACING*2.5f+4, NULL }, + { TRACK_9, +PUMP_COL_SPACING*3.5f+4, NULL }, + { TRACK_10, +PUMP_COL_SPACING*4.5f+4, NULL }, }, }, { // m_iInputColumn[NUM_GameController][NUM_GameButton] @@ -2300,6 +2301,66 @@ static const Style g_Style_Techno_Double5 = { TRACK_10, +TECHNO_COL_SPACING*4.5f, NULL }, }, }, + { // m_iInputColumn[NUM_GameController][NUM_GameButton] + { 1, 6, 4, 3, 2, 5, Style::NO_MAPPING, 0, 7, Style::END_MAPPING }, + { 1, 6, 4, 3, 2, 5, Style::NO_MAPPING, 0, 7, Style::END_MAPPING }, + }, + { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER]; + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 + }, + false, // m_bNeedsZoomOutWith2Players + false, // m_bCanUseBeginnerHelper + false, // m_bLockDifficulties +}; + +static const Style g_Style_Techno_Double8 = +{ // STYLE_TECHNO_DOUBLE8 + true, // m_bUsedForGameplay + true, // m_bUsedForEdit + false, // m_bUsedForDemonstration + false, // m_bUsedForHowToPlay + "double8", // m_szName + StepsType_techno_double8, // m_StepsType + StyleType_OnePlayerTwoSides, // m_StyleType + 16, // m_iColsPerPlayer + { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; + { // PLAYER_1 + { TRACK_1, -TECHNO_VERSUS_COL_SPACING*7.5f, NULL }, + { TRACK_2, -TECHNO_VERSUS_COL_SPACING*6.5f, NULL }, + { TRACK_3, -TECHNO_VERSUS_COL_SPACING*5.5f, NULL }, + { TRACK_4, -TECHNO_VERSUS_COL_SPACING*4.5f, NULL }, + { TRACK_5, -TECHNO_VERSUS_COL_SPACING*3.5f, NULL }, + { TRACK_6, -TECHNO_VERSUS_COL_SPACING*2.5f, NULL }, + { TRACK_7, -TECHNO_VERSUS_COL_SPACING*1.5f, NULL }, + { TRACK_8, -TECHNO_VERSUS_COL_SPACING*0.5f, NULL }, + { TRACK_9, +TECHNO_VERSUS_COL_SPACING*0.5f, NULL }, + { TRACK_10, +TECHNO_VERSUS_COL_SPACING*1.5f, NULL }, + { TRACK_11, +TECHNO_VERSUS_COL_SPACING*2.5f, NULL }, + { TRACK_12, +TECHNO_VERSUS_COL_SPACING*3.5f, NULL }, + { TRACK_13, +TECHNO_VERSUS_COL_SPACING*4.5f, NULL }, + { TRACK_14, +TECHNO_VERSUS_COL_SPACING*5.5f, NULL }, + { TRACK_15, +TECHNO_VERSUS_COL_SPACING*6.5f, NULL }, + { TRACK_16, +TECHNO_VERSUS_COL_SPACING*7.5f, NULL }, + }, + { // PLAYER_2 + { TRACK_1, -TECHNO_VERSUS_COL_SPACING*7.5f, NULL }, + { TRACK_2, -TECHNO_VERSUS_COL_SPACING*6.5f, NULL }, + { TRACK_3, -TECHNO_VERSUS_COL_SPACING*5.5f, NULL }, + { TRACK_4, -TECHNO_VERSUS_COL_SPACING*4.5f, NULL }, + { TRACK_5, -TECHNO_VERSUS_COL_SPACING*3.5f, NULL }, + { TRACK_6, -TECHNO_VERSUS_COL_SPACING*2.5f, NULL }, + { TRACK_7, -TECHNO_VERSUS_COL_SPACING*1.5f, NULL }, + { TRACK_8, -TECHNO_VERSUS_COL_SPACING*0.5f, NULL }, + { TRACK_9, +TECHNO_VERSUS_COL_SPACING*0.5f, NULL }, + { TRACK_10, +TECHNO_VERSUS_COL_SPACING*1.5f, NULL }, + { TRACK_11, +TECHNO_VERSUS_COL_SPACING*2.5f, NULL }, + { TRACK_12, +TECHNO_VERSUS_COL_SPACING*3.5f, NULL }, + { TRACK_13, +TECHNO_VERSUS_COL_SPACING*4.5f, NULL }, + { TRACK_14, +TECHNO_VERSUS_COL_SPACING*5.5f, NULL }, + { TRACK_15, +TECHNO_VERSUS_COL_SPACING*6.5f, NULL }, + { TRACK_16, +TECHNO_VERSUS_COL_SPACING*7.5f, NULL }, + }, + }, { // m_iInputColumn[NUM_GameController][NUM_GameButton] { Style::NO_MAPPING, Style::NO_MAPPING, Style::NO_MAPPING, Style::NO_MAPPING, 1, 3, 2, 0, 4, Style::END_MAPPING }, @@ -2324,6 +2385,7 @@ static const Style *g_apGame_Techno_Styles[] = &g_Style_Techno_Versus8, &g_Style_Techno_Double4, &g_Style_Techno_Double5, + &g_Style_Techno_Double8, NULL }; @@ -2544,7 +2606,7 @@ static const Game g_Game_Popn = /** Guitar5 ******************************************************************/ //ThemeMetric GUITAR5_COL_SPACING ("ColumnSpacing","Guitar5"); -static const int GUITAR5_COL_SPACING = 48; // todo: get a proper value? -aj +static const int GUITAR5_COL_SPACING = 48; static const Style g_Style_Guitar_Five = { // STYLE_GUITAR_FIVE @@ -2989,7 +3051,7 @@ StepsType GameManager::StringToStepsType( RString sStepsType ) sStepsType.MakeLower(); // TODO: Format specific hacks should be moved into the file loader for that format. - // If i'm assuming this correctly, these only apply to .sm files: -aj + // If i'm assuming this correctly, these two only apply to .sm files: -aj // HACK: We eliminated "ez2-single-hard", but we should still handle it. if( sStepsType == "ez2-single-hard" ) diff --git a/src/GameManager.h b/src/GameManager.h index 9f6bf091e9..666700bb62 100644 --- a/src/GameManager.h +++ b/src/GameManager.h @@ -1,4 +1,4 @@ -/* GameManager - Manages Games and Styles. */ +/** @brief GameManager - Manages Games and Styles. */ #ifndef GAMEMANAGER_H #define GAMEMANAGER_H @@ -10,12 +10,16 @@ struct lua_State; #include "GameConstantsAndTypes.h" #include "GameInput.h" +/** @brief The collective information about a Steps' Type. */ struct StepsTypeInfo { const char *szName; + /** @brief The number of tracks, or columns, of this type. */ int iNumTracks; - bool bAllowAutogen; // allow this type to be autogen'd to other types - StepsTypeCategory m_StepsTypeCategory; // what is the most basic StyleType this is used with? + /** @brief A flag to determine if we allow this type to be autogen'ed to other types. */ + bool bAllowAutogen; + /** @brief The most basic StyleType that this StpesTypeInfo is used with. */ + StepsTypeCategory m_StepsTypeCategory; RString GetLocalizedString() const; }; @@ -55,8 +59,10 @@ extern GameManager* GAMEMAN; // global and accessable from anywhere in our progr #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/GameSoundManager.cpp b/src/GameSoundManager.cpp index 0e36042116..9034b86a34 100644 --- a/src/GameSoundManager.cpp +++ b/src/GameSoundManager.cpp @@ -6,7 +6,7 @@ #include "RageUtil.h" #include "GameState.h" #include "TimingData.h" -#include "NotesLoaderSM.h" +#include "NotesLoaderSSC.h" #include "PrefsManager.h" #include "RageDisplay.h" #include "AnnouncerManager.h" @@ -141,7 +141,7 @@ static void StartMusic( MusicToPlay &ToPlay ) { LOG->Trace( "Found '%s'", ToPlay.m_sTimingFile.c_str() ); Song song; - if( SMLoader::LoadFromSMFile(ToPlay.m_sTimingFile, song) ) + if( SSCLoader::LoadFromSSCFile(ToPlay.m_sTimingFile, song) ) { ToPlay.HasTiming = true; ToPlay.m_TimingData = song.m_Timing; diff --git a/src/GameState.cpp b/src/GameState.cpp index 8194bbbeed..0a190e750e 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -936,7 +936,7 @@ void GameState::ResetStageStatistics() m_vLastPeakComboAwards[p].clear(); } - // Reset the round seed. Do this here and not in FinishStage so that players + // Reset the round seed. Do this here and not in FinishStage so that players // get new shuffle patterns if they Back out of gameplay and play again. m_iStageSeed = rand(); } @@ -961,23 +961,15 @@ void GameState::UpdateSongPosition( float fPositionSeconds, const TimingData &ti ASSERT_M( m_fSongBeat > -2000, ssprintf("Song beat %f at %f seconds", m_fSongBeat, fPositionSeconds) ); //if( m_iWarpBeginRow != -1 || m_iWarpEndRow == -1 ) - if( m_iWarpBeginRow != -1 && m_fWarpLength > 0.f ) + if( m_iWarpBeginRow != -1 && m_fWarpLength > 0.0f ) { - // we got a warp in this section. + // There is a warp in this section. LOG->Trace("warp at %i lasts for %f, jumps to %i",m_iWarpBeginRow,m_fWarpLength,m_iWarpBeginRow+BeatToNoteRow(m_fWarpLength)); //fPositionSeconds += (m_fWarpLength * m_fCurBPS); } - /* - // xxx testing: only do this on monotune survivor - if( m_pCurSong && m_pCurSong->GetDisplayFullTitle() == "monotune survivor" ) - LOG->Trace( ssprintf("[GameState::UpdateSongPosition] m_fMusicSeconds before = %f",m_fMusicSeconds) ); - */ + m_fMusicSeconds = fPositionSeconds; - /* - // xxx testing: only do this on monotune survivor - if( m_pCurSong && m_pCurSong->GetDisplayFullTitle() == "monotune survivor" ) - LOG->Trace( ssprintf("[GameState::UpdateSongPosition] m_fMusicSeconds after = %f",m_fMusicSeconds) ); - */ + m_fLightSongBeat = timing.GetBeatFromElapsedTime( fPositionSeconds + g_fLightsAheadSeconds ); m_fSongBeatNoOffset = timing.GetBeatFromElapsedTimeNoOffset( fPositionSeconds ); @@ -1965,7 +1957,7 @@ bool GameState::ChangePreferredDifficulty( PlayerNumber pn, int dir ) } /* The user may be set to prefer a difficulty that isn't always shown; typically, - * Difficulty_Edit. Return the closest shown difficulty <= m_PreferredDifficulty. */ + * Difficulty_Edit. Return the closest shown difficulty <= m_PreferredDifficulty. */ Difficulty GameState::GetClosestShownDifficulty( PlayerNumber pn ) const { const vector &v = CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue(); diff --git a/src/GameState.h b/src/GameState.h index bb1285f0cb..370f789a6c 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -1,4 +1,4 @@ -/* GameState - Holds game data that is not saved between sessions. */ +/** @brief GameState - Holds game data that is not saved between sessions. */ #ifndef GAMESTATE_H #define GAMESTATE_H @@ -36,8 +36,10 @@ class Trail; class GameState { public: + /** @brief Set up the GameState with initial values. */ GameState(); ~GameState(); + /** @brief Reset the GameState back to initial values. */ void Reset(); void ResetPlayer( PlayerNumber pn ); void ApplyCmdline(); // called by Reset @@ -63,11 +65,21 @@ public: void SetCurGame( const Game *pGame ); // Call this instead of m_pCurGame.Set to make sure PREFSMAN->m_sCurrentGame stays in sync BroadcastOnChangePtr m_pCurGame; BroadcastOnChangePtr m_pCurStyle; + /** @brief Determine which side is joined. + * + * The left side is player 1, and the right side is player 2. */ bool m_bSideIsJoined[NUM_PLAYERS]; // left side, right side MultiPlayerStatus m_MultiPlayerStatus[NUM_MultiPlayer]; BroadcastOnChange m_PlayMode; // many screens display different info depending on this value - BroadcastOnChange m_iCoins; // not "credits" - PlayerNumber m_MasterPlayerNumber; // used in Styles where one player controls both sides + /** + * @brief The number of coins presently in the machine. + * + * Note that coins are not "credits". One may have to put in two coins + * 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; @@ -86,7 +98,10 @@ public: int m_iGameSeed, m_iStageSeed; RString m_sStageGUID; - bool PlayersCanJoin() const; // true if it's not too late for a player to join + /** + * @brief Determine if a second player can join in at this time. + * @return true if a player can still enter the game, false otherwise. */ + bool PlayersCanJoin() const; int GetCoinsNeededToJoin() const; bool EnoughCreditsToJoin() const { return m_iCoins >= GetCoinsNeededToJoin(); } int GetNumSidesJoined() const; @@ -127,9 +142,15 @@ public: bool m_bDemonstrationOrJukebox; // ScreenGameplay does special stuff when this is true bool m_bJukeboxUsesModifiers; int m_iNumStagesOfThisSong; - // Increases every stage, doesn't reset when player continues. It's cosmetic and not used in Stage or Screen branching logic. + /** + * @brief Increase this every stage while not resetting on a continue. + * + * This is cosmetic: it's not use for Stage or Screen branching logic. */ int m_iCurrentStageIndex; - // Num stages available for player. Resets when player joins/continues. + /** + * @brief The number of stages available for the players. + * + * This resets whenever a player joins or continues. */ int m_iPlayerStageTokens[NUM_PLAYERS]; static int GetNumStagesMultiplierForSong( const Song* pSong ); @@ -182,8 +203,10 @@ public: float m_fCurBPS; float m_fLightSongBeat; // g_fLightsFalloffSeconds ahead //bool m_bStop; // in the middle of a stop (freeze or delay) - bool m_bFreeze; // in the middle of a freeze - bool m_bDelay; // in the middle of a delay + /** @brief A flag to determine if we're in the middle of a freeze/stop. */ + bool m_bFreeze; + /** @brief A flag to determine if we're in the middle of a delay (Pump style stop). */ + bool m_bDelay; // used for warping: int m_iWarpBeginRow; float m_fWarpLength; @@ -229,11 +252,13 @@ public: bool m_bGoalComplete[NUM_PLAYERS]; bool m_bWorkoutGoalComplete; - void RemoveAllActiveAttacks(); // called on end of song + /** @brief Primarily called at the end of a song to stop all attacks. */ + void RemoveAllActiveAttacks(); PlayerNumber GetBestPlayer() const; StageResult GetStageResult( PlayerNumber pn ) const; - void ResetStageStatistics(); // Call this when it's time to play a new stage. + /** @brief Call this function when it's time to play a new stage. */ + void ResetStageStatistics(); // Options stuff ModsGroup m_SongOptions; @@ -291,6 +316,7 @@ public: void VisitAttractScreen( const RString sScreenName ); // PlayerState + /** @brief Allow access to each player's PlayerState. */ PlayerState* m_pPlayerState[NUM_PLAYERS]; PlayerState* m_pMultiPlayerState[NUM_MultiPlayer]; @@ -346,8 +372,10 @@ extern GameState* GAMESTATE; // global and accessable from anywhere in our progr #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard, Chris Gomez +/** + * @file + * @author Chris Danford, Glenn Maynard, Chris Gomez (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/GameplayAssist.h b/src/GameplayAssist.h index a982e75edd..5f153c3dc4 100644 --- a/src/GameplayAssist.h +++ b/src/GameplayAssist.h @@ -1,4 +1,4 @@ -/* GameplayAssist - Encapsulate playing of handclap and metronome. */ +/** @brief GameplayAssist - Encapsulate playing of handclap and metronome. */ #ifndef GameplayAssist_H #define GameplayAssist_H @@ -6,24 +6,34 @@ #include "RageSound.h" class NoteData; - +/** @brief The handclaps and metronomes ready to assist the player. */ class GameplayAssist { public: + /** @brief Load the sounds. */ void Init(); + /** + * @brief Play the sounds in question for the particular chart. + * @param nd the note data used for playing the ticks. */ void PlayTicks( const NoteData &nd ); + /** @brief Stop playing the sounds. */ void StopPlaying(); private: + /** @brief the sound made when a note is to be hit. */ RageSound m_soundAssistClap; + /** @brief the sound made when crossing a new measure. */ RageSound m_soundAssistMetronomeMeasure; + /** @brief the sound made when crossing a new beat. */ RageSound m_soundAssistMetronomeBeat; }; #endif -/* - * (c) 2003-2006 Chris Danford +/** + * @file + * @author Chris Danford (c) 2003-2006 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/Grade.h b/src/Grade.h index 34d6dc2286..c520f39c6c 100644 --- a/src/Grade.h +++ b/src/Grade.h @@ -1,4 +1,4 @@ -/* Grade - Mark the player receives after clearing a song. */ +/** @brief Grade - Mark the player receives after clearing a song. */ #ifndef GRADE_H #define GRADE_H @@ -7,16 +7,21 @@ #include "EnumHelper.h" #include "ThemeMetric.h" +/** + * @brief Have a specific number of passing grade tiers. + * + * TODO: Look into flexible grading tiers. */ #define NUM_Grade_TierS 20 +/** @brief The list of grading tiers available. */ enum Grade { - Grade_Tier01, // = AAAA - Grade_Tier02, // = AAA - Grade_Tier03, // = AA - Grade_Tier04, // = A - Grade_Tier05, // = B - Grade_Tier06, // = C - Grade_Tier07, // = D + Grade_Tier01, /**< Usually an AAAA */ + Grade_Tier02, /**< Usually an AAA */ + Grade_Tier03, /**< Usually an AA */ + Grade_Tier04, /**< Usually an A */ + Grade_Tier05, /**< Usually a B */ + Grade_Tier06, /**< Usually a C */ + Grade_Tier07, /**< Usually a D */ Grade_Tier08, Grade_Tier09, Grade_Tier10, @@ -30,14 +35,20 @@ enum Grade Grade_Tier18, Grade_Tier19, Grade_Tier20, - Grade_Failed, // = E + Grade_Failed, /**< Usually an E */ NUM_Grade, Grade_Invalid, }; #define Grade_NoData Grade_Invalid -/* This is in the header so the test sets don't require Grade.cpp (through PrefsManager), - * since that pulls in ThemeManager. */ +/** + * @brief Convert the grade supplied to a string representation. + * + * This is in the header so the test sets don't require Grade.cpp (through PrefsManager), + * since that pulls in ThemeManager. + * @param g the grade to convert. + * @return the string reprsentation. + */ static inline RString GradeToString( Grade g ) { ASSERT_M( (g >= 0 && g START_X ("GroupList","StartX"); -static const ThemeMetric START_Y ("GroupList","StartY"); -static const ThemeMetric SPACING_X ("GroupList","SpacingX"); -static const ThemeMetric SPACING_Y ("GroupList","SpacingY"); - -const int MAX_GROUPS_ONSCREEN = 7; - -GroupList::GroupList() -{ - m_iSelection = m_iTop = 0; -} - -GroupList::~GroupList() -{ - for( unsigned i = 0; i < m_sprButtons.size(); ++i ) - { - delete m_sprButtons[i]; - delete m_textLabels[i]; - delete m_ButtonFrames[i]; - } -} - - -bool GroupList::ItemIsOnScreen( int n ) const -{ - const int offset = n - m_iTop; - return offset >= 0 && offset < MAX_GROUPS_ONSCREEN; -} - -void GroupList::Load( const vector& asGroupNames ) -{ - m_asLabels = asGroupNames; - - m_Frame.SetName( "Frame" ); - this->AddChild( &m_Frame ); - ActorUtil::LoadAllCommands( m_Frame, "GroupList" ); - - for( unsigned i=0; i < m_asLabels.size(); i++ ) - { - Sprite *button = new Sprite; - button->SetName( "Button" ); - ActorUtil::LoadAllCommands( *button, "GroupList" ); - - BitmapText *label = new BitmapText; - label->SetName( "Label" ); - ActorUtil::LoadAllCommands( *label, "GroupList" ); - - ActorFrame *frame = new ActorFrame; - frame->SetName( "ButtonFrame" ); - ActorUtil::LoadAllCommands( *frame, "GroupList" ); - - m_sprButtons.push_back( button ); - m_textLabels.push_back( label ); - m_ButtonFrames.push_back( frame ); - - button->Load( THEME->GetPathG("GroupList","bar") ); - label->LoadFromFont( THEME->GetPathF("GroupList","label") ); - label->SetShadowLength( 2 ); - label->SetText( SONGMAN->ShortenGroupName( asGroupNames[i] ) ); - - frame->AddChild( button ); - frame->AddChild( label ); - m_Frame.AddChild( frame ); - - button->SetXY( START_X + i*SPACING_X, START_Y + i*SPACING_Y ); - label->SetXY( START_X + i*SPACING_X, START_Y + i*SPACING_Y ); - - if( i == 0 ) - { - label->SetRainbowScroll( true ); - } - else - { - label->SetRainbowScroll( false ); - label->SetDiffuse( SONGMAN->GetSongGroupColor(asGroupNames[i]) ); - } - - m_bHidden.push_back( ItemIsOnScreen(i) ); - - ResetTextSize( i ); - } - - AfterChange(); -} - -void GroupList::ResetTextSize( int i ) -{ - BitmapText *label = m_textLabels[i]; - const float fTextWidth = (float)label->GetUnzoomedWidth(); - const float fButtonWidth = m_sprButtons[i]->GetZoomedWidth(); - - float fZoom = fButtonWidth/fTextWidth; - fZoom = min( fZoom, 0.8f ); - - label->SetZoomX( fZoom ); - label->SetZoomY( 0.8f ); -} - -void GroupList::BeforeChange() -{ - m_ButtonFrames[m_iSelection]->PlayCommand( "LoseFocus" ); -} - - -void GroupList::AfterChange() -{ - m_Frame.StopTweening(); - m_Frame.PlayCommand( "ScrollTween" ); - m_Frame.SetY( -m_iTop*SPACING_Y ); - - for( int i=0; i < (int) m_asLabels.size(); i++ ) - { - const bool IsHidden = !ItemIsOnScreen(i); - const bool WasHidden = m_bHidden[i]; - - if( IsHidden && !WasHidden ) - { - m_ButtonFrames[i]->PlayCommand( "HideItem" ); - } - else if( !IsHidden && WasHidden ) - { - m_ButtonFrames[i]->PlayCommand( "ShowItem" ); - ResetTextSize( i ); - } - - m_bHidden[i] = IsHidden; - } - - m_ButtonFrames[m_iSelection]->PlayCommand( "GainFocus" ); -} - -void GroupList::Up() -{ - BeforeChange(); - - if( m_iSelection == 0 ) - SetSelection(m_asLabels.size()-1); - else - SetSelection(m_iSelection-1); - - AfterChange(); -} - -void GroupList::Down() -{ - BeforeChange(); - - SetSelection((m_iSelection+1) % m_asLabels.size()); - - AfterChange(); -} - -void GroupList::SetSelection( unsigned sel ) -{ - BeforeChange(); - - m_iSelection=sel; - - if( (int)m_asLabels.size() <= MAX_GROUPS_ONSCREEN || - sel <= MAX_GROUPS_ONSCREEN/2 ) - m_iTop = 0; - else if ( sel >= m_asLabels.size() - MAX_GROUPS_ONSCREEN/2 ) - m_iTop = m_asLabels.size() - MAX_GROUPS_ONSCREEN; - else - m_iTop = sel - MAX_GROUPS_ONSCREEN/2; - - /* The current selection must always be visible. */ - ASSERT( m_iTop <= m_iSelection ); - ASSERT( m_iTop+MAX_GROUPS_ONSCREEN > m_iSelection ); - - AfterChange(); -} - - -void GroupList::TweenOnScreen() -{ - for( int i=0; i < (int) m_asLabels.size(); i++ ) - { - const int offset = max(0, i-m_iTop); - - m_sprButtons[i]->SetX( 400 ); - m_textLabels[i]->SetX( 400 ); - - m_sprButtons[i]->BeginTweening( 0.1f*offset, TWEEN_ACCELERATE ); - m_textLabels[i]->BeginTweening( 0.1f*offset, TWEEN_ACCELERATE ); - - m_sprButtons[i]->BeginTweening( 0.2f, TWEEN_ACCELERATE ); - m_textLabels[i]->BeginTweening( 0.2f, TWEEN_ACCELERATE ); - - m_sprButtons[i]->SetX( 0 ); - m_textLabels[i]->SetX( 0 ); - - /* If this item isn't visible, hide it and skip tweens. */ - if( !ItemIsOnScreen(i) ) - { - m_ButtonFrames[i]->PlayCommand( "HideItem" ); - - m_sprButtons[i]->FinishTweening(); - m_textLabels[i]->FinishTweening(); - } - } -} - -void GroupList::TweenOffScreen() -{ - for( int i=m_iTop; i < min(m_iTop+MAX_GROUPS_ONSCREEN, (int) m_asLabels.size()); i++ ) - { - const int offset = max(0, i-m_iTop); - if( i == m_iSelection ) - { - m_sprButtons[i]->BeginTweening( 1.0f, TWEEN_DECELERATE ); - m_textLabels[i]->BeginTweening( 1.0f, TWEEN_DECELERATE ); - } - else - { - m_sprButtons[i]->BeginTweening( 0.1f*offset, TWEEN_DECELERATE ); - m_textLabels[i]->BeginTweening( 0.1f*offset, TWEEN_DECELERATE ); - } - - m_sprButtons[i]->BeginTweening( 0.2f, TWEEN_DECELERATE ); - m_textLabels[i]->BeginTweening( 0.2f, TWEEN_DECELERATE ); - - m_sprButtons[i]->SetX( 400 ); - m_textLabels[i]->SetX( 400 ); - } -} - -/* - * (c) 2001-2003 Chris Danford, 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/GroupList.h b/src/GroupList.h deleted file mode 100644 index 55121dc920..0000000000 --- a/src/GroupList.h +++ /dev/null @@ -1,68 +0,0 @@ -/* GroupList - Displays a list of groups for SelectGroup. (An old holdover.) */ -#ifndef GROUP_LIST_H -#define GROUP_LIST_H - -#include "ActorFrame.h" -#include "Sprite.h" -#include "BitmapText.h" - -class GroupList: public ActorFrame -{ - ActorFrame m_Frame; - vector m_sprButtons; - vector m_textLabels; - vector m_ButtonFrames; - vector m_asLabels; - - vector m_bHidden; - - /* Currently selected label. */ - int m_iSelection; - /* Label that's currently at the top of the screen. */ - int m_iTop; - - void BeforeChange(); - void AfterChange(); - bool ItemIsOnScreen( int n ) const; - void ResetTextSize( int item ); - -public: - GroupList(); - ~GroupList(); - - void SetSelection(unsigned sel); - int GetSelection() const { return m_iSelection; } - RString GetSelectionName() const { return m_asLabels[m_iSelection]; } - void Up(); - void Down(); - void Load( const vector& asGroupNames ); - void TweenOffScreen(); - void TweenOnScreen(); -}; - -#endif - -/* - * (c) 2001-2003 Chris Danford, 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/HighScore.cpp b/src/HighScore.cpp index 4d1e170bd8..420127f6bd 100644 --- a/src/HighScore.cpp +++ b/src/HighScore.cpp @@ -411,6 +411,7 @@ void Screenshot::LoadFromNode( const XNode* pNode ) // lua start #include "LuaBinding.h" +/** @brief Allow Lua to have access to the HighScore. */ class LunaHighScore: public Luna { public: @@ -457,6 +458,7 @@ public: LUA_REGISTER_CLASS( HighScore ) +/** @brief Allow Lua to have access to the HighScoreList. */ class LunaHighScoreList: public Luna { public: diff --git a/src/HighScore.h b/src/HighScore.h index 791fdf12a5..ba493e4d10 100644 --- a/src/HighScore.h +++ b/src/HighScore.h @@ -1,4 +1,4 @@ -/* HighScore - Player scoring data that persists between sessions. */ +/** @brief HighScore - Player scoring data that persists between sessions. */ #ifndef HIGH_SCORE_H #define HIGH_SCORE_H @@ -13,17 +13,37 @@ struct RadarValues; struct lua_State; struct HighScoreImpl; +/** @brief The high score that is earned by a player. */ struct HighScore { HighScore(); + /** + * @brief Retrieve the name of the player that set the high score. + * @return the name of the player. */ RString GetName() const; + /** + * @brief Retrieve the grade earned from this score. + * @return the grade. + */ Grade GetGrade() const; + /** + * @brief Retrieve the score earned. + * @return the score. */ int GetScore() const; + /** + * @brief Determine if any judgments were tallied during this run. + * @return true if no judgments were recorded, false otherwise. */ bool IsEmpty() const; float GetPercentDP() const; + /** + * @brief Determine how many seconds the player had left in Survival mode. + * @return the number of seconds left. */ float GetSurviveSeconds() const; float GetSurvivalSeconds() const; + /** + * @brief Get the modifiers used for this run. + * @return the modifiers. */ RString GetModifiers() const; DateTime GetDateTime() const; RString GetPlayerGuid() const; @@ -33,6 +53,9 @@ struct HighScore int GetHoldNoteScore( HoldNoteScore tns ) const; const RadarValues &GetRadarValues() const; float GetLifeRemainingSeconds() const; + /** + * @brief Determine if this score was from a situation that would cause disqualification. + * @return true if the score would be disqualified, false otherwise. */ bool GetDisqualified() const; void SetName( const RString &sName ); @@ -70,6 +93,7 @@ private: HiddenPtr m_Impl; }; +/** @brief The list of high scores */ struct HighScoreList { public: @@ -110,10 +134,14 @@ private: }; +/** @brief the picture taken of the high score. */ struct Screenshot { - RString sFileName; // no directory part - just the file name - RString sMD5; // MD5 hash of the screenshot file + /** @brief the filename of the screen shot. There is no directory part. */ + RString sFileName; + /** @brief The MD5 hash of the screen shot file above. */ + RString sMD5; + /** @brief The actual high score in question. */ HighScore highScore; XNode* CreateNode() const; @@ -122,8 +150,10 @@ struct Screenshot #endif -/* - * (c) 2004 Chris Danford +/** + * @file + * @author Chris Danford (c) 2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/IniFile.h b/src/IniFile.h index 7e45a9ec58..5a468c41d2 100644 --- a/src/IniFile.h +++ b/src/IniFile.h @@ -1,4 +1,4 @@ -/* IniFile - Reading and writing .INI files. */ +/** @brief IniFile - Reading and writing .INI files. */ #ifndef INIFILE_H #define INIFILE_H @@ -7,14 +7,20 @@ using namespace std; class RageFileBasic; - +/** @brief The functions to read and write .INI files. */ class IniFile : public XNode { public: + /** @brief Set up an INI file with the defaults. */ IniFile(); - // Retrieve the filename of the last file loaded. + /** + * @brief Retrieve the filename of the last file loaded. + * @return the filename. */ RString GetPath() const { return m_sPath; } + /** + * @brief Retrieve any errors that have occurred. + * @return the latest error. */ const RString &GetError() const { return m_sError; } bool ReadFile( const RString &sPath ); @@ -42,9 +48,15 @@ public: bool DeleteKey( const RString &keyname ); bool DeleteValue( const RString &keyname, const RString &valuename ); - /* Rename a key. For example, call RenameKey("foo", "main") after - * reading an INI where [foo] is an alias to [main]. If to already - * exists, nothing happens. */ + /** + * @brief Rename a key. + * + * For example, call RenameKey("foo", "main") after reading an INI + * where [foo] is an alias to [main]. If to already exists, + * nothing happens. + * @param from the key to rename. + * @param to the new key name. + * @return its success or failure. */ bool RenameKey( const RString &from, const RString &to ); private: @@ -55,9 +67,10 @@ private: #endif -/* - * (c) 2001-2004 Adam Clauss, Chris Danford - * +/** + * @file + * @author Adam Clauss, Chris Danford (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/InputMapper.cpp b/src/InputMapper.cpp index d5d760a350..bc247c5552 100644 --- a/src/InputMapper.cpp +++ b/src/InputMapper.cpp @@ -122,7 +122,7 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_12, GAME_BUTTON_START, false ) - ), + ), AutoMappings( "dance", "4 axis 16 button joystick", @@ -156,8 +156,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_6, DANCE_BUTTON_UPRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_START, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "SideWinder Game Pad USB version 1.0", "SideWinder Game Pad USB", @@ -173,8 +173,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_START, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "4 axis 12 button joystick with hat switch", "Super Joy Box 5", @@ -190,7 +190,7 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_START, false ) - ), + ), /* AutoMappings( "dance", @@ -211,9 +211,9 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 1, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_START, false ), - ), + ), */ - AutoMappings( + AutoMappings( "dance", "MP-8866 Dual USB Joypad", "Super Dual Box (from DDRGame.com, Feb 2008)", @@ -224,12 +224,12 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_4, DANCE_BUTTON_RIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_7, DANCE_BUTTON_UPLEFT, false ), AutoMappingEntry( 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false ), - //AutoMappingEntry{ 0, JOY_BUTTON_5, DANCE_BUTTON_DOWNLEFT, false ), - //AutoMappingEntry{ 0, JOY_BUTTON_6, DANCE_BUTTON_DOWNRIGHT, false ), + //AutoMappingEntry{ 0, JOY_BUTTON_5, DANCE_BUTTON_DOWNLEFT, false ), + //AutoMappingEntry{ 0, JOY_BUTTON_6, DANCE_BUTTON_DOWNRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_START, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "NTPAD", "NTPAD", @@ -247,8 +247,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 1, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_START, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "Psx Gamepad", "PSXPAD", @@ -266,9 +266,9 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 1, JOY_BUTTON_6, DANCE_BUTTON_UPRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_START, false ) - ), + ), // TODO: add black and white buttons, as well as other missing inputs -aj - AutoMappings( + AutoMappings( "dance", "XBOX Gamepad Plugin V0.01", "X-Box gamepad", @@ -284,13 +284,13 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_8, DANCE_BUTTON_UPRIGHT, false ), // R shoulder AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_START, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_BACK, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "0b43:0003", // The EMS USB2 doesn't provide a model string, so Linux - // just gives us the VendorID and ModelID in hex. + // just gives us the VendorID and ModelID in hex. "EMS USB2", - // Player 1. + // Player 1. AutoMappingEntry( 0, JOY_BUTTON_16, DANCE_BUTTON_LEFT, false ), AutoMappingEntry( 0, JOY_BUTTON_14, DANCE_BUTTON_RIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_13, DANCE_BUTTON_UP, false ), @@ -305,7 +305,7 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_START, false ), AutoMappingEntry( 0, JOY_BUTTON_5, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_6, GAME_BUTTON_COIN, false ), - // Player 2. + // Player 2. AutoMappingEntry( 0, JOY_BUTTON_32, DANCE_BUTTON_LEFT, true ), AutoMappingEntry( 0, JOY_BUTTON_30, DANCE_BUTTON_RIGHT, true ), AutoMappingEntry( 0, JOY_BUTTON_29, DANCE_BUTTON_UP, true ), @@ -320,8 +320,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_26, GAME_BUTTON_START, true ), AutoMappingEntry( 0, JOY_BUTTON_21, GAME_BUTTON_BACK, true ), AutoMappingEntry( 0, JOY_BUTTON_22, GAME_BUTTON_COIN, true ) - ), - AutoMappings( + ), + AutoMappings( "dance", "Dance ", //Notice extra space at end "LevelSix USB Pad (DDR638)", // "DDR638" is the model number of the pad @@ -333,8 +333,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_8, DANCE_BUTTON_UPLEFT, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_START, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "SmartJoy PLUS Adapter", "SmartJoy PLUS Adapter", @@ -352,8 +352,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_9, /* Start */ GAME_BUTTON_START, false ), AutoMappingEntry( 0, JOY_BUTTON_5, /* R1 */ GAME_BUTTON_SELECT, false ), AutoMappingEntry( 0, JOY_BUTTON_6, /* R2 */ GAME_BUTTON_COIN, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "RedOctane USB Pad|XBOX DDR", // "RedOctane USB Pad" is Ignition 3s and newer Afterburners. "XBOX DDR" is older Afterburners. "RedOctane Ignition 3 or Afterburner", @@ -367,8 +367,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_8, /* O */ GAME_BUTTON_START, false ), AutoMappingEntry( 1, JOY_BUTTON_9, /* Start */ GAME_BUTTON_START, false ), AutoMappingEntry( 0, JOY_BUTTON_10, /* Sel */ GAME_BUTTON_BACK, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "Joypad to USB converter", "EMS Trio Linker", @@ -382,8 +382,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_2, /* O */ GAME_BUTTON_START, false ), AutoMappingEntry( 1, JOY_BUTTON_10, /* Start */ GAME_BUTTON_START, false ), AutoMappingEntry( 0, JOY_BUTTON_9, /* Sel */ GAME_BUTTON_BACK, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "Positive Gaming Impact USB pad", "Positive Gaming Impact USB pad", @@ -397,8 +397,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_8, /* O */ DANCE_BUTTON_UPRIGHT, false ), AutoMappingEntry( 1, JOY_BUTTON_9, /* Start */ GAME_BUTTON_START, false ), AutoMappingEntry( 0, JOY_BUTTON_10, /* Sel */ GAME_BUTTON_BACK, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "USB Dance Pad", "DDRGame Energy Dance Pad", @@ -412,8 +412,8 @@ static const AutoMappings g_AutoMappings[] = //AutoMappingEntry{ 0, JOY_BUTTON_4, DANCE_BUTTON_DOWNRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_START, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "Dual USB Vibration Joystick", "PC Multi Hub Double Power Box 4", @@ -427,8 +427,8 @@ static const AutoMappings g_AutoMappings[] = //AutoMappingEntry{ 0, JOY_BUTTON_4, DANCE_BUTTON_DOWNRIGHT, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_START, false ) - ), - AutoMappings( + ), + AutoMappings( "dance", "Controller \\(Harmonix Drum Kit for Xbox 360\\)", "Rock Band drum controller (Xbox 360, Windows driver)", @@ -442,8 +442,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_HAT_DOWN, GAME_BUTTON_MENUDOWN, false ), // d-pad down AutoMappingEntry( 0, JOY_BUTTON_8, GAME_BUTTON_START, false ), // start button AutoMappingEntry( 0, JOY_BUTTON_7, GAME_BUTTON_BACK, false ) // back button - ), - AutoMappings( + ), + AutoMappings( "pump", "Pump USB", "Pump USB pad", @@ -458,8 +458,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_9, PUMP_BUTTON_CENTER, true ), AutoMappingEntry( 0, JOY_BUTTON_10, PUMP_BUTTON_DOWNLEFT, true ), AutoMappingEntry( 0, JOY_BUTTON_11, PUMP_BUTTON_DOWNRIGHT, true ) - ), - AutoMappings( + ), + AutoMappings( "pump", "GamePad Pro USB ", // yes, there is a space at the end "GamePad Pro USB", @@ -474,8 +474,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 1, JOY_BUTTON_1, PUMP_BUTTON_CENTER, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_10, GAME_BUTTON_START, false ) - ), - AutoMappings( + ), + AutoMappings( "pump", "Controller \\(Harmonix Drum Kit for Xbox 360\\)", "Rock Band drum controller (Xbox 360, Windows driver)", @@ -490,8 +490,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_HAT_DOWN, GAME_BUTTON_MENUDOWN, false ), // d-pad down AutoMappingEntry( 0, JOY_BUTTON_8, GAME_BUTTON_START, false ), // start button AutoMappingEntry( 0, JOY_BUTTON_7, GAME_BUTTON_BACK, false ) // back button - ), - AutoMappings( + ), + AutoMappings( "para", "ParaParaParadise Controller", "ParaParaParadise Controller", @@ -504,8 +504,8 @@ static const AutoMappings g_AutoMappings[] = AutoMappingEntry( 0, JOY_BUTTON_11, GAME_BUTTON_BACK, false ), AutoMappingEntry( 0, JOY_BUTTON_12, GAME_BUTTON_MENULEFT, false ), AutoMappingEntry( 0, JOY_BUTTON_9, GAME_BUTTON_MENURIGHT, false ) - ), - AutoMappings( + ), + AutoMappings( "techno", "Dance ", //Notice the extra space at end "LevelSix USB Pad (DDR638)", // "DDR638" is the model number of the pad @@ -1075,7 +1075,7 @@ void InputMappings::ReadMappings( const InputScheme *pInputScheme, RString sFile if( !ini.GetValue( "AutoMapping", "DeviceRegex", m_sDeviceRegex ) ) Dialog::OK( "Missing AutoMapping::DeviceRegex in '%s'", sFilePath.c_str() ); - if( !ini.GetValue( "AutoMapping", "Description", m_sDescription ) ) + if( !ini.GetValue( "AutoMapping", "Description", m_sDescription ) ) Dialog::OK( "Missing AutoMapping::Description in '%s'", sFilePath.c_str() ); } diff --git a/src/LightsManager.cpp b/src/LightsManager.cpp index facf0530e7..8e17f094b5 100644 --- a/src/LightsManager.cpp +++ b/src/LightsManager.cpp @@ -120,7 +120,7 @@ LightsManager::~LightsManager() m_vpDrivers.clear(); } -// XXX: make themable +// XXX: Allow themer to change these. (rewritten; who wrote original? -aj) static const float g_fLightEffectRiseSeconds = 0.075f; static const float g_fLightEffectFalloffSeconds = 0.35f; static const float g_fCoinPulseTime = 0.100f; @@ -453,7 +453,7 @@ void LightsManager::ChangeTestCabinetLight( int iDir ) void LightsManager::ChangeTestGameButtonLight( int iDir ) { m_clTestManualCycleCurrent = CabinetLight_Invalid; - + vector vGI; GetUsedGameInputs( vGI ); @@ -473,9 +473,9 @@ CabinetLight LightsManager::GetFirstLitCabinetLight() GameInput LightsManager::GetFirstLitGameButtonLight() { - FOREACH_ENUM( GameController, gc ) + FOREACH_ENUM( GameController, gc ) { - FOREACH_ENUM( GameButton, gb ) + FOREACH_ENUM( GameButton, gb ) { if( m_LightsState.m_bGameButtonLights[gc][gb] ) return GameInput( gc, gb ); @@ -489,7 +489,6 @@ bool LightsManager::IsEnabled() const return m_vpDrivers.size() >= 1 || PREFSMAN->m_bDebugLights; } - /* * (c) 2003-2004 Chris Danford * All rights reserved. diff --git a/src/LightsManager.h b/src/LightsManager.h index 0a3b5fc132..0934744ba6 100644 --- a/src/LightsManager.h +++ b/src/LightsManager.h @@ -61,7 +61,7 @@ class LightsManager public: LightsManager(); ~LightsManager(); - + void Update( float fDeltaTime ); bool IsEnabled() const; @@ -105,7 +105,6 @@ private: int m_iControllerTestManualCycleCurrent; }; - extern LightsManager* LIGHTSMAN; // global and accessable from anywhere in our program #endif diff --git a/src/LyricDisplay.cpp b/src/LyricDisplay.cpp index 2d82037065..21e8b5dfd9 100644 --- a/src/LyricDisplay.cpp +++ b/src/LyricDisplay.cpp @@ -40,7 +40,7 @@ void LyricDisplay::Update( float fDeltaTime ) if( GAMESTATE->m_pCurSong == NULL ) return; - /* If the song has changed (in a course), reset. */ + // If the song has changed (in a course), reset. if( GAMESTATE->m_fMusicSeconds < m_fLastSecond ) Init(); m_fLastSecond = GAMESTATE->m_fMusicSeconds; @@ -54,7 +54,7 @@ void LyricDisplay::Update( float fDeltaTime ) if( GAMESTATE->m_fMusicSeconds < fStartTime ) return; - /* Clamp this lyric to the beginning of the next or the end of the music. */ + // Clamp this lyric to the beginning of the next or the end of the music. float fEndTime; if( m_iCurLyricNumber+1 < GAMESTATE->m_pCurSong->m_LyricSegments.size() ) fEndTime = pSong->m_LyricSegments[m_iCurLyricNumber+1].m_fStartTime; @@ -65,7 +65,7 @@ void LyricDisplay::Update( float fDeltaTime ) const float fTweenBufferTime = IN_LENGTH.GetValue() + OUT_LENGTH.GetValue(); /* If it's negative, two lyrics are so close together that there's no time - * to tween properly. Lyrics should never be this brief, anyway, so just + * to tween properly. Lyrics should never be this brief, anyway, so just * skip it. */ float fShowLength = max( fDistance - fTweenBufferTime, 0.0f ); diff --git a/src/LyricDisplay.h b/src/LyricDisplay.h index f4f1f3c359..a5d7baecf7 100644 --- a/src/LyricDisplay.h +++ b/src/LyricDisplay.h @@ -12,7 +12,7 @@ public: LyricDisplay(); void Update( float fDeltaTime ); - /* Call when song changes: */ + // Call when song changes: void Init(); private: diff --git a/src/LyricsLoader.cpp b/src/LyricsLoader.cpp index 72f53de259..94c5e59d59 100644 --- a/src/LyricsLoader.cpp +++ b/src/LyricsLoader.cpp @@ -8,8 +8,9 @@ #include -// TODO: Use marker for default color instead of a specific color that may accidentally get written back into a lyrics file. -#define LYRICS_DEFAULT_COLOR THEME->GetMetricC("ScreenGameplay","LyricDisplayDefaultColor") +// TODO: Use a marker for default color instead of a specific color that may +// accidentally get written back into a lyrics file. +#define LYRICS_DEFAULT_COLOR THEME->GetMetricC("ScreenGameplay","LyricDisplayDefaultColor") static int CompareLyricSegments(const LyricSegment &seg1, const LyricSegment &seg2) { @@ -67,6 +68,8 @@ bool LyricsLoader::LoadFromLRCFile(const RString& sPath, Song& out) // set color var here for this segment int r, g, b; int result = sscanf( sValueData.c_str(), "0x%2x%2x%2x", &r, &g, &b ); + // According to the Dance With Intensity readme, one can set up to + // ten colors in a line and access them via "{cX}", where X is 0-9. if(result != 3) { LOG->Trace( "The color value '%s' in '%s' is invalid.", @@ -78,11 +81,13 @@ bool LyricsLoader::LoadFromLRCFile(const RString& sPath, Song& out) continue; } - // todo: handle [offset:xxxx] (where xxxx is in milliseconds) tag? -aj + // todo: handle [offset:xxxx] tag? -aj (xxxx is milliseconds) + // offsets each timestamp after the offset by that amount. + //float fLyricOffset = 0.0f; { - /* If we've gotten this far, and no other statement caught - * this value before this does, assume it's a time value. */ + /* If we've gotten this far, and no other statement caught this + * value before this does, assume it's a time value. */ LyricSegment seg; seg.m_Color = CurrentColor; diff --git a/src/Makefile.am b/src/Makefile.am index 59aa06f79f..28eb71d84d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -144,8 +144,11 @@ LyricsLoader.cpp LyricsLoader.h \ ModsGroup.cpp ModsGroup.h \ NoteData.cpp NoteData.h NoteDataUtil.cpp NoteDataUtil.h NoteDataWithScoring.cpp NoteDataWithScoring.h \ NoteTypes.cpp NoteTypes.h NotesLoader.cpp NotesLoader.h \ -NotesLoaderBMS.cpp NotesLoaderBMS.h NotesLoaderDWI.cpp NotesLoaderDWI.h NotesLoaderKSF.cpp NotesLoaderKSF.h NotesLoaderMidi.cpp NotesLoaderMidi.h \ -NotesLoaderPMS.cpp NotesLoaderPMS.h NotesLoaderSM.cpp NotesLoaderSM.h NotesWriterDWI.cpp NotesWriterDWI.h NotesWriterSM.cpp NotesWriterSM.h \ +NotesLoaderBMS.cpp NotesLoaderBMS.h NotesLoaderDWI.cpp NotesLoaderDWI.h \ +NotesLoaderKSF.cpp NotesLoaderKSF.h NotesLoaderMidi.cpp NotesLoaderMidi.h \ +NotesLoaderPMS.cpp NotesLoaderPMS.h NotesLoaderSM.cpp NotesLoaderSM.h \ +NotesLoaderSSC.cpp NotesLoaderSSC.h NotesWriterDWI.cpp NotesWriterDWI.h \ +NotesWriterSM.cpp NotesWriterSM.h NotesWriterSSC.cpp NotesWriterSSC.h \ OptionRowHandler.cpp OptionRowHandler.h OptionsList.cpp OptionsList.h \ PlayerAI.cpp PlayerAI.h PlayerNumber.cpp PlayerNumber.h PlayerOptions.cpp PlayerOptions.h \ PlayerStageStats.cpp PlayerStageStats.h \ @@ -320,11 +323,11 @@ DifficultyList.cpp DifficultyList.h \ DualScrollBar.cpp DualScrollBar.h \ EditMenu.cpp EditMenu.h FadingBanner.cpp FadingBanner.h \ GradeDisplay.cpp GradeDisplay.h GraphDisplay.cpp GraphDisplay.h \ -GrooveRadar.cpp GrooveRadar.h GroupList.cpp GroupList.h HelpDisplay.cpp HelpDisplay.h \ +GrooveRadar.cpp GrooveRadar.h HelpDisplay.cpp HelpDisplay.h \ MemoryCardDisplay.cpp MemoryCardDisplay.h \ MenuTimer.cpp MenuTimer.h \ ModIcon.cpp ModIcon.h ModIconRow.cpp ModIconRow.h \ -MusicList.cpp MusicList.h MusicWheel.cpp MusicWheel.h \ +MusicWheel.cpp MusicWheel.h \ MusicWheelItem.cpp MusicWheelItem.h \ OptionRow.cpp OptionRow.h OptionsCursor.cpp OptionsCursor.h \ PaneDisplay.cpp PaneDisplay.h ScrollBar.cpp ScrollBar.h \ diff --git a/src/MenuTimer.cpp b/src/MenuTimer.cpp index 2f21847b4d..0a277fa766 100644 --- a/src/MenuTimer.cpp +++ b/src/MenuTimer.cpp @@ -47,6 +47,7 @@ void MenuTimer::Load( RString sMetricsGroup ) WARNING_START.Load(sMetricsGroup,"WarningStart"); WARNING_BEEP_START.Load(sMetricsGroup,"WarningBeepStart"); MAX_STALL_SECONDS.Load(sMetricsGroup,"MaxStallSeconds"); + HURRY_UP_TRANSITION.Load(sMetricsGroup,"HurryUpTransition"); // clear warning commands out if they already exist. -aj if(WARNING_COMMAND) @@ -90,7 +91,7 @@ void MenuTimer::Update( float fDeltaTime ) if( fOldSecondsLeft == fNewSecondsLeft ) return; - if( fOldSecondsLeft > 5.5 && fNewSecondsLeft < 5.5 ) // transition to below 5.5 + if( fOldSecondsLeft > HURRY_UP_TRANSITION && fNewSecondsLeft < HURRY_UP_TRANSITION ) SOUND->PlayOnceFromAnnouncer( "hurry up" ); @@ -138,10 +139,10 @@ void MenuTimer::Disable() void MenuTimer::Stall() { - /* Max amount of stall time we'll use: */ + // Max amount of stall time we'll use: const float Amt = min( 0.5f, m_fStallSecondsLeft ); - /* Amount of stall time to add: */ + // Amount of stall time to add: const float ToAdd = Amt - m_fStallSeconds; m_fStallSeconds += ToAdd; @@ -183,7 +184,7 @@ void MenuTimer::SetText( float fSeconds ) RString sText; LuaHelpers::Pop( L, sText ); - + m_text[i].SetText( sText ); } @@ -196,11 +197,11 @@ void MenuTimer::SetText( float fSeconds ) class LunaMenuTimer: public Luna { public: - static int setseconds( T* p, lua_State *L ) { p->SetSeconds(FArg(1)); return 0; } - static int GetSeconds( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSeconds() ); return 1; } - static int pause( T* p, lua_State *L ) { p->Pause(); return 0; } + static int setseconds( T* p, lua_State *L ) { p->SetSeconds(FArg(1)); return 0; } + static int GetSeconds( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSeconds() ); return 1; } + static int pause( T* p, lua_State *L ) { p->Pause(); return 0; } static int stop( T* p, lua_State *L ) { p->Stop(); return 0; } - static int silent( T* p, lua_State *L ) { p->EnableSilent(BArg(1)); return 0; } + static int silent( T* p, lua_State *L ) { p->EnableSilent(BArg(1)); return 0; } static int stealth( T* p, lua_State *L ) { p->EnableStealth(BArg(1)); return 0; } LunaMenuTimer() diff --git a/src/MenuTimer.h b/src/MenuTimer.h index 0fdbdf68aa..7994c27942 100644 --- a/src/MenuTimer.h +++ b/src/MenuTimer.h @@ -53,6 +53,7 @@ protected: ThemeMetric WARNING_START; ThemeMetric WARNING_BEEP_START; ThemeMetric MAX_STALL_SECONDS; + ThemeMetric HURRY_UP_TRANSITION; ThemeMetric1D *WARNING_COMMAND; }; diff --git a/src/MessageManager.cpp b/src/MessageManager.cpp index 5cae2baf5e..ee4dcd6e9b 100644 --- a/src/MessageManager.cpp +++ b/src/MessageManager.cpp @@ -52,6 +52,8 @@ static const char *MessageIDNames[] = { "MenuLeftP2", "MenuRightP1", "MenuRightP2", + "MenuStartP1", + "MenuStartP2", "MenuSelectionChanged", "PlayerJoined", "PlayerUnjoined", diff --git a/src/MessageManager.h b/src/MessageManager.h index b84afc138a..3d424ce3aa 100644 --- a/src/MessageManager.h +++ b/src/MessageManager.h @@ -49,6 +49,8 @@ enum MessageID Message_MenuLeftP2, Message_MenuRightP1, Message_MenuRightP2, + Message_MenuStartP1, + Message_MenuStartP2, Message_MenuSelectionChanged, Message_PlayerJoined, Message_PlayerUnjoined, diff --git a/src/ModIcon.cpp b/src/ModIcon.cpp index 9c9adc8ffb..aba73c36af 100644 --- a/src/ModIcon.cpp +++ b/src/ModIcon.cpp @@ -69,7 +69,7 @@ void ModIcon::Set( const RString &_sText ) m_sprEmpty->SetVisible( bVacant ); m_text.SetText( sText ); - // This line makes Lua option rows crash: -aj + // This line makes Lua option rows crash: -aj m_text.CropToWidth( CROP_TEXT_TO_WIDTH ); } diff --git a/src/ModIconRow.cpp b/src/ModIconRow.cpp index 7f3470cae8..d5cfaa2963 100644 --- a/src/ModIconRow.cpp +++ b/src/ModIconRow.cpp @@ -77,7 +77,7 @@ static const OptionColumnEntry g_OptionColumnEntries[] = {"Brake", 0}, {"Wave", 0}, {"Expand", 0}, - {"Boomerang", 0}, + {"Boomerang", 0}, //--------------------// {"Drunk", 1}, {"Dizzy", 1}, @@ -89,13 +89,13 @@ static const OptionColumnEntry g_OptionColumnEntries[] = {"Sudden", 2}, {"Stealth", 2}, {"Blink", 2}, - {"RandomVanish", 2}, + {"RandomVanish",2}, //--------------------// {"Mirror", 3}, {"Left", 3}, {"Right", 3}, {"Shuffle", 3}, - {"SuperShuffle", 3}, + {"SuperShuffle",3}, //--------------------// {"Little", 4}, {"NoHolds", 4}, @@ -104,11 +104,11 @@ static const OptionColumnEntry g_OptionColumnEntries[] = //--------------------// {"Reverse", 5}, {"Split", 5}, - {"Alternate", 5}, + {"Alternate", 5}, {"Cross", 5}, - {"Centered", 5}, + {"Centered", 5}, //--------------------// - {"Incoming", 6}, + {"Incoming", 6}, {"Space", 6}, {"Hallway", 6}, {"Distant", 6}, @@ -116,7 +116,7 @@ static const OptionColumnEntry g_OptionColumnEntries[] = int OptionToPreferredColumn( RString sOptionText ) { - /* Speedups always go in column 0. digit ... x */ + // Speedups always go in column 0. digit ... x if( sOptionText.size() > 1 && isdigit(sOptionText[0]) && tolower(sOptionText[sOptionText.size()-1]) == 'x' ) @@ -128,7 +128,7 @@ int OptionToPreferredColumn( RString sOptionText ) if( g_OptionColumnEntries[i].szString == sOptionText ) return g_OptionColumnEntries[i].iSlotIndex; - /* This warns about C1234 and noteskins. */ + // This warns about C1234 and noteskins. // LOG->Warn("Unknown option: '%s'", sOptionText.c_str() ); return 0; } diff --git a/src/ModelTypes.cpp b/src/ModelTypes.cpp index f2719737c9..52158bbf30 100644 --- a/src/ModelTypes.cpp +++ b/src/ModelTypes.cpp @@ -238,9 +238,7 @@ bool msAnimation::LoadMilkshapeAsciiBones( RString sAniName, RString sPath ) if (!strncmp (sLine, "//", 2)) continue; - // // bones - // int nNumBones = 0; if( sscanf (sLine, "Bones: %d", &nNumBones) != 1 ) continue; @@ -256,15 +254,15 @@ bool msAnimation::LoadMilkshapeAsciiBones( RString sAniName, RString sPath ) // name if( f.GetLine( sLine ) <= 0 ) THROW; - if (sscanf (sLine, "\"%31[^\"]\"", szName) != 1) + if (sscanf(sLine, "\"%31[^\"]\"", szName) != 1) THROW; Bone.sName = szName; // parent if( f.GetLine( sLine ) <= 0 ) THROW; - strcpy (szName, ""); - sscanf (sLine, "\"%31[^\"]\"", szName); + strcpy(szName, ""); + sscanf(sLine, "\"%31[^\"]\"", szName); Bone.sParentName = szName; diff --git a/src/MsdFile.h b/src/MsdFile.h index b18ed60342..0b52d639ab 100644 --- a/src/MsdFile.h +++ b/src/MsdFile.h @@ -1,47 +1,107 @@ -/* MsdFile - Read .SM, .DWI, and .MSD files. */ +/** @brief MsdFile - Read .SSC, .SM, .DWI, and .MSD files. */ #ifndef MSDFILE_H #define MSDFILE_H +/** @brief The class that reads the various .SSC, .SM, .DWI, and .MSD files. */ class MsdFile { public: - /* #param:param:param:param; <- one whole value */ + /** + * @brief The list of params found in the files. + * + * Note that #param:param:param:param; is one whole value. */ struct value_t { + /** @brief The list of parameters. */ vector params; - + /** + * @brief Access the proper parameter. + * @param i the index. + * @return the proper parameter. + */ RString operator[]( unsigned i ) const { if( i >= params.size() ) return RString(); return params[i]; } }; + /** @brief Remove the MSDFile. */ virtual ~MsdFile() { } - // Returns true if successful, false otherwise. + /** + * @brief Attempt to read an MSD file. + * @param sFilePath the path to the file. + * @param bUnescape a flag to see if we need to unescape values. + * @return its success or failure. + */ bool ReadFile( RString sFilePath, bool bUnescape ); + /** + * @brief Attempt to read an MSD file. + * @param sString the path to the file. + * @param bUnescape a flag to see if we need to unescape values. + * @return its success or failure. + */ void ReadFromString( const RString &sString, bool bUnescape ); + /** + * @brief Should an error take place, have an easy place to get it. + * @return the current error. */ RString GetError() const { return error; } + /** + * @brief Retrieve the number of values for each tag. + * @return the nmber of values. */ unsigned GetNumValues() const { return values.size(); } + /** + * @brief Get the number of parameters for the current index. + * @param val the current value index. + * @return the number of params. + */ unsigned GetNumParams( unsigned val ) const { if( val >= GetNumValues() ) return 0; return values[val].params.size(); } + /** + * @brief Get the specified value. + * @param val the current value index. + * @return The specified value. + */ const value_t &GetValue( unsigned val ) const { ASSERT(val < GetNumValues()); return values[val]; } + /** + * @brief Retrieve the specified parameter. + * @param val the current value index. + * @param par the current parameter index. + * @return the parameter in question. + */ RString GetParam( unsigned val, unsigned par ) const; private: + /** + * @brief Attempt to read an MSD file from the buffer. + * @param buf the buffer containing the MSD file. + * @param len the length of the buffer. + * @param bUnescape a flag to see if we need to unescape values. + */ void ReadBuf( const char *buf, int len, bool bUnescape ); + /** + * @brief Add a new parameter. + * @param buf the new parameter. + * @param len the length of the new parameter. + */ void AddParam( const char *buf, int len ); + /** + * @brief Add a new value. + */ void AddValue(); + /** @brief The list of values. */ vector values; + /** @brief The error string. */ RString error; }; #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard - * +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/MusicList.cpp b/src/MusicList.cpp deleted file mode 100644 index 8327108f5d..0000000000 --- a/src/MusicList.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "global.h" -#include "MusicList.h" -#include "ThemeManager.h" -#include "ThemeMetric.h" -#include "RageUtil.h" -#include "Song.h" -#include "ActorUtil.h" - -/* If this actor is used anywhere other than SelectGroup, we can add a setting - * that changes which metric group we pull settings out of, so it can be - * configured separately. */ -static const ThemeMetric NUM_COLUMNS ("MusicList","NumColumns"); -static const ThemeMetric NUM_ROWS ("MusicList","NumRows"); -static const ThemeMetric START_X ("MusicList","StartX"); -static const ThemeMetric START_Y ("MusicList","StartY"); -static const ThemeMetric SPACING_X ("MusicList","SpacingX"); -static const ThemeMetric CROP_WIDTH ("MusicList","CropWidth"); - -MusicList::MusicList() -{ - CurGroup = 0; -} - -void MusicList::Load() -{ - for( int i=0; iGetPathF("MusicList","titles") ); - m_textTitles[i].SetXY( START_X + i*SPACING_X, START_Y ); - m_textTitles[i].PlayCommand( "Init" ); - this->AddChild( &m_textTitles[i] ); - } -} - -void MusicList::AddGroup() -{ - m_ContentsText.push_back(group()); -} - -void MusicList::AddSongsToGroup(const vector &Songs) -{ - // Generate what text will show in the contents for each group - unsigned group = m_ContentsText.size()-1; - - m_ContentsText[group].m_iNumSongsInGroup = Songs.size(); - - for( int c=0; c= Songs.size() ) - continue; - - if( c == NUM_COLUMNS-1 && r == NUM_ROWS-1 && Songs.size() != unsigned(NUM_COLUMNS*NUM_ROWS) ) - { - sText += ssprintf( "%i more.....", int(Songs.size() - NUM_COLUMNS * NUM_ROWS + 1) ); - continue; - } - - RString sTitle = Songs[iIndex]->GetDisplayFullTitle(); - // TODO: Move this crop threshold into a theme metric or make automatic based on column width - if( sTitle.size() > 40 ) - sTitle = sTitle.Left( 37 ) + "..."; - - RString sTrTitle = Songs[iIndex]->GetTranslitFullTitle(); - if( sTrTitle.size() > 40 ) - sTrTitle = sTrTitle.Left( 37 ) + "..."; - - /* If the main title isn't complete for this font, and we have a translit, - * use it. */ - if(m_textTitles[c].StringWillUseAlternate(sTitle, sTrTitle)) - sText += sTrTitle; - else - sText += sTitle; - sText += "\n"; - } - m_ContentsText[group].ContentsText[c] = sText; - } - -} - -/* TODO: tween? */ -void MusicList::SetGroupNo(int group) -{ - CurGroup = group; - - for( int c=0; cUpdateRankingCourses(); @@ -629,6 +633,7 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt iSectionCount = j-i; // new section, make a section item + // todo: preferred sort section color handling? -aj RageColor colorSection = (so==SORT_GROUP) ? SONGMAN->GetSongGroupColor(pSong->m_sGroupName) : SECTION_COLORS.GetValue(iSectionColorIndex); iSectionColorIndex = (iSectionColorIndex+1) % NUM_SECTION_COLORS; // In certain situations (e.g. simulating Pump it Up), themes may @@ -644,7 +649,7 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt if( so != SORT_ROULETTE ) { if( SHOW_ROULETTE ) - arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_ROULETTE, NULL, "", NULL, RageColor(1,0,0,1), 0) ); + arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_ROULETTE, NULL, "", NULL, ROULETTE_COLOR, 0) ); // Only add TYPE_PORTAL if there's at least one song on the list. bool bFoundAnySong = false; @@ -653,10 +658,10 @@ void MusicWheel::BuildWheelItemDatas( vector &arrayWheelIt bFoundAnySong = true; if( SHOW_RANDOM && bFoundAnySong ) - arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_RANDOM, NULL, "", NULL, RageColor(1,0,0,1), 0) ); + arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_RANDOM, NULL, "", NULL, RANDOM_COLOR, 0) ); if( SHOW_PORTAL && bFoundAnySong ) - arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_PORTAL, NULL, "", NULL, RageColor(1,0,0,1), 0) ); + arrayWheelItemDatas.push_back( new MusicWheelItemData(TYPE_PORTAL, NULL, "", NULL, PORTAL_COLOR, 0) ); } if( GAMESTATE->IsAnExtraStageAndSelectionLocked() ) diff --git a/src/MusicWheel.h b/src/MusicWheel.h index 92b3263988..78e6206856 100644 --- a/src/MusicWheel.h +++ b/src/MusicWheel.h @@ -88,6 +88,9 @@ protected: ThemeMetric USE_SECTIONS_WITH_PREFERRED_GROUP; ThemeMetric HIDE_INACTIVE_SECTIONS; ThemeMetric REMIND_WHEEL_POSITIONS; + ThemeMetric ROULETTE_COLOR; + ThemeMetric RANDOM_COLOR; + ThemeMetric PORTAL_COLOR; vector m_viWheelPositions; }; diff --git a/src/NetworkSyncManager.cpp b/src/NetworkSyncManager.cpp index f78bda96bd..c762fa3239 100644 --- a/src/NetworkSyncManager.cpp +++ b/src/NetworkSyncManager.cpp @@ -839,12 +839,14 @@ LuaFunction( ConnectToServer, ConnectToServer( ( RString(SArg(1)).length()==0 #endif static bool ReportStyle() { NSMAN->ReportStyle(); return true; } +static bool CloseNetworkConnection() { NSMAN->CloseConnection(); return true; } LuaFunction( IsSMOnlineLoggedIn, NSMAN->isSMOLoggedIn[Enum::Check(L, 1)] ) LuaFunction( IsNetConnected, NSMAN->useSMserver ) LuaFunction( IsNetSMOnline, NSMAN->isSMOnline ) LuaFunction( ReportStyle, ReportStyle() ) LuaFunction( GetServerName, NSMAN->GetServerName() ) +LuaFunction( CloseConnection, CloseNetworkConnection() ) /* * (c) 2003-2004 Charles Lohr, Joshua Allen diff --git a/src/NoteDataUtil.cpp b/src/NoteDataUtil.cpp index 9d484513dc..35ed1030b0 100644 --- a/src/NoteDataUtil.cpp +++ b/src/NoteDataUtil.cpp @@ -5,6 +5,7 @@ #include "RageLog.h" #include "PlayerOptions.h" #include "Song.h" +#include "Style.h" #include "GameState.h" #include "RadarValues.h" #include "Foreach.h" @@ -446,9 +447,22 @@ void NoteDataUtil::SplitCompositeNoteData( const NoteData &in, vector { int row = iter->first; TapNote tn = iter->second; + /* + XXX: This code is (hopefully) a temporary hack to make sure that + routine charts don't have any notes without players assigned to them. + I suspect this is due to a related bug that these problems were + occuring to begin with, but at this time, I am unsure how to deal with it. + Hopefully this hack can be removed soon. -- Jason "Wolfman2000" Felds + */ + const Style *curStyle = GAMESTATE->GetCurrentStyle(); + if( (curStyle == NULL || curStyle->m_StyleType == StyleType_TwoPlayersSharedSides ) + && int( tn.pn ) > NUM_PlayerNumber ) + { + tn.pn = PLAYER_1; + } unsigned index = int( tn.pn ); - ASSERT( index < NUM_PlayerNumber ); + ASSERT_M( index < NUM_PlayerNumber, ssprintf("We have a note not assigned to a player. The note in question is on beat %f, column %i.", NoteRowToBeat(row), t + 1) ); tn.pn = PLAYER_INVALID; out[index].SetTapNote( t, row, tn ); } @@ -1368,7 +1382,7 @@ void NoteDataUtil::Little( NoteData &inout, int iStartIndex, int iEndIndex ) } } -// Make all all quarter notes into jumps. +// Make all quarter notes into jumps. void NoteDataUtil::Wide( NoteData &inout, int iStartIndex, int iEndIndex ) { /* Start on an even beat. */ diff --git a/src/NoteDisplay.cpp b/src/NoteDisplay.cpp index 602bb04aec..238bdf84f0 100644 --- a/src/NoteDisplay.cpp +++ b/src/NoteDisplay.cpp @@ -155,7 +155,7 @@ static void DeleteNoteResource( NoteResource *pRes ) { ASSERT( pRes != NULL ); - ASSERT_M( pRes->m_iRefCount > 0, ssprintf("%i", pRes->m_iRefCount) ); + ASSERT_M( pRes->m_iRefCount > 0, ssprintf("RefCount %i > 0", pRes->m_iRefCount) ); --pRes->m_iRefCount; if( pRes->m_iRefCount ) return; diff --git a/src/NoteField.cpp b/src/NoteField.cpp index d0305eeb36..9dbb8d88ff 100644 --- a/src/NoteField.cpp +++ b/src/NoteField.cpp @@ -27,6 +27,7 @@ static ThemeMetric BAR_MEASURE_ALPHA( "NoteField", "BarMeasureAlpha" ); static ThemeMetric BAR_4TH_ALPHA( "NoteField", "Bar4thAlpha" ); static ThemeMetric BAR_8TH_ALPHA( "NoteField", "Bar8thAlpha" ); static ThemeMetric BAR_16TH_ALPHA( "NoteField", "Bar16thAlpha" ); +static ThemeMetric FADE_FAIL_TIME( "NoteField", "FadeFailTime" ); static RString RoutineNoteSkinName( size_t i ) { return ssprintf("RoutineNoteSkinP%i",int(i+1)); } static ThemeMetric1D ROUTINE_NOTESKIN( "NoteField", RoutineNoteSkinName, NUM_PLAYERS ); @@ -264,9 +265,8 @@ void NoteField::Update( float fDeltaTime ) cur->m_ReceptorArrowRow.Update( fDeltaTime ); cur->m_GhostArrowRow.Update( fDeltaTime ); - // TODO: make fade time of 1.5 seconds metricable instead? -aj if( m_fPercentFadeToFail >= 0 ) - m_fPercentFadeToFail = min( m_fPercentFadeToFail + fDeltaTime/1.5f, 1 ); // take 1.5 seconds to totally fade + m_fPercentFadeToFail = min( m_fPercentFadeToFail + fDeltaTime/FADE_FAIL_TIME, 1 ); // Update fade to failed m_pCurDisplay->m_ReceptorArrowRow.SetFadeToFailPercent( m_fPercentFadeToFail ); @@ -412,18 +412,36 @@ void NoteField::DrawAreaHighlight( int iStartBeat, int iEndBeat ) // todo: add DrawWarpAreaBG? -aj +static ThemeMetric BPM_COLOR ( "NoteField", "BPMColor" ); +static ThemeMetric STOP_COLOR ( "NoteField", "StopColor" ); +static ThemeMetric DELAY_COLOR ( "NoteField", "DelayColor" ); +static ThemeMetric TIME_SIGNATURE_COLOR ( "NoteField", "TimeSignatureColor" ); +static ThemeMetric TICKCOUNT_COLOR ( "NoteField", "TickcountColor" ); +static ThemeMetric BPM_IS_LEFT_SIDE ( "NoteField", "BPMIsLeftSide" ); +static ThemeMetric STOP_IS_LEFT_SIDE ( "NoteField", "StopIsLeftSide" ); +static ThemeMetric DELAY_IS_LEFT_SIDE ( "NoteField", "DelayIsLeftSide" ); +static ThemeMetric TIME_SIGNATURE_IS_LEFT_SIDE ( "NoteField", "TimeSignatureIsLeftSide" ); +static ThemeMetric TICKCOUNT_IS_LEFT_SIDE ( "NoteField", "TickcountIsLeftSide" ); +static ThemeMetric BPM_OFFSETX ( "NoteField", "BPMOffsetX" ); +static ThemeMetric STOP_OFFSETX ( "NoteField", "StopOffsetX" ); +static ThemeMetric DELAY_OFFSETX ( "NoteField", "DelayOffsetX" ); +static ThemeMetric TIME_SIGNATURE_OFFSETX ( "NoteField", "TimeSignatureOffsetX" ); +static ThemeMetric TICKCOUNT_OFFSETX ( "NoteField", "TickcountOffsetX" ); + void NoteField::DrawBPMText( const float fBeat, const float fBPM ) { const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat ); const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels ); const float fZoom = ArrowEffects::GetZoom( m_pPlayerState ); + const float xBase = GetWidth()/2.f; + const float xOffset = BPM_OFFSETX * fZoom; m_textMeasureNumber.SetZoom( fZoom ); - m_textMeasureNumber.SetHorizAlign( align_right ); - m_textMeasureNumber.SetDiffuse( RageColor(1,0,0,1) ); + m_textMeasureNumber.SetHorizAlign( BPM_IS_LEFT_SIDE ? align_right : align_left ); + m_textMeasureNumber.SetDiffuse( BPM_COLOR ); m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) ); m_textMeasureNumber.SetText( ssprintf("%.3f", fBPM) ); - m_textMeasureNumber.SetXY( -GetWidth()/2 - 60*fZoom, fYPos ); + m_textMeasureNumber.SetXY( (BPM_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos ); m_textMeasureNumber.Draw(); } @@ -432,16 +450,24 @@ void NoteField::DrawFreezeText( const float fBeat, const float fSecs, const floa const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat ); const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels ); const float fZoom = ArrowEffects::GetZoom( m_pPlayerState ); + const float xBase = GetWidth()/2.f; + const float xOffset = (bDelay ? DELAY_OFFSETX : STOP_OFFSETX) * fZoom; m_textMeasureNumber.SetZoom( fZoom ); - m_textMeasureNumber.SetHorizAlign( align_right ); if(bDelay) - m_textMeasureNumber.SetDiffuse( RageColor(0,0.8f,0.8f,1) ); + { + m_textMeasureNumber.SetHorizAlign( DELAY_IS_LEFT_SIDE ? align_right : align_left ); + m_textMeasureNumber.SetDiffuse( DELAY_COLOR ); + m_textMeasureNumber.SetXY( (DELAY_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos ); + } else - m_textMeasureNumber.SetDiffuse( RageColor(0.8f,0.8f,0,1) ); + { + m_textMeasureNumber.SetHorizAlign( STOP_IS_LEFT_SIDE ? align_right : align_left ); + m_textMeasureNumber.SetDiffuse( STOP_COLOR ); + m_textMeasureNumber.SetXY( (STOP_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos ); + } m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) ); m_textMeasureNumber.SetText( ssprintf("%.3f", fSecs) ); - m_textMeasureNumber.SetXY( -GetWidth()/2.f - 10*fZoom, fYPos ); m_textMeasureNumber.Draw(); } @@ -450,13 +476,32 @@ void NoteField::DrawTimeSignatureText( const float fBeat, int iNumerator, int iD const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat ); const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels ); const float fZoom = ArrowEffects::GetZoom( m_pPlayerState ); + const float xBase = GetWidth()/2.f; + const float xOffset = TIME_SIGNATURE_OFFSETX * fZoom; m_textMeasureNumber.SetZoom( fZoom ); - m_textMeasureNumber.SetHorizAlign( align_right ); - m_textMeasureNumber.SetDiffuse( RageColor(0.8f,0.8f,0,1) ); + m_textMeasureNumber.SetHorizAlign( TIME_SIGNATURE_IS_LEFT_SIDE ? align_right : align_left ); + m_textMeasureNumber.SetDiffuse( TIME_SIGNATURE_COLOR ); m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) ); m_textMeasureNumber.SetText( ssprintf("%d\n--\n%d", iNumerator, iDenominator) ); - m_textMeasureNumber.SetXY( -GetWidth()/2.f - 30*fZoom, fYPos ); + m_textMeasureNumber.SetXY( (TIME_SIGNATURE_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos ); + m_textMeasureNumber.Draw(); +} + +void NoteField::DrawTickcountText( const float fBeat, int iTicks ) +{ + const float fYOffset = ArrowEffects::GetYOffset( m_pPlayerState, 0, fBeat ); + const float fYPos = ArrowEffects::GetYPos( m_pPlayerState, 0, fYOffset, m_fYReverseOffsetPixels ); + const float fZoom = ArrowEffects::GetZoom( m_pPlayerState ); + const float xBase = GetWidth()/2.f; + const float xOffset = TICKCOUNT_OFFSETX * fZoom; + + m_textMeasureNumber.SetZoom( fZoom ); + m_textMeasureNumber.SetHorizAlign( TICKCOUNT_IS_LEFT_SIDE ? align_right : align_left ); + m_textMeasureNumber.SetDiffuse( TICKCOUNT_COLOR ); + m_textMeasureNumber.SetGlow( RageColor(1,1,1,RageFastCos(RageTimer::GetTimeSinceStartFast()*2)/2+0.5f) ); + m_textMeasureNumber.SetText( ssprintf("%d", iTicks) ); + m_textMeasureNumber.SetXY( (TICKCOUNT_IS_LEFT_SIDE ? -xBase - xOffset : xBase + xOffset), fYPos ); m_textMeasureNumber.Draw(); } @@ -712,6 +757,19 @@ void NoteField::DrawPrimitives() DrawTimeSignatureText( fBeat, vTimeSignatureSegments[i].m_iNumerator, vTimeSignatureSegments[i].m_iDenominator ); } } + + // Tickcount text + const vector &tTickcountSegments = GAMESTATE->m_pCurSong->m_Timing.m_TickcountSegments; + for( unsigned i=0; i= iFirstRowToDraw && + tTickcountSegments[i].m_iStartRow <= iLastRowToDraw) + { + float fBeat = NoteRowToBeat(tTickcountSegments[i].m_iStartRow); + if( IS_ON_SCREEN(fBeat) ) + DrawTickcountText( fBeat, tTickcountSegments[i].m_iTicks ); + } + } // todo: add warp text -aj diff --git a/src/NoteField.h b/src/NoteField.h index 364bf769e6..eb4d3b0645 100644 --- a/src/NoteField.h +++ b/src/NoteField.h @@ -60,6 +60,7 @@ protected: void DrawBPMText( const float fBeat, const float fBPM ); void DrawFreezeText( const float fBeat, const float fBPM, const float bDelay ); void DrawTimeSignatureText( const float fBeat, int iNumerator, int iDenominator ); + void DrawTickcountText( const float fBeat, int iTicks ); void DrawAttackText( const float fBeat, const Attack &attack ); void DrawBGChangeText( const float fBeat, const RString sNewBGName ); float GetWidth() const; diff --git a/src/NoteTypes.cpp b/src/NoteTypes.cpp index 769dd4a03a..e16bcff81f 100644 --- a/src/NoteTypes.cpp +++ b/src/NoteTypes.cpp @@ -33,6 +33,11 @@ XToString( NoteType ); LuaXType( NoteType ) XToLocalizedString( NoteType ); +/** + * @brief Convert the NoteType to a beat representation. + * @param nt the NoteType to check. + * @return the proper beat. + */ float NoteTypeToBeat( NoteType nt ) { switch( nt ) @@ -51,10 +56,21 @@ float NoteTypeToBeat( NoteType nt ) } } -// FIXME: Remove hard-coded beat values and instead look at the time signature in the song. +/** + * @brief The number of beats per measure. + * + * FIXME: Look at the time signature of the song and use that instead at some point. */ static const int BEATS_PER_MEASURE = 4; +/** + * @brief The number of rows used in a measure. + * + * FIXME: Similar to the above, use time signatures and don't force hard-coded values. */ static const int ROWS_PER_MEASURE = ROWS_PER_BEAT * BEATS_PER_MEASURE; +/** + * @brief Retrieve the proper quantized NoteType for the note. + * @param row The row to check for. + * @return the quantized NoteType. */ NoteType GetNoteType( int row ) { if( row % (ROWS_PER_MEASURE/4) == 0) return NOTE_TYPE_4TH; @@ -72,7 +88,12 @@ NoteType BeatToNoteType( float fBeat ) { return GetNoteType( BeatToNoteRow(fBeat) ); } - +/** + * @brief Determine if the row has a particular type of quantized note. + * @param row the row in the Steps. + * @param t the quantized NoteType to check for. + * @return true if the NoteType is t, false otherwise. + */ bool IsNoteOfType( int row, NoteType t ) { return GetNoteType(row) == t; diff --git a/src/NoteTypes.h b/src/NoteTypes.h index 479135ba6c..7cb0fd2ba2 100644 --- a/src/NoteTypes.h +++ b/src/NoteTypes.h @@ -1,4 +1,4 @@ -/* NoteTypes - Types for holding tap notes and scores. */ +/** @brief NoteTypes - Types for holding tap notes and scores. */ #ifndef NOTE_TYPES_H #define NOTE_TYPES_H @@ -8,25 +8,30 @@ class XNode; +/** @brief The result of hitting (or missing) a tap note. */ struct TapNoteResult { + /** @brief Set up the TapNoteResult with default values. */ TapNoteResult() : tns(TNS_None), fTapNoteOffset(0.f), bHidden(false) { } - + /** @brief The TapNoteScore that was achieved by the player. */ TapNoteScore tns; - /* Offset, in seconds, for a tap grade. Negative numbers mean the note - * was hit early; positive numbers mean it was hit late. These values are - * only meaningful for graded taps (tns >= TNS_W5). */ + /** + * @brief Offset, in seconds, for a tap grade. + * + * Negative numbers mean the note was hit early; positive numbers mean + * it was hit late. These values are only meaningful for graded taps + * (tns >= TNS_W5). */ float fTapNoteOffset; - // If the whole row has been judged, all taps on the row will be set to hidden. + /** @brief If the whole row has been judged, all taps on the row will be set to hidden. */ bool bHidden; // XML XNode* CreateNode() const; void LoadFromNode( const XNode* pNode ); }; - +/** @brief The result of holding (or letting go of) a hold note. */ struct HoldNoteResult { HoldNoteResult() : hns(HNS_None), fLife(1.f), fOverlappedTime(0), iLastHeldRow(0), iCheckpointsHit(0), iCheckpointsMissed(0), bHeld(false), bActive(false) { } @@ -34,46 +39,58 @@ struct HoldNoteResult HoldNoteScore hns; - /* 1.0 means this HoldNote has full life. - * 0.0 means this HoldNote is dead + /** + * @brief the current life of the hold. + * + * 1.0 means this HoldNote has full life. + * + * 0.0 means this HoldNote is dead. + * * When this value hits 0.0 for the first time, m_HoldScore becomes HNS_LetGo. * If the life is > 0.0 when the HoldNote ends, then m_HoldScore becomes HNS_Held. */ float fLife; - /* The number of seconds the hold note has overlapped the current beat, or 0 - * if it doesn't overlap. */ + /** @brief The number of seconds the hold note has overlapped the current beat. + * + * This value is 0 if it doesn't overlap. */ float fOverlappedTime; - /* Last index where fLife was greater than 0. If the tap was missed, this + /** @brief Last index where fLife was greater than 0. If the tap was missed, this * will be the first index of the hold. */ int iLastHeldRow; - // If checkpoint holds are enabled, the number of checkpoints hit and missed. + /** @brief If checkpoint holds are enabled, the number of checkpoints hit. */ int iCheckpointsHit; + /** @brief If checkpoint holds are enabled, the number of checkpoints missed. */ int iCheckpointsMissed; - bool bHeld; // Was button held during last update? - bool bActive; // Is life > 0 && overlaps current beat + /** @brief Was the button held during the last update? */ + bool bHeld; + /** @brief Is there life in the hold and does it overlap the current beat? */ + bool bActive; // XML XNode* CreateNode() const; void LoadFromNode( const XNode* pNode ); }; +/** @brief The various properties of a tap note. */ struct TapNote { + /** @brief What is the TapNote's core type? */ enum Type { - empty, // no note here - tap, // step on this - hold_head, // graded like a tap - hold_tail, // in 2sand3s mode, holds are deleted and hold_tail is added - mine, // don't step! - lift, // up - attack, - autoKeysound, - fake, // not scored for or against + empty, /**< There is no note here. */ + tap, /**< The player simply steps on this. */ + hold_head, /**< This is graded like the Tap type, but should be held. */ + hold_tail, /**< In 2sand3s mode, holds are deleted and hold_tail is added. */ + mine, /**< In most modes, it is suggested to not step on these mines. */ + lift, /**< Lift your foot up when it crosses the target area. */ + attack, /**< Hitting this note causes an attack to take place. */ + autoKeysound, /**< A special sound is played when this note crosses the target area. */ + fake, /**< This arrow can't be scored for or against the player. */ }; + /** @brief The list of a TapNote's sub types. */ enum SubType { hold_head_hold, @@ -82,18 +99,24 @@ struct TapNote NUM_SubType, SubType_Invalid }; + /** @brief The different places a TapNote could come from. */ enum Source { - original, // part of the original NoteData - addition, // additional note added by a transform + original, /**< This note is part of the original NoteData. */ + addition, /**< This note is additional note added by a transform. */ }; - + /** @brief The core note type that is about to cross the target area. */ Type type; - SubType subType; // Only used if type is hold_head. + /** @brief The sub type of the note. This is only used if the type is hold_head. */ + SubType subType; + /** @brief The originating source of the TapNote. */ Source source; + /** @brief The result of hitting or missing the TapNote. */ TapNoteResult result; - PlayerNumber pn; // used in routine mode - bool bHopoPossible; // set just before gameplay begins + /** @brief The Player that is supposed to hit this note. This is mainly for Routine Mode. */ + PlayerNumber pn; + /** @brief Can this note be hammered on or pulled off? This is set before gameplay begins. */ + bool bHopoPossible; // used only if Type == attack: RString sAttackModifiers; @@ -173,30 +196,42 @@ extern TapNote TAP_ORIGINAL_FAKE; // 'F' extern TapNote TAP_ADDITION_TAP; extern TapNote TAP_ADDITION_MINE; -// TODO: Don't have a hard-coded track limit. +/** + * @brief The number of tracks allowed. + * + * TODO: Don't have a hard-coded track limit. + */ const int MAX_NOTE_TRACKS = 16; -/* This is a divisor for our "fixed-point" time/beat representation. It must be +/** + * @brief The number of rows per beat. + * + * This is a divisor for our "fixed-point" time/beat representation. It must be * evenly divisible by 2, 3, and 4, to exactly represent 8th, 12th and 16th notes. */ const int ROWS_PER_BEAT = 48; -// In the editor, enforce a reasonable limit on the number of notes. +/** + * @brief Enforce a maximum number of notes per measure in the step editor. + * + * TODO: See if there is a way to de-hard-code this number. + */ const int MAX_NOTES_PER_MEASURE = 50; - +/** @brief The max number of rows allowed for a Steps pattern. */ const int MAX_NOTE_ROW = (1<<30); +/** @brief The list of quantized note types allowed at present. */ enum NoteType { - NOTE_TYPE_4TH, // quarter note - NOTE_TYPE_8TH, // eighth note - NOTE_TYPE_12TH, // quarter note triplet - NOTE_TYPE_16TH, // sixteenth note - NOTE_TYPE_24TH, // eighth note triplet - NOTE_TYPE_32ND, // thirty-second note - NOTE_TYPE_48TH, // sixteenth note triplet - NOTE_TYPE_64TH, // sixty-fourth note - NOTE_TYPE_192ND,// sixty-fourth note triplet + NOTE_TYPE_4TH, /**< quarter note */ + NOTE_TYPE_8TH, /**< eighth note */ + NOTE_TYPE_12TH, /**< quarter note triplet */ + NOTE_TYPE_16TH, /**< sixteenth note */ + NOTE_TYPE_24TH, /**< eighth note triplet */ + NOTE_TYPE_32ND, /**< thirty-second note */ + NOTE_TYPE_48TH, /**< sixteenth note triplet */ + NOTE_TYPE_64TH, /**< sixty-fourth note */ + NOTE_TYPE_192ND,/**< sixty-fourth note triplet */ NUM_NoteType, NoteType_Invalid }; @@ -225,8 +260,10 @@ inline float NoteRowToBeat( int iRow ) { return iRow / (float)ROWS_PER_BEAT; } #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/NotesLoader.cpp b/src/NotesLoader.cpp index 6d12e2cb75..0d257c3c81 100644 --- a/src/NotesLoader.cpp +++ b/src/NotesLoader.cpp @@ -1,6 +1,7 @@ #include "global.h" #include "NotesLoader.h" #include "NotesLoaderSM.h" +#include "NotesLoaderSSC.h" #include "NotesLoaderDWI.h" #include "NotesLoaderBMS.h" #include "NotesLoaderPMS.h" @@ -30,14 +31,17 @@ bool NotesLoader::LoadFromDir( const RString &sPath, Song &out, set &Bl vector list; BlacklistedImages.clear(); - SMLoader::GetApplicableFiles( sPath, list ); + SSCLoader::GetApplicableFiles( sPath, list ); if( !list.empty() ) { - if( !SMLoader::LoadFromDir(sPath, out) ) + if( !SSCLoader::LoadFromDir( sPath, out ) ) return false; - SMLoader::TidyUpData( out, false ); + SSCLoader::TidyUpData( out, false ); return true; } + SMLoader::GetApplicableFiles( sPath, list ); + if (!list.empty() ) + return SMLoader::LoadFromDir( sPath, out ); DWILoader::GetApplicableFiles( sPath, list ); if( !list.empty() ) return DWILoader::LoadFromDir( sPath, out, BlacklistedImages ); diff --git a/src/NotesLoaderDWI.cpp b/src/NotesLoaderDWI.cpp index 69dab5eade..6b67d636f8 100644 --- a/src/NotesLoaderDWI.cpp +++ b/src/NotesLoaderDWI.cpp @@ -15,6 +15,7 @@ static std::map g_mapDanceNoteToNoteDataColumn; +/** @brief The different types of core DWI arrows and pads. */ enum { DANCE_NOTE_NONE = 0, @@ -32,6 +33,14 @@ enum DANCE_NOTE_PAD2_RIGHT }; +/** + * @brief Turn the individual character to the proper note. + * @param c The character in question. + * @param i The player. + * @param note1Out The first result based on the character. + * @param note2Out The second result based on the character. + * @param sPath the path to the file. + */ static void DWIcharToNote( char c, GameController i, int ¬e1Out, int ¬e2Out, const RString &sPath ) { switch( c ) @@ -79,6 +88,14 @@ static void DWIcharToNote( char c, GameController i, int ¬e1Out, int ¬e2Ou } } +/** + * @brief Determine the note column[s] to place notes. + * @param c The character in question. + * @param i The player. + * @param col1Out The first result based on the character. + * @param col2Out The second result based on the character. + * @param sPath the path to the file. + */ static void DWIcharToNoteCol( char c, GameController i, int &col1Out, int &col2Out, const RString &sPath ) { int note1, note2; @@ -95,11 +112,18 @@ static void DWIcharToNoteCol( char c, GameController i, int &col1Out, int &col2O col2Out = -1; } -/* Ack. DWI used to use <...> to indicate 1/192nd notes; at some +/** + * @brief Determine if the note in question is a 192nd note. + * + * DWI used to use <...> to indicate 1/192nd notes; at some * point, <...> was changed to indicate jumps, and `' was used for * 1/192nds. So, we have to do a check to figure out what it really * means. If it contains 0s, it's most likely 192nds; otherwise, - * it's most likely a jump. Search for a 0 before the next >: */ + * it's most likely a jump. Search for a 0 before the next >: + * @param sStepData the step data. + * @param pos the position of the step data. + * @return true if it's a 192nd note, false otherwise. + */ static bool Is192( const RString &sStepData, size_t pos ) { while( pos < sStepData.size() ) @@ -113,9 +137,20 @@ static bool Is192( const RString &sStepData, size_t pos ) return false; } - +/** @brief All DWI files use 4 beats per measure. */ const int BEATS_PER_MEASURE = 4; +/** + * @brief Look through the notes tag to extract the data. + * @param sMode the steps type. + * @param sDescription the difficulty. + * @param sNumFeet the meter. + * @param sStepData1 the guaranteed step data. + * @param sStepData2 used if sMode is double or couple. + * @param out the step data. + * @param sPath the path to the file. + * @return the success or failure of the operation. + */ static bool LoadFromDWITokens( RString sMode, RString sDescription, @@ -336,8 +371,16 @@ static bool LoadFromDWITokens( return true; } -/* This value can be in either "HH:MM:SS.sssss", "MM:SS.sssss", "SSS.sssss" - * or milliseconds. */ +/** + * @brief Turn the DWI style timestamp into a compatible time for our system. + * + * This value can be in either "HH:MM:SS.sssss", "MM:SS.sssss", "SSS.sssss" + * or milliseconds. + * @param arg1 Either hours, minutes, or seconds, depending on other args. + * @param arg2 Either minutes or seconds, depending on other args. + * @param arg3 Seconds if not empty. + * @return the proper timestamp. + */ static float ParseBrokenDWITimestamp( const RString &arg1, const RString &arg2, const RString &arg3 ) { if( arg1.empty() ) diff --git a/src/NotesLoaderDWI.h b/src/NotesLoaderDWI.h index 49099e0811..99f0f0a33a 100644 --- a/src/NotesLoaderDWI.h +++ b/src/NotesLoaderDWI.h @@ -1,4 +1,4 @@ -/* DWILoader - reads a Song from a .DWI file. */ +/** @brief DWILoader - reads a Song from a .DWI file. */ #ifndef NOTES_LOADER_DWI_H #define NOTES_LOADER_DWI_H @@ -7,16 +7,31 @@ class Song; +/** @brief The DWILoader handles parsing the .dwi file. */ namespace DWILoader { + /** + * @brief Retrieve the list of .dwi 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 ); + /** + * @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. + * @param BlacklistedImages a set of images that aren't used. + * @return its success or failure. + */ bool LoadFromDir( const RString &sPath, Song &out, set &BlacklistedImages ); } #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/NotesLoaderKSF.cpp b/src/NotesLoaderKSF.cpp index 8ac3ee78b2..22656c43a8 100644 --- a/src/NotesLoaderKSF.cpp +++ b/src/NotesLoaderKSF.cpp @@ -9,55 +9,6 @@ #include "Song.h" #include "Steps.h" -#if 0 -static void RemoveHoles( NoteData &out, const Song &song ) -{ - // Start at the second BPM segment; the first one is already aligned. - for( unsigned seg = 1; seg < song.m_Timing.m_BPMSegments.size(); ++seg ) - { -// const float FromBeat = song.m_Timing.m_BPMSegments[seg].m_fStartBeat; - const float FromBeat = song.m_Timing.m_BPMSegments[seg].m_fStartBeat * song.m_BPMSegments[seg].m_fBPM / song.m_BPMSegments[0].m_fBPM; - const int FromRow = (int) BeatToNoteRow(FromBeat); - const int ToRow = (int) BeatToNoteRow(song.m_Timing.m_BPMSegments[seg].m_fStartBeat); - - LOG->Trace("from %f (%i) to (%i)", FromBeat, FromRow, ToRow); -// const int ToRow = lrintf(FromRow * song.m_Timing.m_BPMSegments[0].m_fBPM / song.m_BPMSegments[seg].m_fBPM); -// const int Rows = out.GetLastRow() - FromRow + 1; -// int LastRow; -// if(seg+1 < song.m_Timing.m_BPMSegments().size()) -// LastRow = (int) NoteRowToBeat( song.m_Timing.m_BPMSegments[seg+1].m_fStartBeat ) - 1; -// else -// LastRow = out.GetLastRow(); - NoteData tmp; - tmp.SetNumTracks( out.GetNumTracks() ); - tmp.CopyRange( &out, FromRow, MAX_NOTE_ROW ); - out.ClearRange( FromRow, MAX_NOTE_ROW ); - out.CopyRange( &tmp, 0, MAX_NOTE_ROW, ToRow ); - } - -/* - for( t = 0; t < notedata.GetNumTracks(); ++t ) - { - const float CurBPM = song.GetBPMAtBeat( NoteRowToBeat(row) ); - song.m_Timing.m_BPMSegments.size() - for( int row = 0; row <= notedata.GetLastRow(); ++row ) - { - TapNote tn = notedata.GetTapNote(t, row); - if( tn == TAP_EMPTY ) - continue; - - const int RealRow = lrintf(row * OrigBPM / CurBPM); - if( RealRow == row ) - continue; - LOG->Trace("from %i to %i", row, RealRow); - notedata.SetTapNote( t, RealRow, tn ); - notedata.SetTapNote( t, row, TAP_EMPTY ); - } - } -*/ -} -#endif - static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, bool bKIUCompliant ) { LOG->Trace( "Steps::LoadFromKSFFile( '%s' )", sPath.c_str() ); @@ -79,9 +30,10 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, { const MsdFile::value_t &sParams = msd.GetValue( i ); RString sValueName = sParams[0]; + sValueName.MakeUpper(); // handle the data - if( 0==stricmp(sValueName,"TICKCOUNT") ) + if( sValueName=="TICKCOUNT" ) { iTickCount = atoi( sParams[1] ); if( iTickCount <= 0 ) @@ -90,18 +42,18 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, return false; } } - else if( 0==stricmp(sValueName,"STEP") ) + else if( sValueName=="STEP" ) { RString theSteps = sParams[1]; TrimLeft( theSteps ); split( theSteps, "\n", vNoteRows, true ); } - else if( 0==stricmp(sValueName,"DIFFICULTY") ) + else if( sValueName=="DIFFICULTY" ) { out.SetMeter( max(atoi(sParams[1]), 0) ); } // new cases from Aldo_MX's fork: - else if( 0==stricmp(sValueName,"PLAYER") ) + else if( sValueName=="PLAYER" ) { RString sPlayer = sParams[1]; sPlayer.MakeLower(); @@ -317,10 +269,6 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, const Song &song, fCurBeat = prevBeat + 1.0f / iTickCount; } - // We need to remove holes where the BPM increases. -// if( song.m_Timing.m_BPMSegments.size() > 1 ) -// RemoveHoles( notedata, song ); - out.SetNoteData( notedata ); out.TidyUpData(); @@ -402,67 +350,68 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant { const MsdFile::value_t &sParams = msd.GetValue(i); RString sValueName = sParams[0]; + sValueName.MakeUpper(); // handle the data - if( 0==stricmp(sValueName,"TITLE") ) + if( sValueName=="TITLE" ) LoadTags(sParams[1], out); - else if( 0==stricmp(sValueName,"BPM") ) + else if( sValueName=="BPM" ) { BPM1 = StringToFloat(sParams[1]); out.AddBPMSegment( BPMSegment(0, BPM1) ); } - else if( 0==stricmp(sValueName,"BPM2") ) + else if( sValueName=="BPM2" ) { bKIUCompliant = true; BPM2 = StringToFloat( sParams[1] ); } - else if( 0==stricmp(sValueName,"BPM3") ) + else if( sValueName=="BPM3" ) { bKIUCompliant = true; BPM3 = StringToFloat( sParams[1] ); } - else if( 0==stricmp(sValueName,"BUNKI") ) + else if( sValueName=="BUNKI" ) { bKIUCompliant = true; BPMPos2 = StringToFloat( sParams[1] ) / 100.0f; } - else if( 0==stricmp(sValueName,"BUNKI2") ) + else if( sValueName=="BUNKI2" ) { bKIUCompliant = true; BPMPos3 = StringToFloat( sParams[1] ) / 100.0f; } - else if( 0==stricmp(sValueName,"STARTTIME") ) + else if( sValueName=="STARTTIME" ) { SMGap1 = -StringToFloat( sParams[1] )/100; out.m_Timing.m_fBeat0OffsetInSeconds = SMGap1; } // This is currently required for more accurate KIU BPM changes. - else if( 0==stricmp(sValueName,"STARTTIME2") ) + else if( sValueName=="STARTTIME2" ) { bKIUCompliant = true; SMGap2 = -StringToFloat( sParams[1] )/100; } - else if ( 0==stricmp(sValueName,"STARTTIME3") ) + else if ( sValueName=="STARTTIME3" ) { // STARTTIME3 only ensures this is a KIU compliant simfile. bKIUCompliant = true; } - else if ( 0==stricmp(sValueName,"TICKCOUNT") ) + 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 = atoi( sParams[1] ); iTickCount = iTickCount > 0 ? iTickCount : 2; // again, Direct Move uses 4 as a default. - // add a time signature for those using the [Player] + // add a tickcount for those using the [Player] // CheckpointsUseTimeSignatures metric. -aj - TimeSignatureSegment seg; - seg.m_iStartRow = BeatToNoteRow(0.0f); - seg.m_iNumerator = iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount; - seg.m_iDenominator = 4; - out.m_Timing.AddTimeSignatureSegment( seg ); + // It's not with timesigs now -DaisuMaster + TickcountSegment tcs; + tcs.m_iStartRow = BeatToNoteRow(0.0f); + tcs.m_iTicks = iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount; + out.m_Timing.AddTickcountSegment( tcs ); } - else if ( 0==stricmp(sValueName,"STEP") ) + else if ( sValueName=="STEP" ) { /* STEP will always be the last header in a KSF file by design. Due to * the Direct Move syntax, it is best to get the rows of notes here. */ @@ -471,29 +420,29 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant split( theSteps, "\n", vNoteRows, true ); } - else if( 0==stricmp(sValueName,"DIFFICULTY") ) + else if( sValueName=="DIFFICULTY" ) { /* DIFFICULTY is handled only in LoadFromKSFFile. Ignore it here. */ continue; } // New cases noted in Aldo_MX's code: - else if( 0==stricmp(sValueName,"MUSICINTRO") || 0==stricmp(sValueName,"INTRO") ) + else if( sValueName=="MUSICINTRO" || sValueName=="INTRO" ) { out.m_fMusicSampleStartSeconds = HHMMSSToSeconds( sParams[1] ); } - else if( 0==stricmp(sValueName,"TITLEFILE") ) + else if( sValueName=="TITLEFILE" ) { out.m_sBackgroundFile = sParams[1]; } - else if( 0==stricmp(sValueName,"DISCFILE") ) + else if( sValueName=="DISCFILE" ) { out.m_sBannerFile = sParams[1]; } - else if( 0==stricmp(sValueName,"SONGFILE") ) + else if( sValueName=="SONGFILE" ) { out.m_sMusicFile = sParams[1]; } - //else if( 0==stricmp(sValueName,"INTROFILE") ) + //else if( sValueName=="INTROFILE" ) //{ // nothing to add... //} @@ -505,7 +454,7 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant } } - //intro length in piu mixes is normally 7 seconds + //intro length in piu mixes is generally 7 seconds out.m_fMusicSampleLengthSeconds = 7.0f; /* BPM Change checks are done here. If bKIUCompliant, it's short and sweet. @@ -563,12 +512,11 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant if (BeginsWith(NoteRowString, "|T")) { iTickCount = (int)numTemp; - TimeSignatureSegment seg; - seg.m_iStartRow = BeatToNoteRow(fCurBeat); - seg.m_iNumerator = iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount; - seg.m_iDenominator = 4; - out.m_Timing.AddTimeSignatureSegment( seg ); - + TickcountSegment tcs; + tcs.m_iStartRow = BeatToNoteRow(fCurBeat); + tcs.m_iTicks = iTickCount > ROWS_PER_BEAT ? ROWS_PER_BEAT : iTickCount; + out.m_Timing.AddTickcountSegment( tcs ); + continue; } else if (BeginsWith(NoteRowString, "|B")) @@ -581,16 +529,14 @@ static bool LoadGlobalData( const RString &sPath, Song &out, bool &bKIUCompliant else if (BeginsWith(NoteRowString, "|E")) { // Finally! the |E| tag is working as it should. I can die happy now -DaisuMaster - bool bDelay = true; float fCurDelay = 60 / out.m_Timing.GetBPMAtBeat(fCurBeat) * (float)numTemp / iTickCount; - fCurDelay += out.m_Timing.GetStopAtRow(BeatToNoteRow(fCurBeat), bDelay); + fCurDelay += out.m_Timing.GetStopAtRow(BeatToNoteRow(fCurBeat) ); out.m_Timing.SetStopAtBeat( fCurBeat, fCurDelay, true ); continue; } else if (BeginsWith(NoteRowString, "|D")) { - bool bDelay = true; - float fCurDelay = out.m_Timing.GetStopAtRow(BeatToNoteRow(fCurBeat), bDelay); + float fCurDelay = out.m_Timing.GetStopAtRow(BeatToNoteRow(fCurBeat) ); fCurDelay += (float)numTemp / 1000; out.m_Timing.SetStopAtBeat( fCurBeat, fCurDelay, true ); continue; diff --git a/src/NotesLoaderSM.cpp b/src/NotesLoaderSM.cpp index 73b168d931..5dbbe73bfe 100644 --- a/src/NotesLoaderSM.cpp +++ b/src/NotesLoaderSM.cpp @@ -14,7 +14,7 @@ const int MAX_EDIT_STEPS_SIZE_BYTES = 60*1024; // 60KB -static void LoadFromSMTokens( +void SMLoader::LoadFromSMTokens( RString sStepsType, RString sDescription, RString sDifficulty, @@ -94,6 +94,7 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out ) out.m_BPMSegments.clear(); out.m_StopSegments.clear(); out.m_WarpSegments.clear(); + out.m_vTimeSignatureSegments.clear(); vector arrayWarpsFromNegativeBPMs; //vector arrayWarpsFromNegativeStops; @@ -128,6 +129,9 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out ) const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); + // XXX: Remove Negatives Bug? + new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat); + new_seg.m_fStopSeconds = fFreezeSeconds; if(fFreezeSeconds > 0.0f) { @@ -168,7 +172,10 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out ) const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); - + // XXX: Remove Negatives Bug? + new_seg.m_iStartRow = BeatToNoteRow(fFreezeBeat); + new_seg.m_fStopSeconds = fFreezeSeconds; + // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); if(fFreezeSeconds > 0.0f) @@ -197,7 +204,11 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out ) const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); - + // XXX: Remove Negatives Bug? + BPMSegment new_seg; + new_seg.m_iStartRow = BeatToNoteRow(fBeat); + new_seg.SetBPM( fNewBPM ); + // convert negative BPMs into Warp segments if( fNewBPM < 0.0f ) { @@ -238,25 +249,25 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out ) ); */ - out.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + out.AddBPMSegment( new_seg ); continue; } else { // last BPM is a negative one? ugh. -aj (MAX_NOTE_ROW exists btw) - out.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + out.AddBPMSegment( new_seg ); } } if(fNewBPM > 0.0f) - out.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + out.AddBPMSegment( new_seg ); else { out.m_bHasNegativeBpms = true; // only add Negative BPMs in quirks mode -aj if( PREFSMAN->m_bQuirksMode ) - out.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + out.AddBPMSegment( new_seg ); else LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); } @@ -307,6 +318,46 @@ void SMLoader::LoadTimingFromSMFile( const MsdFile &msd, TimingData &out ) out.AddTimeSignatureSegment( seg ); } } + + else if( sValueName=="TICKCOUNTS" ) + { + vector arrayTickcountExpressions; + split( sParams[1], ",", 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 #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayTickcountExpressions[f].c_str() ); + continue; + } + + const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); + int iTicks = atoi( arrayTickcountValues[1] ); + // you're lazy, let SM do the work for you... -DaisuMaster + if( iTicks < 1) iTicks = 1; + if( iTicks > ROWS_PER_BEAT ) iTicks = ROWS_PER_BEAT; + + TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); + out.AddTickcountSegment( new_seg ); + + if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants + { + // LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks ); + //out.AddTickcountSegment( new_seg ); + } + else + { + //LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); + //LOG->UserLog( "Song file", "(UNKNOWN)", "Clamping tickcount value to %d at beat %f.", iTicks, fTickcountBeat); + //etc + } + } + } // warps (replacement for Negative BPM and Negative Stops) /* @@ -712,120 +763,10 @@ bool SMLoader::LoadFromSMFile( const RString &sPath, Song &out, bool bFromCache out.AddSteps( pNewNotes ); } /* - else if( sValueName=="OFFSET" ) - { - out.m_Timing.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); - } - else if( sValueName=="STOPS" || sValueName=="FREEZES" ) - { - vector arrayFreezeExpressions; - split( sParams[1], ",", arrayFreezeExpressions ); - - 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 #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); - continue; - } - - const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); - const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); - - StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); - - // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); - - out.m_Timing.AddStopSegment( new_seg ); - } - } - - else if( sValueName=="BPMS" ) - { - vector arrayBPMChangeExpressions; - split( sParams[1], ",", arrayBPMChangeExpressions ); - - 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 #%s value \"%s\" (must have exactly one '='), ignored.", - sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); - continue; - } - - const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); - const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); - - if( PREFSMAN->m_bQuirksMode ) - { - // in quirks mode, accept all BPMs, not just positives. - // xxx: make this work for decent simfiles only? -aj - out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - } - else - { - if( fNewBPM > 0.0f ) - out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); - else - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); - } - } - } - - else if( sValueName=="TIMESIGNATURES" ) - { - vector vs1; - split( sParams[1], ",", vs1 ); - - FOREACH_CONST( RString, vs1, s1 ) - { - vector vs2; - split( *s1, "=", vs2 ); - - if( vs2.size() < 3 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); - continue; - } - - const float fBeat = StringToFloat( vs2[0] ); - - TimeSignatureSegment seg; - seg.m_iStartRow = BeatToNoteRow(fBeat); - seg.m_iNumerator = atoi( vs2[1] ); - seg.m_iDenominator = atoi( vs2[2] ); - - if( fBeat < 0 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); - continue; - } - - if( seg.m_iNumerator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); - continue; - } - - if( seg.m_iDenominator < 1 ) - { - LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); - continue; - } - - out.m_Timing.AddTimeSignatureSegment( seg ); - } - } - */ - else if( sValueName=="OFFSET" || sValueName=="BPMS" || sValueName=="STOPS" || sValueName=="FREEZES" || sValueName=="DELAYS" || sValueName=="TIMESIGNATURES" || sValueName=="LEADTRACK" ) + * We used to check for timing data in this section. That has + * since been moved to a dedicated function. + */ + else if( sValueName=="OFFSET" || sValueName=="BPMS" || sValueName=="STOPS" || sValueName=="FREEZES" || sValueName=="DELAYS" || sValueName=="TIMESIGNATURES" || sValueName=="LEADTRACK" || sValueName=="TICKCOUNTS" ) ; else LOG->UserLog( "Song file", sPath, "has an unexpected value named \"%s\".", sValueName.c_str() ); diff --git a/src/NotesLoaderSM.h b/src/NotesLoaderSM.h index 433c0023e7..f8a7e78352 100644 --- a/src/NotesLoaderSM.h +++ b/src/NotesLoaderSM.h @@ -12,6 +12,9 @@ class TimingData; 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 ); diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp new file mode 100644 index 0000000000..b4be9ce8d2 --- /dev/null +++ b/src/NotesLoaderSSC.cpp @@ -0,0 +1,1188 @@ +#include "global.h" +#include "NotesLoaderSSC.h" +#include "BackgroundUtil.h" +#include "GameManager.h" +#include "MsdFile.h" // No JSON here. +#include "NoteTypes.h" +#include "NotesLoaderSM.h" // For loading SM style edits. +#include "RageFileManager.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "Song.h" +#include "SongManager.h" +#include "Steps.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. + * + * This code is right now copied from NotesLoaderSM. There may be a time + * when we add to this code, or perhaps just refactor it properly. + * @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 ) +{ + vector aBGChangeValues; + split( sBGChangeExpression, "=", aBGChangeValues, false ); + + aBGChangeValues.resize( min((int)aBGChangeValues.size(),11) ); + + switch( aBGChangeValues.size() ) + { + case 11: + change.m_def.m_sColor2 = aBGChangeValues[10]; + change.m_def.m_sColor2.Replace( '^', ',' ); + change.m_def.m_sColor2 = RageColor::NormalizeColorString( change.m_def.m_sColor2 ); + // fall through + case 10: + change.m_def.m_sColor1 = aBGChangeValues[9]; + change.m_def.m_sColor1.Replace( '^', ',' ); + change.m_def.m_sColor1 = RageColor::NormalizeColorString( change.m_def.m_sColor1 ); + // fall through + case 9: + change.m_sTransition = aBGChangeValues[8]; + // fall through + case 8: + change.m_def.m_sFile2 = aBGChangeValues[7]; + // fall through + case 7: + change.m_def.m_sEffect = aBGChangeValues[6]; + // fall through + case 6: + // param 7 overrides this. + // Backward compatibility: + if( change.m_def.m_sEffect.empty() ) + { + bool bLoop = atoi( aBGChangeValues[5] ) != 0; + if( !bLoop ) + change.m_def.m_sEffect = SBE_StretchNoLoop; + } + // fall through + case 5: + // param 7 overrides this. + // Backward compatibility: + if( change.m_def.m_sEffect.empty() ) + { + bool bRewindMovie = atoi( aBGChangeValues[4] ) != 0; + if( bRewindMovie ) + change.m_def.m_sEffect = SBE_StretchRewind; + } + // fall through + case 4: + // param 9 overrides this. + // Backward compatibility: + if( change.m_sTransition.empty() ) + change.m_sTransition = (atoi( aBGChangeValues[3] ) != 0) ? "CrossFade" : ""; + // fall through + case 3: + change.m_fRate = StringToFloat( aBGChangeValues[2] ); + // fall through + case 2: + change.m_def.m_sFile1 = aBGChangeValues[1]; + // fall through + case 1: + change.m_fStartBeat = StringToFloat( aBGChangeValues[0] ); + // fall through + } + + return aBGChangeValues.size() >= 2; +} + +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 ); +} + +bool SSCLoader::LoadFromSSCFile( const RString &sPath, Song &out, bool bFromCache ) +{ + LOG->Trace( "Song::LoadFromSSCFile(%s)", sPath.c_str() ); + + MsdFile msd; + if( !msd.ReadFile( sPath, true ) ) + { + LOG->UserLog( "Song file", sPath, "couldn't be opened: %s", msd.GetError().c_str() ); + return false; + } + + out.m_Timing.m_sFile = sPath; // songs still have their fallback timing. + + int state = GETTING_SONG_INFO; + const unsigned values = msd.GetNumValues(); + Steps* pNewNotes; + + for( unsigned i = 0; i < values; i++ ) + { + const MsdFile::value_t &sParams = msd.GetValue(i); + RString sValueName = sParams[0]; + sValueName.MakeUpper(); + + switch (state) + { + case GETTING_SONG_INFO: + { + if( sValueName=="VERSION" ) + { + out.m_fVersion = StringToFloat( sParams[1] ); + } + + else if( sValueName=="TITLE" ) + { + out.m_sMainTitle = sParams[1]; + } + + else if( sValueName=="SUBTITLE" ) + { + out.m_sSubTitle = sParams[1]; + } + + else if( sValueName=="ARTIST" ) + { + out.m_sArtist = sParams[1]; + } + + else if( sValueName=="TITLETRANSLIT" ) + { + out.m_sMainTitleTranslit = sParams[1]; + } + + else if( sValueName=="SUBTITLETRANSLIT" ) + { + out.m_sSubTitleTranslit = sParams[1]; + } + + else if( sValueName=="ARTISTTRANSLIT" ) + { + out.m_sArtistTranslit = sParams[1]; + } + + else if( sValueName=="GENRE" ) + { + out.m_sGenre = sParams[1]; + } + + else if( sValueName=="CREDIT" ) + { + out.m_sCredit = sParams[1]; + } + + else if( sValueName=="BANNER" ) + { + out.m_sBannerFile = sParams[1]; + } + + else if( sValueName=="BACKGROUND" ) + { + out.m_sBackgroundFile = sParams[1]; + } + + else if( sValueName=="LYRICSPATH" ) + { + out.m_sLyricsFile = sParams[1]; + } + + else if( sValueName=="CDTITLE" ) + { + out.m_sCDTitleFile = sParams[1]; + } + + else if( sValueName=="MUSIC" ) + { + out.m_sMusicFile = sParams[1]; + } + + else if( sValueName=="INSTRUMENTTRACK" ) + { + vector vs1; + split( sParams[1], ",", vs1 ); + FOREACH_CONST( RString, vs1, s ) + { + vector vs2; + split( *s, "=", vs2 ); + if( vs2.size() >= 2 ) + { + InstrumentTrack it = StringToInstrumentTrack( vs2[0] ); + if( it != InstrumentTrack_Invalid ) + out.m_sInstrumentTrackFile[it] = vs2[1]; + } + } + } + + else if( sValueName=="MUSICLENGTH" ) + { + if( !bFromCache ) + continue; + out.m_fMusicLengthSeconds = StringToFloat( sParams[1] ); + } + + else if( sValueName=="LASTBEATHINT" ) + { + out.m_fSpecifiedLastBeat = StringToFloat( sParams[1] ); + } + + else if( sValueName=="MUSICBYTES" ) + { + ; // ignore + } + + else if( sValueName=="SAMPLESTART" ) + { + out.m_fMusicSampleStartSeconds = HHMMSSToSeconds( sParams[1] ); + } + + else if( sValueName=="SAMPLELENGTH" ) + { + out.m_fMusicSampleLengthSeconds = HHMMSSToSeconds( sParams[1] ); + } + + else if( sValueName=="DISPLAYBPM" ) + { + // #DISPLAYBPM:[xxx][xxx:xxx]|[*]; + if( sParams[1] == "*" ) + out.m_DisplayBPMType = Song::DISPLAY_RANDOM; + else + { + out.m_DisplayBPMType = Song::DISPLAY_SPECIFIED; + out.m_fSpecifiedBPMMin = StringToFloat( sParams[1] ); + if( sParams[2].empty() ) + out.m_fSpecifiedBPMMax = out.m_fSpecifiedBPMMin; + else + out.m_fSpecifiedBPMMax = StringToFloat( sParams[2] ); + } + } + + else if( sValueName=="SELECTABLE" ) + { + if(!stricmp(sParams[1],"YES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if(!stricmp(sParams[1],"NO")) + out.m_SelectionDisplay = out.SHOW_NEVER; + // ROULETTE from 3.9 is no longer in use. + else if(!stricmp(sParams[1],"ROULETTE")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + /* The following two cases are just fixes to make sure simfiles that + * used 3.9+ features are not excluded here */ + else if(!stricmp(sParams[1],"ES") || !stricmp(sParams[1],"OMES")) + out.m_SelectionDisplay = out.SHOW_ALWAYS; + else if( atoi(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() ); + } + + else if( sValueName.Left(strlen("BGCHANGES"))=="BGCHANGES" || sValueName=="ANIMATIONS" ) + { + BackgroundLayer iLayer = BACKGROUND_LAYER_1; + if( sscanf(sValueName, "BGCHANGES%d", &*ConvertValue(&iLayer)) == 1 ) + enum_add(iLayer, -1); // #BGCHANGES2 = BACKGROUND_LAYER_2 + + bool bValid = iLayer>=0 && iLayerUserLog( "Song file", sPath, "has a #BGCHANGES tag \"%s\" that is out of range.", sValueName.c_str() ); + } + else + { + vector aBGChangeExpressions; + split( sParams[1], ",", aBGChangeExpressions ); + + for( unsigned b=0; b aFGChangeExpressions; + split( sParams[1], ",", aFGChangeExpressions ); + + for( unsigned b=0; b sBits; + split( sParams[j], "=", sBits, false ); + + // Need an identifer and a value for this to work + if( sBits.size() < 2 ) + continue; + + TrimLeft( sBits[0] ); + TrimRight( sBits[0] ); + + if( !sBits[0].CompareNoCase("TIME") ) + attack.fStartSecond = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("LEN") ) + attack.fSecsRemaining = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("END") ) + end = strtof( sBits[1], NULL ); + else if( !sBits[0].CompareNoCase("MODS") ) + { + attack.sModifiers = sBits[1]; + + if( end != -9999 ) + { + attack.fSecsRemaining = end - attack.fStartSecond; + end = -9999; + } + + if( attack.fSecsRemaining < 0.0f ) + attack.fSecsRemaining = 0.0f; + + out.m_Attacks.push_back( attack ); + } + } + } + + else if( sValueName=="OFFSET" ) + { + out.m_Timing.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); + } + /* Below are the song based timings that should only be used + * if the steps do not have their own timing. */ + else if( sValueName=="STOPS" ) + { + vector arrayFreezeExpressions; + split( sParams[1], ",", arrayFreezeExpressions ); + + 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 #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); + + if(fFreezeSeconds > 0.0f) + { + // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + out.m_Timing.AddStopSegment( new_seg ); + } + else + { + // negative stops (hi JS!) -aj + if( PREFSMAN->m_bQuirksMode ) + { + // LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + out.m_Timing.AddStopSegment( new_seg ); + } + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } + } + } + else if( sValueName=="DELAYS" ) + { + vector arrayDelayExpressions; + split( sParams[1], ",", 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 #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayDelayExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayDelayValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); + + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); + + // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + + if(fFreezeSeconds > 0.0f) + out.m_Timing.AddStopSegment( new_seg ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } + } + + else if( sValueName=="BPMS" ) + { + vector arrayBPMChangeExpressions; + split( sParams[1], ",", arrayBPMChangeExpressions ); + + 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 #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); + continue; + } + + const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); + const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); + + if(fNewBPM > 0.0f) + out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + else + { + out.m_Timing.m_bHasNegativeBpms = true; + // only add Negative BPMs in quirks mode -aj + if( PREFSMAN->m_bQuirksMode ) + out.m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); + } + } + } + + else if( sValueName=="TIMESIGNATURES" ) + { + vector vs1; + split( sParams[1], ",", vs1 ); + + FOREACH_CONST( RString, vs1, s1 ) + { + vector vs2; + split( *s1, "=", vs2 ); + + if( vs2.size() < 3 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); + continue; + } + + const float fBeat = StringToFloat( vs2[0] ); + + TimeSignatureSegment seg; + seg.m_iStartRow = BeatToNoteRow(fBeat); + seg.m_iNumerator = atoi( vs2[1] ); + seg.m_iDenominator = atoi( vs2[2] ); + + if( fBeat < 0 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); + continue; + } + + if( seg.m_iNumerator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); + continue; + } + + if( seg.m_iDenominator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); + continue; + } + + out.m_Timing.AddTimeSignatureSegment( seg ); + } + } + + else if( sValueName=="TICKCOUNTS" ) + { + vector arrayTickcountExpressions; + split( sParams[1], ",", 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 #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayTickcountExpressions[f].c_str() ); + continue; + } + + const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); + const int iTicks = atoi( arrayTickcountValues[1] ); + TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); + + if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants + { + // LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks ); + out.m_Timing.AddTickcountSegment( new_seg ); + } + else + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); + } + } + } + + else if( sValueName=="COMBOS" ) + {/* + vector arrayComboExpressions; + split( sParams[1], ",", arrayComboExpressions ); + + for( unsigned f=0; f arrayComboValues; + split( arrayComboExpressions[f], "=", arrayComboValues ); + if( arrayComboValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayComboExpressions[f].c_str() ); + continue; + } + const float fComboBeat = StringToFloat( arrayComboValues[0] ); + const int iCombos = atoi( arrayComboValues[1] ); + ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); + out.m_Timing.AddComboSegment( new_seg ); + } + */ + } + + /* The following are cache tags. Never fill their values + * directly: only from the cached version. */ + else if( sValueName=="FIRSTBEAT" ) + { + 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 = atoi( sParams[1] ) != 0; + } + + else if( sValueName=="HASBANNER" ) + { + if( bFromCache ) + out.m_bHasBanner = atoi( sParams[1] ) != 0; + } + + // This tag will get us to the next section. + else if( sValueName=="NOTEDATA" ) + { + state = GETTING_STEP_INFO; + pNewNotes = new Steps; + } + break; + } + case GETTING_STEP_INFO: + { + if( sValueName=="STEPSTYPE" ) + { + pNewNotes->m_StepsType = GAMEMAN->StringToStepsType( sParams[1] ); + } + + else if( sValueName=="DESCRIPTION" ) + { + pNewNotes->SetDescription( sParams[1] ); + } + + else if( sValueName=="DIFFICULTY" ) + { + pNewNotes->SetDifficulty( DwiCompatibleStringToDifficulty( sParams[1] ) ); + } + + else if( sValueName=="METER" ) + { + pNewNotes->SetMeter( atoi( sParams[1] ) ); + } + + else if( sValueName=="RADARVALUES" ) + { + vector saValues; + split( sParams[1], ",", saValues, true ); + if( saValues.size() == NUM_RadarCategory * NUM_PLAYERS ) + { + RadarValues v[NUM_PLAYERS]; + FOREACH_PlayerNumber( pn ) + FOREACH_ENUM( RadarCategory, rc ) + v[pn][rc] = StringToFloat( saValues[pn*NUM_RadarCategory + rc] ); + pNewNotes->SetCachedRadarValues( v ); + } + } + + else if( sValueName=="CREDIT" ) + { + pNewNotes->SetCredit( sParams[1] ); + } + + else if( sValueName=="NOTES" ) + { + state = GETTING_SONG_INFO; + //pNewNotes->m_Timing = out.m_Timing; + pNewNotes->SetSMNoteData( sParams[1] ); + pNewNotes->TidyUpData(); + out.AddSteps( pNewNotes ); + } + + else if( sValueName=="BPMS" ) + { + /* + state = GETTING_STEP_TIMING_INFO; + vector arrayBPMChangeExpressions; + split( sParams[1], ",", arrayBPMChangeExpressions ); + + 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 #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayBPMChangeExpressions[b].c_str() ); + continue; + } + + const float fBeat = StringToFloat( arrayBPMChangeValues[0] ); + const float fNewBPM = StringToFloat( arrayBPMChangeValues[1] ); + + if(fNewBPM > 0.0f) + pNewNotes->m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + else + { + pNewNotes->m_Timing.m_bHasNegativeBpms = true; + // only add Negative BPMs in quirks mode -aj + if( PREFSMAN->m_bQuirksMode ) + pNewNotes->m_Timing.AddBPMSegment( BPMSegment(BeatToNoteRow(fBeat), fNewBPM) ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid BPM change at beat %f, BPM %f.", fBeat, fNewBPM ); + } + } + */ + } + break; + } + case GETTING_STEP_TIMING_INFO: + { + if( sValueName=="STOPS" ) + { + /* + vector arrayFreezeExpressions; + split( sParams[1], ",", arrayFreezeExpressions ); + + 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 #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayFreezeExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayFreezeValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayFreezeValues[1] ); + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds ); + + if(fFreezeSeconds > 0.0f) + { + // LOG->Trace( "Adding a freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + pNewNotes->m_Timing.AddStopSegment( new_seg ); + } + else + { + // negative stops (hi JS!) -aj + if( PREFSMAN->m_bQuirksMode ) + { + // LOG->Trace( "Adding a negative freeze segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + pNewNotes->m_Timing.AddStopSegment( new_seg ); + } + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid stop at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } + } + */ + } + else if( sValueName=="DELAYS" ) + { + /* + vector arrayDelayExpressions; + split( sParams[1], ",", 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 #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayDelayExpressions[f].c_str() ); + continue; + } + + const float fFreezeBeat = StringToFloat( arrayDelayValues[0] ); + const float fFreezeSeconds = StringToFloat( arrayDelayValues[1] ); + + StopSegment new_seg( BeatToNoteRow(fFreezeBeat), fFreezeSeconds, true ); + + // LOG->Trace( "Adding a delay segment: beat: %f, seconds = %f", new_seg.m_fStartBeat, new_seg.m_fStopSeconds ); + + if(fFreezeSeconds > 0.0f) + pNewNotes->m_Timing.AddStopSegment( new_seg ); + else + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid delay at beat %f, length %f.", fFreezeBeat, fFreezeSeconds ); + } + */ + } + else if( sValueName=="TIMESIGNATURES" ) + { + /* + vector vs1; + split( sParams[1], ",", vs1 ); + + FOREACH_CONST( RString, vs1, s1 ) + { + vector vs2; + split( *s1, "=", vs2 ); + + if( vs2.size() < 3 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with %i values.", (int)vs2.size() ); + continue; + } + + const float fBeat = StringToFloat( vs2[0] ); + + TimeSignatureSegment seg; + seg.m_iStartRow = BeatToNoteRow(fBeat); + seg.m_iNumerator = atoi( vs2[1] ); + seg.m_iDenominator = atoi( vs2[2] ); + + if( fBeat < 0 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f.", fBeat ); + continue; + } + + if( seg.m_iNumerator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iNumerator %i.", fBeat, seg.m_iNumerator ); + continue; + } + + if( seg.m_iDenominator < 1 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid time signature change with beat %f, iDenominator %i.", fBeat, seg.m_iDenominator ); + continue; + } + + pNewNotes->m_Timing.AddTimeSignatureSegment( seg ); + } + */ + } + + else if( sValueName=="TICKCOUNTS" ) + { + /* + vector arrayTickcountExpressions; + split( sParams[1], ",", 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 #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayTickcountExpressions[f].c_str() ); + continue; + } + + const float fTickcountBeat = StringToFloat( arrayTickcountValues[0] ); + const int iTicks = atoi( arrayTickcountValues[1] ); + TickcountSegment new_seg( BeatToNoteRow(fTickcountBeat), iTicks ); + + if(iTicks >= 1 && iTicks <= ROWS_PER_BEAT ) // Constants + { + // LOG->Trace( "Adding a tickcount segment: beat: %f, ticks = %d", fTickcountBeat, iTicks ); + pNewNotes->m_Timing.AddTickcountSegment( new_seg ); + } + else + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid tickcount at beat %f, ticks %d.", fTickcountBeat, iTicks ); + } + } + */ + } + else if( sValueName=="COMBOS" ) + { + /* + vector arrayComboExpressions; + split( sParams[1], ",", arrayComboExpressions ); + + for( unsigned f=0; f arrayComboValues; + split( arrayComboExpressions[f], "=", arrayComboValues ); + if( arrayComboValues.size() != 2 ) + { + LOG->UserLog( "Song file", "(UNKNOWN)", "has an invalid #%s value \"%s\" (must have exactly one '='), ignored.", + sValueName.c_str(), arrayComboExpressions[f].c_str() ); + continue; + } + const float fComboBeat = StringToFloat( arrayComboValues[0] ); + const int iCombos = atoi( arrayComboValues[1] ); + ComboSegment new_seg( BeatToNoteRow( fComboBeat ), iCombos ); + pNewNotes->m_Timing.AddComboSegment( new_seg ); + } + */ + } + else if( sValueName=="OFFSET" ) + {/* + pNewNotes->m_Timing.m_fBeat0OffsetInSeconds = StringToFloat( sParams[1] ); + */ + } + + else if( sValueName=="NOTES" ) + { + state = GETTING_SONG_INFO; + // pNewNotes->m_Timing.m_fBeat0OffsetInSeconds = out.m_Timing.m_fBeat0OffsetInSeconds; + pNewNotes->SetSMNoteData( sParams[1] ); + pNewNotes->TidyUpData(); + out.AddSteps( pNewNotes ); + } + break; + } + } + } + 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() ); + + 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 SSCLoader::LoadEditFromMsd( const MsdFile &msd, const RString &sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ) +{ + Song* pSong = NULL; + Steps* pNewNotes; + bool bSSCFormat = false; + + 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=="NOTEDATA" ) + { + pNewNotes = new Steps; + bSSCFormat = true; + } + if( sValueName=="STEPSTYPE" ) + { + pNewNotes->m_StepsType = GAMEMAN->StringToStepsType( sParams[1] ); + bSSCFormat = true; + } + + else if( sValueName=="DESCRIPTION" ) + { + pNewNotes->SetDescription( sParams[1] ); + bSSCFormat = true; + } + + else if( sValueName=="DIFFICULTY" ) + { + pNewNotes->SetDifficulty( DwiCompatibleStringToDifficulty( sParams[1] ) ); + bSSCFormat = true; + } + + else if( sValueName=="METER" ) + { + pNewNotes->SetMeter( atoi( sParams[1] ) ); + bSSCFormat = true; + } + + else if( sValueName=="RADARVALUES" ) + { + vector saValues; + split( sParams[1], ",", saValues, true ); + if( saValues.size() == NUM_RadarCategory * NUM_PLAYERS ) + { + RadarValues v[NUM_PLAYERS]; + FOREACH_PlayerNumber( pn ) + FOREACH_ENUM( RadarCategory, rc ) + v[pn][rc] = StringToFloat( saValues[pn*NUM_RadarCategory + rc] ); + pNewNotes->SetCachedRadarValues( v ); + } + bSSCFormat = true; + } + + else if( sValueName=="CREDIT" ) + { + pNewNotes->SetCredit( sParams[1] ); + bSSCFormat = true; + } + + // TimingData for Steps isn't set yet, but still prepare for it. + else if( sValueName=="BPMS" ) + { + bSSCFormat = true; + } + else if( sValueName=="STOPS" ) + { + bSSCFormat = true; + } + else if( sValueName=="DELAYS" ) + { + bSSCFormat = true; + } + else if( sValueName=="TIMESIGNATURES" ) + { + bSSCFormat = true; + } + else if( sValueName=="TICKCOUNTS" ) + { + bSSCFormat = true; + } + else if( sValueName=="COMBOS" ) + { + bSSCFormat = true; + } + + 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 ( !bSSCFormat && 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; + + if( bSSCFormat ) + { + pNewNotes->SetSMNoteData( sParams[1] ); + pNewNotes->TidyUpData(); + pSong->AddSteps( pNewNotes ); + } + else + { + pNewNotes = new Steps; + SMLoader::LoadFromSMTokens( + 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() ); + } + } + + return true; +} + +void SSCLoader::TidyUpData( Song &song, bool bFromCache ) +{ + /* + * Hack: if the song has any changes at all (so it won't use a random BGA) + * and doesn't end with "-nosongbg-", add a song background BGC. Remove + * "-nosongbg-" if it exists. + * + * This way, songs that were created earlier, when we added the song BG + * at the end by default, will still behave as expected; all new songs will + * have to add an explicit song BG tag if they want it. This is really a + * formatting hack only; nothing outside of SMLoader ever sees "-nosongbg-". + */ + vector &bg = song.GetBackgroundChanges(BACKGROUND_LAYER_1); + if( !bg.empty() ) + { + /* BGChanges have been sorted. On the odd chance that a BGChange exists + * with a very high beat, search the whole list. */ + bool bHasNoSongBgTag = false; + + for( unsigned i = 0; !bHasNoSongBgTag && i < bg.size(); ++i ) + { + if( !bg[i].m_def.m_sFile1.CompareNoCase(NO_SONG_BG_FILE) ) + { + bg.erase( bg.begin()+i ); + bHasNoSongBgTag = true; + } + } + + // If there's no -nosongbg- tag, add the song BG. + if( !bHasNoSongBgTag ) do + { + /* If we're loading cache, -nosongbg- should always be in there. We + * must not call IsAFile(song.GetBackgroundPath()) when loading cache. */ + if( bFromCache ) + break; + + /* 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 ) + break; + + // If the last BGA is already the song BGA, don't add a duplicate. + if( !bg.empty() && !bg.back().m_def.m_sFile1.CompareNoCase(song.m_sBackgroundFile) ) + break; + + if( !IsAFile( song.GetBackgroundPath() ) ) + break; + + bg.push_back( BackgroundChange(song.m_fLastBeat,song.m_sBackgroundFile) ); + } while(0); + } +} + +/* + * (c) 2011 Jason Felds + * 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/NotesLoaderSSC.h b/src/NotesLoaderSSC.h new file mode 100644 index 0000000000..675a91a2e8 --- /dev/null +++ b/src/NotesLoaderSSC.h @@ -0,0 +1,101 @@ +/** @brief SSCLoader - Reads a Song and its Steps from a .SSC file. */ +#ifndef NotesLoaderSSC_H +#define NotesLoaderSSC_H + +#include "GameConstantsAndTypes.h" + +class MsdFile; +class Song; +class Steps; +class TimingData; + +/** + * @brief The various states while parsing a .ssc file. + */ +enum SSCLoadingStates +{ + GETTING_SONG_INFO, /**< Retrieving song information. */ + GETTING_STEP_INFO, /**< Retrieving step information. */ + GETTING_STEP_TIMING_INFO, /**< Retrieving a step's individual timing information. */ + GETTING_NOTE_INFO, /**< Retrieving the specific notes. This state may be deprecated. */ + NUM_SSCLoadingStates /**< The number of states used. */ +}; + +/** + * @brief The SSCLoader handles all of the parsing needed for .ssc files. + */ +namespace SSCLoader +{ + /** + * @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 ); + /** + * @brief Attempt to load the specified ssc 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. + */ + 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 ); + /** + * @brief Attempt to load an edit from the hard drive. + * @param sEditFilePath a path on the hard drive to check. + * @param slot the Profile of the user with the edit. + * @param bAddStepsToSong a flag to determine if we add the edit steps to the song file. + * @return its success or failure. + */ + bool LoadEditFromFile( RString sEditFilePath, ProfileSlot slot, bool bAddStepsToSong ); + /** + * @brief Attempt to parse the edit file in question. + * @param msd the edit file itself. + * @param sEditFilePath a const reference to a path on the hard drive to check. + * @param slot the Profile of the user with the edit. + * @param bAddStepsToSong a flag to determine if we add the edit steps to the song file. + * @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 ); +} +#endif +/** + * @file + * @author Jason Felds (c) 2011 + * + * @section LICENSE + * 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/NotesWriterSM.cpp b/src/NotesWriterSM.cpp index 296d11dff0..285fa2311b 100644 --- a/src/NotesWriterSM.cpp +++ b/src/NotesWriterSM.cpp @@ -18,8 +18,8 @@ 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. + // 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, @@ -103,7 +103,7 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) { const BPMSegment &bs = out.m_Timing.m_BPMSegments[i]; - f.Write( ssprintf( "%.6f=%.6f", NoteRowToBeat(bs.m_iStartRow), bs.GetBPM() ) ); + f.PutLine( ssprintf( "%.6f=%.6f", NoteRowToBeat(bs.m_iStartRow), bs.GetBPM() ) ); if( i != out.m_Timing.m_BPMSegments.size()-1 ) f.Write( "," ); } @@ -162,6 +162,18 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) } f.PutLine( ";" ); + ASSERT( !out.m_Timing.m_TickcountSegments.empty() ); + f.Write( "#TICKCOUNTS:" ); + for( unsigned i=0; i &lines ) return join( "\r\n", lines.begin()+j, lines.end() ); } -static RString GetSMNotesTag( const Song &song, const Steps &in, bool bSavingCache ) +static RString GetSMNotesTag( const Song &song, const Steps &in ) { vector lines; @@ -259,15 +271,11 @@ static RString GetSMNotesTag( const Song &song, const Steps &in, bool bSavingCac return JoinLineList( lines ); } -bool NotesWriterSM::Write( RString sPath, const Song &out, const vector& vpStepsToSave, bool bSavingCache ) +bool NotesWriterSM::Write( RString sPath, const Song &out ) { int flags = RageFile::WRITE; - /* If we're not saving cache, we're saving real data, so enable SLOW_FLUSH - * to prevent data loss. If we're saving cache, this will slow things down - * too much. */ - if( !bSavingCache ) - flags |= RageFile::SLOW_FLUSH; + flags |= RageFile::SLOW_FLUSH; RageFile f; if( !f.Open( sPath, flags ) ) @@ -277,23 +285,13 @@ bool NotesWriterSM::Write( RString sPath, const Song &out, const vector& } WriteGlobalTags( f, out ); - 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( "#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( "// end cache tags" ) ); - } // Save specified Steps to this file + const vector& vpStepsToSave = out.GetAllSteps(); FOREACH_CONST( Steps*, vpStepsToSave, s ) { const Steps* pSteps = *s; - RString sTag = GetSMNotesTag( out, *pSteps, bSavingCache ); + RString sTag = GetSMNotesTag( out, *pSteps ); f.PutLine( sTag ); } if( f.Flush() == -1 ) @@ -313,7 +311,7 @@ void NotesWriterSM::GetEditFileContents( const Song *pSong, const Steps *pSteps, if( asParts.size() ) sDir = join( "/", asParts.begin()+1, asParts.end() ); sOut += ssprintf( "#SONG:%s;\r\n", sDir.c_str() ); - sOut += GetSMNotesTag( *pSong, *pSteps, false ); + sOut += GetSMNotesTag( *pSong, *pSteps ); } RString NotesWriterSM::GetEditFileName( const Song *pSong, const Steps *pSteps ) diff --git a/src/NotesWriterSM.h b/src/NotesWriterSM.h index 046bedc9b5..7427248425 100644 --- a/src/NotesWriterSM.h +++ b/src/NotesWriterSM.h @@ -7,7 +7,7 @@ class Song; class Steps; namespace NotesWriterSM { - bool Write( RString sPath, const Song &out, const vector& vpStepsToSave, bool bSavingCache ); + bool Write( RString sPath, const Song &out ); void GetEditFileContents( const Song *pSong, const Steps *pSteps, RString &sOut ); RString GetEditFileName( const Song *pSong, const Steps *pSteps ); bool WriteEditFileToMachine( const Song *pSong, Steps *pSteps, RString &sErrorOut ); diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp new file mode 100644 index 0000000000..5c7e8f3a68 --- /dev/null +++ b/src/NotesWriterSSC.cpp @@ -0,0 +1,504 @@ +#include "global.h" +#include +#include +#include "NotesWriterSSC.h" +#include "BackgroundUtil.h" +#include "Foreach.h" +#include "GameManager.h" +#include "LocalizedString.h" +#include "NoteTypes.h" +#include "Profile.h" +#include "ProfileManager.h" +#include "RageFile.h" +#include "RageFileManager.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "Song.h" +#include "Steps.h" + +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; +} + +static void WriteGlobalTags( RageFile &f, const Song &out ) +{ + f.PutLine( ssprintf( "#VERSION:%.2f;", out.m_fVersion ) ); + 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() ) ); + f.PutLine( ssprintf( "#TITLETRANSLIT:%s;", SmEscape(out.m_sMainTitleTranslit).c_str() ) ); + f.PutLine( ssprintf( "#SUBTITLETRANSLIT:%s;", SmEscape(out.m_sSubTitleTranslit).c_str() ) ); + f.PutLine( ssprintf( "#ARTISTTRANSLIT:%s;", SmEscape(out.m_sArtistTranslit).c_str() ) ); + f.PutLine( ssprintf( "#GENRE:%s;", SmEscape(out.m_sGenre).c_str() ) ); + f.PutLine( ssprintf( "#CREDIT:%s;", SmEscape(out.m_sCredit).c_str() ) ); + f.PutLine( ssprintf( "#BANNER:%s;", SmEscape(out.m_sBannerFile).c_str() ) ); + f.PutLine( ssprintf( "#BACKGROUND:%s;", SmEscape(out.m_sBackgroundFile).c_str() ) ); + f.PutLine( ssprintf( "#LYRICSPATH:%s;", SmEscape(out.m_sLyricsFile).c_str() ) ); + f.PutLine( ssprintf( "#CDTITLE:%s;", SmEscape(out.m_sCDTitleFile).c_str() ) ); + 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] ); + if( !vs.empty() ) + { + RString s = join( ",", vs ); + f.PutLine( "#INSTRUMENTTRACK:" + s + ";\n" ); + } + } + f.PutLine( ssprintf( "#OFFSET:%.6f;", out.m_Timing.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 + case Song::SHOW_ALWAYS: f.Write( "YES" ); break; + //case Song::SHOW_NONSTOP: f.Write( "NONSTOP" ); break; + case Song::SHOW_NEVER: f.Write( "NO" ); break; + } + f.PutLine( ";" ); + + switch( out.m_DisplayBPMType ) + { + case Song::DISPLAY_ACTUAL: + // write nothing + break; + case Song::DISPLAY_SPECIFIED: + if( out.m_fSpecifiedBPMMin == out.m_fSpecifiedBPMMax ) + f.PutLine( ssprintf( "#DISPLAYBPM:%.6f;", out.m_fSpecifiedBPMMin ) ); + else + f.PutLine( ssprintf( "#DISPLAYBPM:%.6f:%.6f;", out.m_fSpecifiedBPMMin, out.m_fSpecifiedBPMMax ) ); + break; + case Song::DISPLAY_RANDOM: + f.PutLine( ssprintf( "#DISPLAYBPM:*;" ) ); + break; + } + + f.Write( "#BPMS:" ); + for( unsigned i=0; im_iStartRow), iter->m_iNumerator, iter->m_iDenominator ) ); + vector::const_iterator iter2 = iter; + iter2++; + if( iter2 != out.m_Timing.m_vTimeSignatureSegments.end() ) + f.Write( "," ); + } + f.PutLine( ";" ); + + ASSERT( !out.m_Timing.m_TickcountSegments.empty() ); + f.Write( "#TICKCOUNTS:" ); + for( unsigned i=0; i &lines ) +{ + for( unsigned i = 0; i < lines.size(); ++i ) + TrimRight( lines[i] ); + + // Skip leading blanks. + unsigned j = 0; + while( j < lines.size() && lines.size() == 0 ) + ++j; + + return join( "\r\n", lines.begin()+j, lines.end() ); +} + +static RString GetSSCNotesTag( const Song &song, const Steps &in, bool bSavingCache ) +{ + vector lines; + + lines.push_back( "" ); + // Escape to prevent some clown from making a comment of "\r\n;" + 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( "#STEPSTYPE:%s;", GAMEMAN->GetStepsTypeInfo(in.m_StepsType).szName ) ); + lines.push_back( ssprintf( "#DESCRIPTION:%s;", SmEscape(in.GetDescription()).c_str() ) ); + lines.push_back( ssprintf( "#DIFFICULTY:%s;", DifficultyToString(in.GetDifficulty()).c_str() ) ); + lines.push_back( ssprintf( "#METER:%d;", in.GetMeter() ) ); + + vector asRadarValues; + FOREACH_PlayerNumber( pn ) + { + const RadarValues &rv = in.GetRadarValues( pn ); + FOREACH_ENUM( RadarCategory, rc ) + asRadarValues.push_back( ssprintf("%.3f", rv[rc]) ); + } + lines.push_back( ssprintf( "#RADARVALUES:%s:", join(",",asRadarValues).c_str() ) ); + + lines.push_back( ssprintf( "#CREDIT:%s;", SmEscape(in.GetCredit()).c_str() ) ); + + // TODO: Remove this block, uncomment below block for Split Timing. -Wolfman2000 + lines.push_back( "#BPMS:;" ); + lines.push_back( "#STOPS:;" ); + lines.push_back( "#DELAYS:;" ); + lines.push_back( "#TIMESIGNATURES:;" ); + lines.push_back( "#TICKCOUNTS:;" ); + // lines.push_back( "#COMBOS:;" ); + + /* + vector asBPMValues; + for( unsigned i=0; i asStopValues; + for( unsigned i=0; i asDelayValues; + for( unsigned i=0; i asTimeSigValues; + FOREACH_CONST( TimeSignatureSegment, in.m_Timing.m_vTimeSignatureSegments, iter ) + { + asTimeSigValues.push_back( ssprintf( "%.6f=%d=%d", NoteRowToBeat(iter->m_iStartRow), iter->m_iNumerator, iter->m_iDenominator ) ); + vector::const_iterator iter2 = iter; + iter2++; + } + lines.push_back( ssprintf( "#TIMESIGNATURES:%s;", join("\n,", asTimeSigValues).c_str() ) ); + + ASSERT( !in.m_Timing.m_TickcountSegments.empty() ); + vector asTickValues; + for( unsigned i=0; i asComboValues; + for( unsigned i=0; i& vpStepsToSave, bool bSavingCache ) +{ + int flags = RageFile::WRITE; + + /* If we're not saving cache, we're saving real data, so enable SLOW_FLUSH + * to prevent data loss. If we're saving cache, this will slow things down + * too much. */ + if( !bSavingCache ) + flags |= RageFile::SLOW_FLUSH; + + RageFile f; + if( !f.Open( sPath, flags ) ) + { + LOG->UserLog( "Song file", sPath, "couldn't be opened for writing: %s", f.GetError().c_str() ); + return false; + } + + WriteGlobalTags( f, out ); + 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( "#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( "// end cache tags" ) ); + } + + // Save specified Steps to this file + FOREACH_CONST( Steps*, vpStepsToSave, s ) + { + const Steps* pSteps = *s; + RString sTag = GetSSCNotesTag( out, *pSteps, bSavingCache ); + f.PutLine( sTag ); + } + if( f.Flush() == -1 ) + return false; + + return true; +} + +void NotesWriterSSC::GetEditFileContents( const Song *pSong, const Steps *pSteps, RString &sOut ) +{ + sOut = ""; + RString sDir = pSong->GetSongDir(); + + // "Songs/foo/bar"; strip off "Songs/". + vector asParts; + split( sDir, "/", asParts ); + if( asParts.size() ) + sDir = join( "/", asParts.begin()+1, asParts.end() ); + sOut += ssprintf( "#SONG:%s;\r\n", sDir.c_str() ); + sOut += GetSSCNotesTag( *pSong, *pSteps, false ); +} + +RString NotesWriterSSC::GetEditFileName( const Song *pSong, const Steps *pSteps ) +{ + /* Try to make a unique name. This isn't guaranteed. Edit descriptions are + * case-sensitive, filenames on disk are usually not, and we decimate certain + * characters for FAT filesystems. */ + RString sFile = pSong->GetTranslitFullTitle() + " - " + pSteps->GetDescription(); + + // HACK: + if( pSteps->m_StepsType == StepsType_dance_double ) + sFile += " (doubles)"; + + sFile += ".edit"; + + MakeValidFilename( sFile ); + return sFile; +} + +static LocalizedString DESTINATION_ALREADY_EXISTS ("NotesWriterSSC", "Error renaming file. Destination file '%s' already exists."); +static LocalizedString ERROR_WRITING_FILE ("NotesWriterSSC", "Error writing file '%s'."); +bool NotesWriterSSC::WriteEditFileToMachine( const Song *pSong, Steps *pSteps, RString &sErrorOut ) +{ + RString sDir = PROFILEMAN->GetProfileDir( ProfileSlot_Machine ) + EDIT_STEPS_SUBDIR; + + RString sPath = sDir + GetEditFileName(pSong,pSteps); + + // Check to make sure that we're not clobering an existing file before opening. + bool bFileNameChanging = + pSteps->GetSavedToDisk() && + pSteps->GetFilename() != sPath; + if( bFileNameChanging && DoesFileExist(sPath) ) + { + sErrorOut = ssprintf( DESTINATION_ALREADY_EXISTS.GetValue(), sPath.c_str() ); + return false; + } + + RageFile f; + if( !f.Open(sPath, RageFile::WRITE | RageFile::SLOW_FLUSH) ) + { + sErrorOut = ssprintf( ERROR_WRITING_FILE.GetValue(), sPath.c_str() ); + return false; + } + + RString sTag; + GetEditFileContents( pSong, pSteps, sTag ); + if( f.PutLine(sTag) == -1 || f.Flush() == -1 ) + { + sErrorOut = ssprintf( ERROR_WRITING_FILE.GetValue(), sPath.c_str() ); + return false; + } + + /* If the file name of the edit has changed since the last save, then delete the old + * file after saving the new one. If we delete it first, then we'll lose data on error. */ + + if( bFileNameChanging ) + FILEMAN->Remove( pSteps->GetFilename() ); + pSteps->SetFilename( sPath ); + + return true; +} + +/* + * (c) 2011 Jason Felds + * 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/MusicList.h b/src/NotesWriterSSC.h similarity index 58% rename from src/MusicList.h rename to src/NotesWriterSSC.h index bb505d74c7..4819dc60d9 100644 --- a/src/MusicList.h +++ b/src/NotesWriterSSC.h @@ -1,50 +1,22 @@ -/* MusicList - Displays all the songs in a given group. (An artifact from SelectGroup.) */ -#ifndef MUSIC_LIST_H -#define MUSIC_LIST_H +/* NotesWriterSSC - Writes a Song to an .SSC file. */ -#include "ActorFrame.h" -#include "BitmapText.h" - -const int MAX_MLIST_COLUMNS = 5; +#ifndef NOTES_WRITER_SSC_H +#define NOTES_WRITER_SSC_H class Song; - -class MusicList : public ActorFrame +class Steps; +namespace NotesWriterSSC { - BitmapText m_textTitles[MAX_MLIST_COLUMNS]; - - struct group - { - RString ContentsText[MAX_MLIST_COLUMNS]; - int m_iNumSongsInGroup; - }; - - vector m_ContentsText; - - int NumGroups, CurGroup; - -public: - MusicList(); - void Load(); - - /* Add a new group. */ - void AddGroup(); - - /* Add songs to the group that was just added. */ - void AddSongsToGroup(const vector &songs); - - /* Set the displayed group number. */ - void SetGroupNo(int group); - - void TweenOnScreen(); - void TweenOffScreen(); - int GetNumSongs() const { return m_ContentsText[CurGroup].m_iNumSongsInGroup; } -}; + bool Write( RString sPath, const Song &out, const vector& vpStepsToSave, bool bSavingCache ); + void GetEditFileContents( const Song *pSong, const Steps *pSteps, RString &sOut ); + RString GetEditFileName( const Song *pSong, const Steps *pSteps ); + bool WriteEditFileToMachine( const Song *pSong, Steps *pSteps, RString &sErrorOut ); +} #endif /* - * (c) 2001-2003 Chris Danford + * (c) 2011 Jason Felds * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/OptionRow.cpp b/src/OptionRow.cpp index 3d83d90a96..cc37ffb4dc 100644 --- a/src/OptionRow.cpp +++ b/src/OptionRow.cpp @@ -661,7 +661,7 @@ const BitmapText &OptionRow::GetTextItemForRow( PlayerNumber pn, int iChoiceOnRo { case LAYOUT_SHOW_ONE_IN_ROW: index = bOneChoice ? 0 : pn; - /* If only P2 is enabled, his selections will be in index 0. */ + // If only P2 is enabled, his selections will be in index 0. if( m_textItems.size() == 1 ) index = 0; break; @@ -685,14 +685,13 @@ void OptionRow::GetWidthXY( PlayerNumber pn, int iChoiceOnRow, int &iWidthOut, i iYOut = lrintf( m_Frame.GetDestY() ); } - int OptionRow::GetOneSelection( PlayerNumber pn, bool bAllowFail ) const { for( unsigned i=0; im_Def.m_selectType ) { case SELECT_ONE: - /* Import the focus from the selected option. */ + // Import the focus from the selected option. iSelection = GetOneSelection( pn, true ); break; } - // // HACK: Set focus to one item in the row, which is "go down" - // if( m_bFirstItemGoesDown ) iSelection = 0; @@ -809,12 +806,14 @@ void OptionRow::SetExitText( RString sExitText ) void OptionRow::Reload() { // TODO: Nothing uses this yet and it causes skips when changing options. - //if( m_pHand->m_Def.m_bExportOnChange ) - //{ - // bool bRowHasFocus[NUM_PLAYERS]; - // ZERO( bRowHasFocus ); - // ExportOptions( vpns, bRowHasFocus ); - //} + /* + if( m_pHand->m_Def.m_bExportOnChange ) + { + bool bRowHasFocus[NUM_PLAYERS]; + ZERO( bRowHasFocus ); + ExportOptions( vpns, bRowHasFocus ); + } + */ switch( m_pHand->Reload() ) { @@ -841,14 +840,15 @@ void OptionRow::Reload() break; } - // TODO: Nothing uses this yet and it causes skips when changing options. - //if( m_pHand->m_Def.m_bExportOnChange ) - //{ - // bool bRowHasFocus[NUM_PLAYERS]; - // ZERO( bRowHasFocus ); - // ExportOptions( vpns, bRowHasFocus ); - //} + /* + if( m_pHand->m_Def.m_bExportOnChange ) + { + bool bRowHasFocus[NUM_PLAYERS]; + ZERO( bRowHasFocus ); + ExportOptions( vpns, bRowHasFocus ); + } + */ } void OptionRow::HandleMessage( const Message &msg ) @@ -866,8 +866,8 @@ void OptionRow::HandleMessage( const Message &msg ) } -/* Hack: the NextRow entry is never set, and should be transparent. Remove - * it, and readd it below. */ +/* Hack: the NextRow entry is never set, and should be transparent. + * Remove it, and readd it below. */ #define ERASE_ONE_BOOL_AT_FRONT_IF_NEEDED( vbSelected ) \ if( GetFirstItemGoesDown() ) \ vbSelected.erase( vbSelected.begin() ); @@ -889,7 +889,7 @@ void OptionRow::ImportOptions( const vector &vpns ) ASSERT( m_vbSelected[p].size() == m_pHand->m_Def.m_vsChoices.size() ); ERASE_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[p] ); } - + m_pHand->ImportOption( this, vpns, m_vbSelected ); FOREACH_CONST( PlayerNumber, vpns, iter ) @@ -906,7 +906,7 @@ int OptionRow::ExportOptions( const vector &vpns, bool bRowHasFocu ASSERT( m_pHand->m_Def.m_vsChoices.size() > 0 ); int iChangeMask = 0; - + FOREACH_CONST( PlayerNumber, vpns, iter ) { PlayerNumber p = *iter; @@ -916,15 +916,14 @@ int OptionRow::ExportOptions( const vector &vpns, bool bRowHasFocu ASSERT( m_vbSelected[p].size() == m_pHand->m_Def.m_vsChoices.size() ); ERASE_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[p] ); - // SELECT_NONE rows get exported if they have focus when the user presses - // Start. + // SELECT_NONE rows get exported if they have focus when the user presses Start. int iChoice = GetChoiceInRowWithFocus( p ); if( m_pHand->m_Def.m_selectType == SELECT_NONE && bFocus ) m_vbSelected[p][iChoice] = true; } iChangeMask |= m_pHand->ExportOption( vpns, m_vbSelected ); - + FOREACH_CONST( PlayerNumber, vpns, iter ) { PlayerNumber p = *iter; @@ -933,14 +932,13 @@ int OptionRow::ExportOptions( const vector &vpns, bool bRowHasFocu int iChoice = GetChoiceInRowWithFocus( p ); if( m_pHand->m_Def.m_selectType == SELECT_NONE && bFocus ) m_vbSelected[p][iChoice] = false; - + INSERT_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[p] ); } return iChangeMask; } - /* * (c) 2001-2004 Chris Danford * All rights reserved. diff --git a/src/OptionRowHandler.cpp b/src/OptionRowHandler.cpp index e471b88649..c6b43459b6 100644 --- a/src/OptionRowHandler.cpp +++ b/src/OptionRowHandler.cpp @@ -745,7 +745,8 @@ class OptionRowHandlerListDifficulties: public OptionRowHandlerList FOREACH_CONST( Difficulty, CommonMetrics::DIFFICULTIES_TO_SHOW.GetValue(), d ) { - StepsType st = GAMEMAN->GetHowToPlayStyleForGame( GAMESTATE->m_pCurGame )->m_StepsType; // TODO: Is this the best thing we can do here? + // TODO: Is this the best thing we can do here? + StepsType st = GAMEMAN->GetHowToPlayStyleForGame( GAMESTATE->m_pCurGame )->m_StepsType; RString s = CustomDifficultyToLocalizedString( GetCustomDifficulty(st, *d, CourseType_Invalid) ); m_Def.m_vsChoices.push_back( s ); diff --git a/src/Player.cpp b/src/Player.cpp index 60a480258b..fd3a45e715 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -128,6 +128,7 @@ ThemeMetric MAX_HOLD_LIFE ( "Player", "MaxHoldLife" ); // sm-ssc additio ThemeMetric PENALIZE_TAP_SCORE_NONE ( "Player", "PenalizeTapScoreNone" ); ThemeMetric JUDGE_HOLD_NOTES_ON_SAME_ROW_TOGETHER ( "Player", "JudgeHoldNotesOnSameRowTogether" ); ThemeMetric HOLD_CHECKPOINTS ( "Player", "HoldCheckpoints" ); +ThemeMetric CHECKPOINTS_USE_TICKCOUNTS ( "Player", "CheckpointsUseTickcounts" ); ThemeMetric CHECKPOINTS_USE_TIME_SIGNATURES ( "Player", "CheckpointsUseTimeSignatures" ); ThemeMetric CHECKPOINTS_FLASH_ON_HOLD ( "Player", "CheckpointsFlashOnHold" ); // sm-ssc addition ThemeMetric IMMEDIATE_HOLD_LET_GO ( "Player", "ImmediateHoldLetGo" ); @@ -138,6 +139,9 @@ ThemeMetric ROLL_BODY_INCREMENTS_COMBO ( "Player", "RollBodyIncrementsComb ThemeMetric CHECKPOINTS_TAPS_SEPARATE_JUDGMENT ( "Player", "CheckpointsTapsSeparateJudgment" ); ThemeMetric SCORE_MISSED_HOLDS_AND_ROLLS ( "Player", "ScoreMissedHoldsAndRolls" ); // sm-ssc addition ThemeMetric PERCENT_UNTIL_COLOR_COMBO ( "Player", "PercentUntilColorCombo" ); +ThemeMetric COMBO_STOPPED_AT ( "Player", "ComboStoppedAt" ); +ThemeMetric ATTACK_RUN_TIME_RANDOM ( "Player", "AttackRunTimeRandom" ); +ThemeMetric ATTACK_RUN_TIME_MINE ( "Player", "AttackRunTimeMine" ); float Player::GetWindowSeconds( TimingWindow tw ) { @@ -581,7 +585,7 @@ void Player::Load() void Player::SendComboMessages( int iOldCombo, int iOldMissCombo ) { const int iCurCombo = m_pPlayerStageStats ? m_pPlayerStageStats->m_iCurCombo : 0; - if( iOldCombo > 50 && iCurCombo < 50 ) + if( iOldCombo > COMBO_STOPPED_AT && iCurCombo < COMBO_STOPPED_AT ) { SCREENMAN->PostMessageToTopScreen( SM_ComboStopped, 0 ); } @@ -641,8 +645,7 @@ void Player::Update( float fDeltaTime ) { float fCurrentGameTime = STATSMAN->m_CurStageStats.m_fGameplaySeconds; - // Should we hardcode this, or make it a preference/theme metric? ~ Mike - const float fAttackRunTime = 6.0f; + const float fAttackRunTime = ATTACK_RUN_TIME_RANDOM; // Don't start until 1 seconds into game, minimum if( fCurrentGameTime > 1.0f ) @@ -982,6 +985,7 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vectorTrace(ssprintf("[Player::UpdateHoldNotes] fLife = %f",fLife)); bool bSteppedOnHead = true; + bool bHeadJudged = true; FOREACH( TrackRowTapNote, vTN, trtn ) { TapNote &tn = *trtn->pTN; @@ -992,7 +996,8 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vectorTrace("[Player::UpdateHoldNotes] initiated note, fLife != 0"); /* This hold note is not judged and we stepped on its head. @@ -1073,7 +1081,7 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vectorTrace("LetGo from life == 0 (did initiate hold)"); hns = HNS_LetGo; @@ -1162,7 +1170,7 @@ void Player::UpdateHoldNotes( int iSongRow, float fDeltaTime, vector= iMaxEndRow ) + if( iSongRow >= iMaxEndRow && bHeadJudged ) { bool bLetGoOfHoldNote = false; @@ -2488,6 +2496,10 @@ void Player::UpdateTapNotesMissedOlderThan( float fMissIfOlderThanSeconds ) if( !NeedsTapJudging(tn) ) continue; + // warp hackery + if( iter.Row() >= GAMESTATE->m_iWarpBeginRow && iter.Row() <= (GAMESTATE->m_iWarpBeginRow + BeatToNoteRow(GAMESTATE->m_fWarpLength)) ) + continue; + if( tn.type == TapNote::mine ) { tn.result.tns = TNS_AvoidMine; @@ -2524,15 +2536,15 @@ void Player::UpdateJudgedRows() { int iRow = iter.Row(); + // if row is within a warp section, ignore it. -aj + if( iRow >= GAMESTATE->m_iWarpBeginRow && + iRow <= (GAMESTATE->m_iWarpBeginRow + BeatToNoteRow(GAMESTATE->m_fWarpLength)) ) + continue; + if( iLastSeenRow != iRow ) { iLastSeenRow = iRow; - // if row is within a warp section, ignore it. -aj - if( iRow >= GAMESTATE->m_iWarpBeginRow && - iRow <= (GAMESTATE->m_iWarpBeginRow + BeatToNoteRow(GAMESTATE->m_fWarpLength)) ) - continue; - // crossed a nonempty row if( !NoteDataWithScoring::IsRowCompletelyJudged(m_NoteData, iRow) ) { @@ -2612,8 +2624,7 @@ void Player::UpdateJudgedRows() * etc.) are still applied. */ if( m_pPlayerState->m_PlayerOptions.GetCurrent().m_bTransforms[PlayerOptions::TRANSFORM_ATTACKMINES] ) { - // Should we hardcode this, or make it a preference/theme metric? ~ Mike - const float fAttackRunTime = 7.0f; + const float fAttackRunTime = ATTACK_RUN_TIME_MINE; Attack attMineAttack; attMineAttack.sModifiers = ApplyRandomAttack(); @@ -2774,7 +2785,11 @@ void Player::CrossedRows( int iLastRowCrossed, const RageTimer &now ) if( HOLD_CHECKPOINTS ) { int iCheckpointFrequencyRows = ROWS_PER_BEAT/2; - if( CHECKPOINTS_USE_TIME_SIGNATURES ) + if( CHECKPOINTS_USE_TICKCOUNTS ) + { + iCheckpointFrequencyRows = ROWS_PER_BEAT / GAMESTATE->m_pCurSong->m_Timing.GetTickcountAtRow( iLastRowCrossed ); + } + else if( CHECKPOINTS_USE_TIME_SIGNATURES ) { TimeSignatureSegment tSignature = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iLastRowCrossed ) ); @@ -2985,6 +3000,11 @@ void Player::HandleHoldCheckpoint( int iRow, int iNumHoldsHeldThisRow, int iNumH bNoCheating = false; #endif + // more warp hackery. -aj + if( iRow >= GAMESTATE->m_iWarpBeginRow && + iRow <= (GAMESTATE->m_iWarpBeginRow + BeatToNoteRow(GAMESTATE->m_fWarpLength)) ) + return; + // don't accumulate combo if AutoPlay is on. if( bNoCheating && m_pPlayerState->m_PlayerController == PC_AUTOPLAY ) return; diff --git a/src/Player.h b/src/Player.h index dbd4caf0bf..82118d95ce 100644 --- a/src/Player.h +++ b/src/Player.h @@ -23,6 +23,7 @@ class NoteField; class PlayerStageStats; class JudgedRows; +// todo: replace these with a Message and MESSAGEMAN? -aj AutoScreenMessage( SM_100Combo ); AutoScreenMessage( SM_200Combo ); AutoScreenMessage( SM_300Combo ); diff --git a/src/PlayerOptions.cpp b/src/PlayerOptions.cpp index 2b4053b6b6..87352f4233 100644 --- a/src/PlayerOptions.cpp +++ b/src/PlayerOptions.cpp @@ -14,6 +14,14 @@ #define ONE( arr ) { for( unsigned Z = 0; Z < ARRAYLEN(arr); ++Z ) arr[Z]=1.0f; } +ThemeMetric RANDOM_SPEED_CHANCE ( "PlayerOptions", "RandomSpeedChance" ); +ThemeMetric RANDOM_REVERSE_CHANCE ( "PlayerOptions", "RandomReverseChance" ); +ThemeMetric RANDOM_DARK_CHANCE ( "PlayerOptions", "RandomDarkChance" ); +ThemeMetric RANDOM_ACCEL_CHANCE ( "PlayerOptions", "RandomAccelChance" ); +ThemeMetric RANDOM_EFFECT_CHANCE ( "PlayerOptions", "RandomEffectChance" ); +ThemeMetric RANDOM_HIDDEN_CHANCE ( "PlayerOptions", "RandomHiddenChance" ); +ThemeMetric RANDOM_SUDDEN_CHANCE ( "PlayerOptions", "RandomSuddenChance" ); + void PlayerOptions::Init() { m_bSetScrollSpeed = false; @@ -526,22 +534,22 @@ void PlayerOptions::NextPerspective() void PlayerOptions::ChooseRandomModifiers() { - if( RandomFloat(0,1)>0.8f ) + if( RandomFloat(0,1)0.8f ) + if( RandomFloat(0,1)0.9f ) + if( RandomFloat(0,1)0.66f ) + if( f0.33f ) + else if( f0.95f ) + if( f0.9f ) + else if( fGetMetricF("PlayerStageStats",ssprintf("GradePercent%s",GradeToString((Grade)i).c_str())) +// deprecated, but no solution to replace them exists yet: #define GRADE_TIER02_IS_ALL_W2S THEME->GetMetricB("PlayerStageStats","GradeTier02IsAllW2s") #define GRADE_TIER01_IS_ALL_W2S THEME->GetMetricB("PlayerStageStats","GradeTier01IsAllW2s") #define GRADE_TIER02_IS_FULL_COMBO THEME->GetMetricB("PlayerStageStats","GradeTier02IsFullCombo") @@ -76,7 +77,7 @@ void PlayerStageStats::AddStats( const PlayerStageStats& other ) m_iActualDancePoints += other.m_iActualDancePoints; m_iCurPossibleDancePoints += other.m_iCurPossibleDancePoints; m_iPossibleGradePoints += other.m_iPossibleGradePoints; - + for( int t=0; tTrace( "GetGrade: fActual: %f, fPossible: %d", fActual, m_iPossibleGradePoints ); - float fPercent = (m_iPossibleGradePoints == 0) ? 0 : fActual / m_iPossibleGradePoints; Grade grade = GetGradeFromPercent( fPercent ); //LOG->Trace( "GetGrade: Grade: %s, %i", GradeToString(grade).c_str(), GRADE_TIER02_IS_ALL_W2S ); + + // todo: move all these conditions to Lua. -aj if( GRADE_TIER02_IS_ALL_W2S ) { if( FullComboOfScore(TNS_W1) ) @@ -260,9 +262,6 @@ float PlayerStageStats::GetPercentDancePoints() const float PlayerStageStats::GetCurMaxPercentDancePoints() const { if ( m_iPossibleDancePoints == 0 ) - - - return 0; // div/0 if ( m_iCurPossibleDancePoints == m_iPossibleDancePoints ) @@ -403,14 +402,13 @@ float PlayerStageStats::GetLifeRecordLerpAt( float fStepsSecond ) const if( later == m_fLifeRecord.end() ) return earlier->second; - if( earlier->first == later->first ) // two samples from the same time. Don't divide by zero in SCALE + if( earlier->first == later->first ) // two samples from the same time. Don't divide by zero in SCALE return earlier->second; // earlier <= pos <= later return SCALE( fStepsSecond, earlier->first, later->first, earlier->second, later->second ); } - void PlayerStageStats::GetLifeRecord( float *fLifeOut, int iNumSamples, float fStepsEndSecond ) const { for( int i = 0; i < iNumSamples; ++i ) @@ -768,7 +766,6 @@ public: LUA_REGISTER_CLASS( PlayerStageStats ) // lua end - /* * (c) 2001-2004 Chris Danford, Glenn Maynard * All rights reserved. diff --git a/src/PlayerStageStats.h b/src/PlayerStageStats.h index 59f487e8f6..373911e6b1 100644 --- a/src/PlayerStageStats.h +++ b/src/PlayerStageStats.h @@ -123,7 +123,6 @@ public: void PushSelf( lua_State *L ); }; - #endif /* diff --git a/src/PlayerState.h b/src/PlayerState.h index ac4f5f0749..26559e50f8 100644 --- a/src/PlayerState.h +++ b/src/PlayerState.h @@ -1,4 +1,4 @@ -/* PlayerState - Holds per-player game state. */ +/** @brief PlayerState - Holds per-player game state. */ #ifndef PlayerState_H #define PlayerState_H @@ -11,37 +11,68 @@ #include "SampleHistory.h" struct lua_State; +/** @brief The player's indivdual state. */ class PlayerState { public: + /** @brief Set up the PlayerState with initial values. */ PlayerState(); + /** @brief Reset the PlayerState with the initial values. */ void Reset(); + /** + * @brief Update the PlayerState based on the present time. + * @param fDelta the current time. */ void Update( float fDelta ); - // TODO: Remove use of PlayerNumber. All data about the player should live - // in PlayerState and callers should not use PlayerNumber to index into - // GameState. + /** + * @brief The PlayerNumber assigned to this Player: usually 1 or 2. + * + * TODO: Remove use of PlayerNumber. All data about the player should live + * in PlayerState and callers should not use PlayerNumber to index into + * GameState. */ PlayerNumber m_PlayerNumber; + MultiPlayer m_mp; + /** + * @brief Change the PlayerOptions to their default. + * @param l the level of mods to reset. + */ void ResetToDefaultPlayerOptions( ModsLevel l ); + /** @brief The PlayerOptions presently in use by the Player. */ ModsGroup m_PlayerOptions; - // Used in Gameplay - mutable float m_fLastDrawnBeat; // Set by NoteField. Used to push note-changing modifers back so that notes doesn't pop. - + /** + * @brief Used to push note-changing modifiers back so that notes don't pop. + * + * This is used during gameplay and set by NoteField. */ + mutable float m_fLastDrawnBeat; + /** @brief The Player's HealthState in general terms. */ HealthState m_HealthState; - float m_fLastStrumMusicSeconds; // Set to the MusicSeconds of when the a strum button was pressed. If -1, the strum window has passed. - float m_fLastHopoNoteMusicSeconds; // Set to the MusicSeconds of the last note successfully strummed or hammered in a hopochain, -1, then there is no current hopo chain - int m_iLastHopoNoteCol; // if -1, then there is no current hopo chain + /** + * @brief Set to the MusicSeconds of when the a strum button was pressed. + * + * If -1, the strum window has passed. */ + float m_fLastStrumMusicSeconds; + /** + * @brief Set to the MusicSeconds of the last note successfully strummed or hammered in a hopochain. + * + * If -1, then there is no current hopo chain. */ + float m_fLastHopoNoteMusicSeconds; + /** + * @brief Set to the column in the current hopo chain. + * + * If -1, then there is no current hopo chain. */ + int m_iLastHopoNoteCol; + /** @brief Reset the hopo state to its default. */ void ClearHopoState() { m_fLastHopoNoteMusicSeconds = -1; m_iLastHopoNoteCol = -1; } - + /** @brief The type of person/machine controlling the Player. */ PlayerController m_PlayerController; SampleHistory m_EffectHistory; @@ -80,8 +111,10 @@ public: #endif -/* - * (c) 2001-2004 Chris Danford, Chris Gomez +/** + * @file + * @author Chris Danford, Chris Gomez (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/PrefsManager.cpp b/src/PrefsManager.cpp index a47285277c..2ced597a9e 100644 --- a/src/PrefsManager.cpp +++ b/src/PrefsManager.cpp @@ -134,6 +134,17 @@ XToString( ScoringType ); StringToX( ScoringType ); LuaXType( ScoringType ); +// XXX: Fix fail bug? +/* static const char *DefaultFailTypeNames[] = { + "Immediate", + "ImmediateContinue", + "EndOfSong", + "Off", +}; +XToString( DefaultFailType ); +StringToX( DefaultFailType ); +LuaXType( DefaultFailType ); */ + bool g_bAutoRestart = false; #ifdef DEBUG # define TRUE_IF_DEBUG true @@ -157,7 +168,6 @@ PrefsManager::PrefsManager() : m_sAnnouncer ( "Announcer", "" ), m_sTheme ( "Theme", SpecialFiles::BASE_THEME_NAME ), - m_sDefaultTheme ( "DefaultTheme", "default" ), m_sDefaultModifiers ( "DefaultModifiers", "" ), m_bWindowed ( "Windowed", true ), @@ -188,7 +198,7 @@ PrefsManager::PrefsManager() : m_bOnlyDedicatedMenuButtons ( "OnlyDedicatedMenuButtons", false ), m_bMenuTimer ( "MenuTimer", false ), - m_fLifeDifficultyScale ( "LifeDifficultyScale", .0f ), + m_fLifeDifficultyScale ( "LifeDifficultyScale", 1.0f ), m_iRegenComboAfterMiss ( "RegenComboAfterMiss", 5 ), @@ -257,6 +267,7 @@ PrefsManager::PrefsManager() : m_sAdditionalSongFolders ( "AdditionalSongFolders", "" ), m_sAdditionalCourseFolders ( "AdditionalCourseFolders", "" ), m_sAdditionalFolders ( "AdditionalFolders", "" ), + m_sDefaultTheme ( "DefaultTheme", "default" ), m_sLastSeenVideoDriver ( "LastSeenVideoDriver", "" ), m_sVideoRenderers ( "VideoRenderers", "" ), // StepMania.cpp sets these on first run: m_bSmoothLines ( "SmoothLines", false ), diff --git a/src/PrefsManager.h b/src/PrefsManager.h index bae3779a4b..f9443ac9e5 100644 --- a/src/PrefsManager.h +++ b/src/PrefsManager.h @@ -115,6 +115,16 @@ enum ScoringType ScoringType_Invalid }; +enum DefaultFailType +{ + FAIL_IMMEDIATE, + FAIL_IMMEDIATECONTINUE, + FAIL_ENDOFSONG, + FAIL_OFF, + NUM_DefaultFailType, + DefaultFailType_Invalid +}; + class PrefsManager { public: @@ -279,6 +289,7 @@ public: Preference m_sCoursesToShowRanking; Preference m_bQuirksMode; // enable quirky behavior desired by users of microsoft stepmania explorer 6.9 + // Preference m_sDefaultFailType; // XXX: Fix fail bug? // Debug: Preference m_bLogToDisk; diff --git a/src/ProductInfo.h b/src/ProductInfo.h index d59dadb80e..f64d44756e 100644 --- a/src/ProductInfo.h +++ b/src/ProductInfo.h @@ -1,30 +1,48 @@ -/* ProductInfo - Branding strings. Don't forget to also change ProductInfo.inc! */ +/** @brief ProductInfo - Branding strings. Don't forget to also change ProductInfo.inc! */ #ifndef PRODUCT_INFO_H #define PRODUCT_INFO_H -// A friendly string to refer to the product in crash dialogs, etc - i.e. "StepMania" not "StepMania4" +/** + * @brief A friendly string to refer to the product in crash dialogs, etc. + * + * As an example, use "StepMania" here, not "StepMania4". + */ #define PRODUCT_FAMILY_BARE sm-ssc -// A unique name for each application that you might want installed side-by-side with other applications - i.e. "StepMania4" not "StepMania" (would conflict with StepMania 3.x) +/** + * @brief A unique name for each application that you might want installed side-by-side with other applications. + * + * As an example, use "StepMania4" here, not "StepMania". + * It would cause a conflict with older versions such as StepMania 3.X. + */ #define PRODUCT_ID_BARE sm-ssc -/* Version info displayed to the user. +/** + * @brief Version info displayed to the user. + * * These are the 'official' version designations: + *
    + *
  • "experimental: pre-release versions.
  • * - * "experimental: pre-release versions - * "private beta v0.0": hmm, think about it for a second there. - * ==Public versions== - * "v0.0 alpha #": Alpha versions (bug squashing, polishing until we reach beta) - * "v0.0 beta #": Beta versions (bug squashing, _focus_ is on high priority bugs) - * "v0.0 rc#": Release Candidates (if there are no problems, move on to final) - * "v0.0": Final Releases -*/ + *
  • "private beta v0.0": hmm, think about it for a second there.
  • + * + *
  • ==Public versions== + * - "v0.0 alpha #": Alpha versions (bug squashing, polishing until we reach beta) + * - "v0.0 beta #": Beta versions (bug squashing, _focus_ is on high priority bugs) + * - "v0.0 rc#": Release Candidates (if there are no problems, move on to final) + * - "v0.0": Final Releases + *
+ */ #ifndef PRODUCT_VER_BARE -#define PRODUCT_VER_BARE v1.1 +#define PRODUCT_VER_BARE v1.2.1 #endif -// A unique ID for a build of an application. This is used in crash reports and in the network code's version handling +/** + * @brief A unique ID for a build of an application. + * + * This is used in crash reports and in the network code's version handling. + */ #define PRODUCT_ID_VER_BARE PRODUCT_ID_BARE PRODUCT_VER_BARE // These cannot be #undef'd so make them unlikely to conflict with anything @@ -37,14 +55,17 @@ #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" +/** @brief The URL to report bugs on the program. */ #define REPORT_BUG_URL "http://ssc.ajworld.net/sm-ssc/bugtracker/" #define CAN_INSTALL_PACKAGES true #endif -/* - * (c) 2003-2005 Chris Danford +/** + * @file + * @author Chris Danford (c) 2003-2005 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/ProductInfo.inc b/src/ProductInfo.inc index fbd6a80dbf..616754e3fa 100644 --- a/src/ProductInfo.inc +++ b/src/ProductInfo.inc @@ -5,7 +5,7 @@ ; see ProductInfo.h for use descriptions !define PRODUCT_ID "sm-ssc" -!define PRODUCT_VER "v1.1" +!define PRODUCT_VER "v1.2.1" !define PRODUCT_DISPLAY "${PRODUCT_ID} ${PRODUCT_VER}" !define PRODUCT_BITMAP "ssc" diff --git a/src/Profile.cpp b/src/Profile.cpp index 35c52c7377..22b071a4d6 100644 --- a/src/Profile.cpp +++ b/src/Profile.cpp @@ -28,7 +28,9 @@ const RString STATS_XML = "Stats.xml"; const RString STATS_XML_GZ = "Stats.xml.gz"; +/** @brief The filename for where one can edit their personal profile information. */ const RString EDITABLE_INI = "Editable.ini"; +/** @brief The filename containing the signature for STATS_XML's signature. */ const RString DONT_SHARE_SIG = "DontShare.sig"; const RString PUBLIC_KEY_FILE = "public.key"; const RString SCREENSHOTS_SUBDIR = "Screenshots/"; @@ -1939,6 +1941,7 @@ class LunaProfile: public Luna { public: static int GetDisplayName( T* p, lua_State *L ) { lua_pushstring(L, p->m_sDisplayName ); return 1; } + static int GetLastUsedHighScoreName( T* p, lua_State *L ) { lua_pushstring(L, p->m_sLastUsedHighScoreName ); return 1; } static int GetHighScoreList( T* p, lua_State *L ) { if( LuaBinding::CheckLuaObjectType(L, 1, "Song") ) @@ -2035,6 +2038,7 @@ public: LunaProfile() { ADD_METHOD( GetDisplayName ); + ADD_METHOD( GetLastUsedHighScoreName ); ADD_METHOD( GetHighScoreList ); ADD_METHOD( GetCharacter ); ADD_METHOD( SetCharacter ); diff --git a/src/Profile.h b/src/Profile.h index 9809c68467..b351656bd0 100644 --- a/src/Profile.h +++ b/src/Profile.h @@ -1,4 +1,4 @@ -/* Profile - Player data that persists between sessions. Can be stored on a local disk or on a memory card. */ +/** @brief Profile - Player data that persists between sessions. Can be stored on a local disk or on a memory card. */ #ifndef Profile_H #define Profile_H @@ -24,19 +24,25 @@ class Character; // Current file versions extern const RString STATS_XML; -// Editable data is an INI because the default INI file association on Windows -// systems will open the ini file in an editor. The default association for -// XML will open in IE. Users have a much better chance of discovering how to -// edit this data if they don't have to fight against the file associations. +/** + * @brief The filename where one can edit their personal profile data. + * + * Editable data is an INI because the default INI file association on Windows + * systems will open the ini file in an editor. The default association for + * XML will open in IE. Users have a much better chance of discovering how to + * edit this data if they don't have to fight against the file associations. */ extern const RString EDITABLE_INI; -// The "don't share" file is something that the user should always keep private. -// They can safely share STATS_XML with STATS_XML's signature so that others -// can authenticate the STATS_XML data. However, others can't copy that data -// to their own profile for use in the game unless they also have the "don't -// share" file. DontShare contains a piece of information that we can -// construct using STATS_XML but the user can't construct using STATS_XML. -// The file contains a signature of the STATS_XML's signature. +/** + * @brief The filename containing the signature for STATS_XML's signature. + * + * + * The "don't share" file is something that the user should always keep private. + * They can safely share STATS_XML with STATS_XML's signature so that others + * can authenticate the STATS_XML data. However, others can't copy that data + * to their own profile for use in the game unless they also have the "don't + * share" file. DontShare contains a piece of information that we can + * construct using STATS_XML but the user can't construct using STATS_XML. */ extern const RString DONT_SHARE_SIG; extern const RString PUBLIC_KEY_FILE; @@ -46,6 +52,7 @@ extern const RString EDIT_COURSES_SUBDIR; extern const RString LASTGOOD_SUBDIR; // extern const RString RIVAL_SUBDIR; +/** @brief The max number of characters that can be used in a profile. */ const unsigned int PROFILE_MAX_DISPLAY_NAME_LENGTH = 32; @@ -137,7 +144,10 @@ public: map m_iNumSongsPlayedByStyle; int m_iNumSongsPlayedByDifficulty[NUM_Difficulty]; int m_iNumSongsPlayedByMeter[MAX_METER+1]; - /* This stat counts once per song, even if two players are active. */ + /** + * @brief Count the total number of songs played. + * + * This stat counts once per song, even if two players are active. */ int m_iNumTotalSongsPlayed; int m_iNumStagesPassedByPlayMode[NUM_PlayMode]; int m_iNumStagesPassedByGrade[NUM_Grade]; @@ -206,13 +216,15 @@ public: int GetNextScreenshotIndex() { return m_vScreenshots.size(); } - // Calorie Data - // Why track calories in a map, and not in a static sized array like - // Bookkeeping? The machine's clock is not guaranteed to be set correctly. - // If calorie array is in a static sized array, playing on a machine with - // a mis-set clock could wipe out all your past data. With this scheme, - // the worst that could happen is that playing on a mis-set machine will - // insert some garbage entries into the map. + /** + * @brief The basics for Calorie Data + * + * Why track calories in a map, and not in a static sized array like + * Bookkeeping? The machine's clock is not guaranteed to be set correctly. + * If calorie array is in a static sized array, playing on a machine with + * a mis-set clock could wipe out all your past data. With this scheme, + * the worst that could happen is that playing on a mis-set machine will + * insert some garbage entries into the map. */ struct Calories { Calories() { fCals = 0; } @@ -315,8 +327,10 @@ private: #endif -/* - * (c) 2001-2004 Chris Danford +/** + * @file + * @author Chris Danford (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/ProfileManager.cpp b/src/ProfileManager.cpp index cab97d0523..65db1110c7 100644 --- a/src/ProfileManager.cpp +++ b/src/ProfileManager.cpp @@ -674,9 +674,7 @@ void ProfileManager::IncrementStepsPlayCount( const Song* pSong, const Steps* pS GetMachineProfile()->IncrementStepsPlayCount( pSong, pSteps ); } -// // Course stats -// void ProfileManager::AddCourseScore( const Course* pCourse, const Trail* pTrail, PlayerNumber pn, const HighScore &hs_, int &iPersonalIndexOut, int &iMachineIndexOut ) { HighScore hs = hs_; @@ -686,7 +684,7 @@ void ProfileManager::AddCourseScore( const Course* pCourse, const Trail* pTrail, iMachineIndexOut = -1; // In event mode, set the score's name immediately to the Profile's last - // used name. If no profile last used name exists, use "EVNT". + // used name. If no profile last used name exists, use "EVNT". if( GAMESTATE->IsEventMode() ) { Profile* pProfile = GetProfile(pn); @@ -700,10 +698,7 @@ void ProfileManager::AddCourseScore( const Course* pCourse, const Trail* pTrail, hs.SetName( RANKING_TO_FILL_IN_MARKER[pn] ); } - - // // save high score - // if( IsPersistentProfile(pn) ) GetProfile(pn)->AddCourseHighScore( pCourse, pTrail, hs, iPersonalIndexOut ); if( hs.GetPercentDP() >= PREFSMAN->m_fMinPercentageForMachineCourseHighScore ) @@ -724,10 +719,7 @@ void ProfileManager::IncrementCoursePlayCount( const Course* pCourse, const Trai GetMachineProfile()->IncrementCoursePlayCount( pCourse, pTrail ); } - -// // Category stats -// void ProfileManager::AddCategoryScore( StepsType st, RankingCategory rc, PlayerNumber pn, const HighScore &hs_, int &iPersonalIndexOut, int &iMachineIndexOut ) { HighScore hs = hs_; @@ -804,7 +796,6 @@ int ProfileManager::GetNumLocalProfiles() const return g_vLocalProfile.size(); } - // lua start #include "LuaBinding.h" @@ -828,7 +819,6 @@ public: static int GetLocalProfileIDFromIndex( T* p, lua_State *L ) { lua_pushstring(L, p->GetLocalProfileIDFromIndex(IArg(1)) ); return 1; } static int GetLocalProfileIndexFromID( T* p, lua_State *L ) { lua_pushnumber(L, p->GetLocalProfileIndexFromID(SArg(1)) ); return 1; } static int GetNumLocalProfiles( T* p, lua_State *L ) { lua_pushnumber(L, p->GetNumLocalProfiles() ); return 1; } - //static int GetProfileDirectoryForPlayer( T* p, lua_State *L ) { lua_pushstring(L, m_sProfileDir[Enum::Check(L, 1)] ) return 1; } static int GetProfileDir( T* p, lua_State *L ) { lua_pushstring(L, p->GetProfileDir(Enum::Check(L, 1)) ); return 1; } static int IsSongNew( T* p, lua_State *L ) { lua_pushboolean(L, p->IsSongNew(Luna::check(L,1)) ); return 1; } @@ -843,8 +833,7 @@ public: ADD_METHOD( GetLocalProfileIDFromIndex ); ADD_METHOD( GetLocalProfileIndexFromID ); ADD_METHOD( GetNumLocalProfiles ); - //ADD_METHOD( GetProfileDirectoryForPlayer ); // uses PlayerNumber - ADD_METHOD( GetProfileDir ); // uses ProfileSlot + ADD_METHOD( GetProfileDir ); ADD_METHOD( IsSongNew ); } }; diff --git a/src/Quad.h b/src/Quad.h index ac8d89af43..e3e03012d3 100644 --- a/src/Quad.h +++ b/src/Quad.h @@ -1,23 +1,31 @@ -/* Quad - A rectangle shaped actor with color. */ +/** @brief Quad - A rectangle shaped actor with color. */ #ifndef QUAD_H #define QUAD_H #include "Sprite.h" - +/** @brief the Rectangular Actor with color. */ class Quad : public Sprite { public: + /** @brief Initialize the quad. */ Quad(); + /** + * @brief Load the quad from the specified node. + * @param pNode the node to load the quad from. + */ void LoadFromNode( const XNode* pNode ); + /** @brief Copy the quad. */ virtual Quad *Copy() const; }; #endif -/* - * (c) 2002-2003 Chris Danford +/** + * @file + * @author Chris Danford (c) 2002-2003 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/RadarValues.h b/src/RadarValues.h index c738129fc7..0d217102d3 100644 --- a/src/RadarValues.h +++ b/src/RadarValues.h @@ -1,4 +1,4 @@ -/* RadarValues - Cached song statistics. */ +/** @brief RadarValues - Cached song statistics. */ #ifndef RARAR_VALUES_H #define RARAR_VALUES_H @@ -6,11 +6,12 @@ #include "GameConstantsAndTypes.h" #include "ThemeMetric.h" +/** @brief Unknown radar values are given a default value. */ #define RADAR_VAL_UNKNOWN -1 class XNode; struct lua_State; - +/** @brief The collection of radar values. */ struct RadarValues { union Values @@ -40,12 +41,22 @@ struct RadarValues void MakeUnknown(); void Zero(); + /** + * @brief Add one set of radar values to another. + * @param other The other set of radar values to add. + * @return the new set of radar values. + */ RadarValues& operator+=( const RadarValues& other ) { FOREACH_ENUM( RadarCategory, rc ) m_Values.f[rc] += other.m_Values.f[rc]; return *this; } + /** + * @brief Determine if one set of radar values are equal to another. + * @param other The otehr set of radar values. + * @return true if the two sets are equal, false otherwise. + */ bool operator==( const RadarValues& other ) const { FOREACH_ENUM( RadarCategory, rc ) @@ -55,6 +66,11 @@ struct RadarValues } return true; } + /** + * @brief Determine if one set of radar values are not equal to another. + * @param other The otehr set of radar values. + * @return true if the two sets are not equal, false otherwise. + */ bool operator!=( const RadarValues& other ) const { return !operator==( other ); @@ -76,8 +92,10 @@ struct RadarValues #endif -/* - * (c) 2001-2004 Chris Danford +/** + * @file + * @author Chris Danford (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/RageFile.cpp b/src/RageFile.cpp index 4a56b1a66a..471e39c34e 100644 --- a/src/RageFile.cpp +++ b/src/RageFile.cpp @@ -351,6 +351,14 @@ public: return 1; } + static int ReadBytes( T* p, lua_State *L ) + { + RString string; + p->Read( string, IArg(1) ); + lua_pushstring( L, string ); + return 1; + } + static int Seek( T* p, lua_State *L ) { lua_pushinteger( L, p->Seek( IArg(1) ) ); @@ -403,6 +411,7 @@ public: ADD_METHOD( Close ); ADD_METHOD( Write ); ADD_METHOD( Read ); + ADD_METHOD( ReadBytes ); ADD_METHOD( Seek ); ADD_METHOD( Tell ); ADD_METHOD( GetLine ); diff --git a/src/RageFileManager.cpp b/src/RageFileManager.cpp index 22304916b1..deaa84bc2c 100644 --- a/src/RageFileManager.cpp +++ b/src/RageFileManager.cpp @@ -838,8 +838,8 @@ RageFileBasic *RageFileManager::OpenForWriting( const RString &sPath, int mode, * * The purpose of this is to create files in the expected place. For example, if we * have both C:/games/StepMania and C:/games/DWI loaded, and we're writing - * "Songs/Music/Waltz/waltz.sm", and the song was loaded out of - * "C:/games/DWI/Songs/Music/Waltz/waltz.dwi", we want to write the new SM into the + * "Songs/Music/Waltz/waltz.ssc", and the song was loaded out of + * "C:/games/DWI/Songs/Music/Waltz/waltz.dwi", we want to write the new SSC into the * same directory (if possible). Don't split up files in the same directory any * more than we have to. * diff --git a/src/RageInputDevice.cpp b/src/RageInputDevice.cpp index 861e38d8a2..457840428a 100644 --- a/src/RageInputDevice.cpp +++ b/src/RageInputDevice.cpp @@ -1,7 +1,5 @@ -/* - * Define all of the input devices we know about. This is the public - * interface for describing input devices. - */ +/* Define all of the input devices we know about. This is the public interface + * for describing input devices. */ #include "global.h" #include "RageInputDevice.h" @@ -106,7 +104,7 @@ static void InitNames() g_mapNamesToString[JOY_UP] = "Up1"; g_mapNamesToString[JOY_DOWN] = "Down1"; - /* Secondary sticks: */ + // Secondary sticks: g_mapNamesToString[JOY_LEFT_2] = "Left2"; g_mapNamesToString[JOY_RIGHT_2] = "Right2"; g_mapNamesToString[JOY_UP_2] = "Up2"; @@ -143,13 +141,13 @@ static void InitNames() g_mapStringToNames[m->second] = m->first; } -/* Return a reversible representation of a DeviceButton. This is not affected +/* Return a reversible representation of a DeviceButton. This is not affected * by InputDrivers, localization or the keyboard language. */ RString DeviceButtonToString( DeviceButton key ) { InitNames(); - /* All printable ASCII except for uppercase alpha characters line up. */ + // All printable ASCII except for uppercase alpha characters line up. if( key >= 33 && key < 127 && !(key >= 'A' && key <= 'Z' ) ) return ssprintf( "%c", key ); @@ -194,7 +192,6 @@ DeviceButton StringToDeviceButton( const RString& s ) return DeviceButton_Invalid; } - static const char *InputDeviceNames[] = { "Key", "Joy1", @@ -237,7 +234,7 @@ static const char *InputDeviceNames[] = { XToString( InputDevice ); StringToX( InputDevice ); -/* Return a reversible representation of a DeviceInput. This is not affected by +/* Return a reversible representation of a DeviceInput. This is not affected by * InputDrivers, localization or the keyboard language. */ RString DeviceInput::ToString() const { diff --git a/src/RageInputDevice.h b/src/RageInputDevice.h index 4aa17f01b7..58e89c2b01 100644 --- a/src/RageInputDevice.h +++ b/src/RageInputDevice.h @@ -57,7 +57,6 @@ inline bool IsJoystick( InputDevice id ) { return DEVICE_JOY1 <= id && id < DEVI inline bool IsPump( InputDevice id ) { return DEVICE_PUMP1 <= id && id < DEVICE_PUMP1+NUM_PUMPS; } //inline bool IsMouse( InputDevice id ) { return id == DEVICE_MOUSE; } - struct InputDeviceInfo { InputDeviceInfo( InputDevice id_, RString sDesc_ ) @@ -76,7 +75,6 @@ struct InputDeviceInfo } }; - enum InputDeviceState { InputDeviceState_Connected, // has an InputHandler and controller is plugged in @@ -88,11 +86,10 @@ enum InputDeviceState }; const RString& InputDeviceStateToString( InputDeviceState ids ); - -/* Only raw, unshifted keys go in this table; this doesn't include internationalized - * keyboards, only keys that we might actually want to test for programmatically. Any - * other keys are mapped to KEY_OTHER_0 and up. (If we want to support real international - * input, stick a wchar_t in DeviceInput.) */ +/* Only raw, unshifted keys go in this table; this doesn't include + * internationalized keyboards, only keys that we might actually want to test + * for programmatically. Any other keys are mapped to KEY_OTHER_0 and up. (If we + * want to support real international input, stick a wchar_t in DeviceInput.) */ enum DeviceButton { @@ -262,17 +259,17 @@ enum DeviceButton KEY_KP_ENTER, KEY_OTHER_0, - /* ... */ + // ... KEY_LAST_OTHER=511, - /* Joystick inputs. We try to have enough input names so any input on a reasonable - * joystick has an obvious mapping, but keep it generic and don't try to handle odd - * special cases. For example, many controllers have two sticks, so the JOY_LEFT_2, etc. - * pairs are useful for many types of sticks. */ - /* Standard axis: */ + /* Joystick inputs. We try to have enough input names so any input on a + * reasonable joystick has an obvious mapping, but keep it generic and don't + * try to handle odd special cases. For example, many controllers have two + * sticks, so the JOY_LEFT_2, etc. pairs are useful for many types of sticks. */ + // Standard axis: JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN, - /* Secondary sticks: */ + // Secondary sticks: JOY_LEFT_2, JOY_RIGHT_2, JOY_UP_2, JOY_DOWN_2, JOY_Z_UP, JOY_Z_DOWN, @@ -280,7 +277,7 @@ enum DeviceButton JOY_HAT_LEFT, JOY_HAT_RIGHT, JOY_HAT_UP, JOY_HAT_DOWN, JOY_AUX_1, JOY_AUX_2, JOY_AUX_3, JOY_AUX_4, - /* Buttons: */ + // Buttons: JOY_BUTTON_1, JOY_BUTTON_2, JOY_BUTTON_3, JOY_BUTTON_4, JOY_BUTTON_5, JOY_BUTTON_6, JOY_BUTTON_7, JOY_BUTTON_8, JOY_BUTTON_9, JOY_BUTTON_10, JOY_BUTTON_11, JOY_BUTTON_12, JOY_BUTTON_13, JOY_BUTTON_14, JOY_BUTTON_15, @@ -292,15 +289,15 @@ enum DeviceButton MIDI_FIRST = 600, MIDI_LAST = 699, - /* Mouse: */ + // Mouse: /* MOUSE_LEFT = 700, MOUSE_RIGHT, MOUSE_MIDDLE, - MOUSE_FORWARD, // for mice with forward and backwards buttons - MOUSE_BACK, - MOUSE_WHEELUP, // wheel mice - MOUSE_WHEELDOWN, + // wheel mice + MOUSE_WHEELUP, MOUSE_WHEELDOWN, + // for mice with forward and backwards buttons + MOUSE_FORWARD, MOUSE_BACK, */ NUM_DeviceButton, @@ -316,12 +313,12 @@ public: InputDevice device; DeviceButton button; - /* This is usually 0 or 1. Analog joystick inputs can set this to a percentage (0..1). - * This should be 0 for analog axes within the dead zone. */ + /* This is usually 0 or 1. Analog joystick inputs can set this to a percentage + * (0..1). This should be 0 for analog axes within the dead zone. */ float level; - /* Whether this button is pressed. This is level with a threshold and debouncing - * applied. */ + /* Whether this button is pressed. This is level with a threshold and + * debouncing applied. */ bool bDown; RageTimer ts; @@ -333,8 +330,8 @@ public: bool operator==( const DeviceInput &other ) const { - /* Return true if we represent the same button on the same device. Don't - * compare level or ts. */ + /* Return true if we represent the same button on the same device. + * Don't compare level or ts. */ return device == other.device && button == other.button; } bool operator!=( const DeviceInput &other ) const @@ -343,8 +340,8 @@ public: } bool operator<( const DeviceInput &other ) const { - /* Return true if we represent the same button on the same device. Don't - * compare level or ts. */ + /* Return true if we represent the same button on the same device. + * Don't compare level or ts. */ if( device != other.device ) return device < other.device; return button < other.button; @@ -357,6 +354,7 @@ public: void MakeInvalid() { device = InputDevice_Invalid; }; bool IsJoystick() const { return ::IsJoystick(device); } + //bool IsMouse() const { return ::IsMouse(device); } }; typedef vector DeviceInputList; diff --git a/src/RageUtil.h b/src/RageUtil.h index f5eb111326..eb489e50ca 100644 --- a/src/RageUtil.h +++ b/src/RageUtil.h @@ -1,4 +1,4 @@ -/* RageUtil - Miscellaneous helper macros and functions. */ +/** @brief RageUtil - Miscellaneous helper macros and functions. */ #ifndef RAGE_UTIL_H #define RAGE_UTIL_H @@ -7,12 +7,16 @@ #include class RageFileDriver; +/** @brief Safely delete pointers. */ #define SAFE_DELETE(p) do { delete (p); (p)=NULL; } while( false ) +/** @brief Safely delete array pointers. */ #define SAFE_DELETE_ARRAY(p) do { delete[] (p); (p)=NULL; } while( false ) +/** @brief Zero out the memory. */ #define ZERO(x) memset(&(x), 0, sizeof(x)) +/** @brief Copy from a to b. */ #define COPY(a,b) do { ASSERT(sizeof(a)==sizeof(b)); memcpy(&(a), &(b), sizeof(a)); } while( false ) - +/** @brief Get the length of the array. */ #define ARRAYLEN(a) (sizeof(a) / sizeof((a)[0])) /* Common harmless mismatches. All min(T,T) and max(T,T) cases are handled @@ -26,13 +30,19 @@ inline unsigned long min( unsigned long a, unsigned int b ) { return a < b? a:b; inline unsigned long max( unsigned int a, unsigned long b ) { return a > b? a:b; } inline unsigned long max( unsigned long a, unsigned int b ) { return a > b? a:b; } +/** @brief If outside the range from low to high, bring it within range. */ #define clamp(val,low,high) ( max( (low), min((val),(high)) ) ) -// Scales x so that l1 corresponds to l2 and h1 corresponds to h2. Does not modify x, MUST assign the result to something! -// Do the multiply before the divide to that integer scales have more precision. +/** + * @brief Scales x so that l1 corresponds to l2 and h1 corresponds to h2. + * + * This does not modify x, so it MUST assign the result to something! + * Do the multiply before the divide to that integer scales have more precision. + * + * One such example: SCALE(x, 0, 1, L, H); interpolate between L and H. + */ #define SCALE(x, l1, h1, l2, h2) (((x) - (l1)) * ((h2) - (l2)) / ((h1) - (l1)) + (l2)) -// Like SCALE(x, 0, 1, L, H); interpolate between L and H. template inline U lerp( T x, U l, U h ) { @@ -259,14 +269,21 @@ typedef MersenneTwister RandomGen; extern RandomGen g_RandomNumberGenerator; -// [0.0f,1.0f) +/** + * @brief Generate a random float between 0 inclusive and 1 exclusive. + * @return the random float. + */ inline float RandomFloat() { return g_RandomNumberGenerator() / 2147483648.0f; } - -// Returns a float between dLow and dHigh inclusive +/** + * @brief Return a float between the low and high values. + * @param fLow the low value, inclusive. + * @param fHigh the high value, inclusive. + * @return the random float. + */ inline float RandomFloat( float fLow, float fHigh ) { return SCALE( RandomFloat(), 0.0f, 1.0f, fLow, fHigh ); @@ -639,8 +656,10 @@ void GetConnectsDisconnects( const vector &before, const vector &after, ve #endif -/* - * Copyright (c) 2001-2005 Chris Danford, Glenn Maynard +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2005 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/RoomWheel.cpp b/src/RoomWheel.cpp index 72341d5510..77d9087676 100644 --- a/src/RoomWheel.cpp +++ b/src/RoomWheel.cpp @@ -12,15 +12,6 @@ AutoScreenMessage( SM_BackFromRoomName ) AutoScreenMessage( SM_RoomInfoRetract ) AutoScreenMessage( SM_RoomInfoDeploy ) -ThemeMetric TEXT_X; -ThemeMetric TEXT_Y; -ThemeMetric TEXT_WIDTH; -ThemeMetric TEXT_ON_COMMAND; - -ThemeMetric DESC_X; -ThemeMetric DESC_Y; -ThemeMetric DESC_WIDTH; - RoomWheel::~RoomWheel() { FOREACH( WheelItemBaseData*, m_CurWheelItemData, i ) @@ -56,6 +47,7 @@ RoomWheelItem::RoomWheelItem( const RoomWheelItem &cpy ): WheelItemBase( cpy ), m_sprNormalPart( cpy.m_sprNormalPart ), m_sprColorPart( cpy.m_sprColorPart ), + m_sprOverPart( cpy.m_sprOverPart ), m_text( cpy.m_text ), m_Desc( cpy.m_Desc ) { @@ -63,6 +55,7 @@ RoomWheelItem::RoomWheelItem( const RoomWheelItem &cpy ): { this->AddChild( m_sprNormalPart ); this->AddChild( m_sprColorPart ); + this->AddChild( m_sprOverPart ); this->AddChild( &m_text ); this->AddChild( &m_Desc ); } @@ -70,7 +63,6 @@ RoomWheelItem::RoomWheelItem( const RoomWheelItem &cpy ): void RoomWheelItem::Load( RString sType ) { - // colorpart gets added first in MusicWheelItem, so follow that here. m_sprColorPart.Load( THEME->GetPathG(sType,"ColorPart") ); this->AddChild( m_sprColorPart ); @@ -78,34 +70,18 @@ void RoomWheelItem::Load( RString sType ) m_sprNormalPart.Load( THEME->GetPathG(sType,"NormalPart") ); this->AddChild( m_sprNormalPart ); - TEXT_X .Load(sType,"TextX"); - TEXT_Y .Load(sType,"TextY"); - TEXT_ON_COMMAND .Load(sType,"TextOnCommand"); - TEXT_WIDTH .Load(sType,"TextWidth"); - + m_text.SetName( "Text" ); m_text.LoadFromFont( THEME->GetPathF(sType,"text") ); - //m_text.SetShadowLength( 0 ); - m_text.SetXY( TEXT_X, TEXT_Y ); - m_text.RunCommands( TEXT_ON_COMMAND ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_text ); this->AddChild( &m_text ); - m_text.SetHorizAlign( align_left ); - m_text.SetMaxWidth(TEXT_WIDTH); - /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ - - DESC_X .Load(sType,"DescX"); - DESC_Y .Load(sType,"DescY"); - DESC_WIDTH .Load(sType,"DescWidth"); - - m_Desc.SetName( "Desc" ); - ActorUtil::LoadAllCommands( m_Desc, "RoomWheelItem" ); + m_Desc.SetName( "Description" ); m_Desc.LoadFromFont( THEME->GetPathF("RoomWheel","text") ); - m_Desc.SetHorizAlign( align_left ); - m_Desc.SetShadowLength( 0 ); - m_Desc.SetMaxWidth( DESC_WIDTH ); - m_Desc.SetXY( DESC_X, DESC_Y); - m_Desc.PlayCommand( "On" ); + LOAD_ALL_COMMANDS_AND_SET_XY( m_Desc ); this->AddChild( &m_Desc ); + + m_sprOverPart.Load( THEME->GetPathG(sType,"OverPart") ); + this->AddChild( m_sprOverPart ); } void RoomWheel::BuildWheelItemsData( vector &arrayWheelItemDatas ) @@ -164,7 +140,6 @@ void RoomWheel::RemoveItem( int index ) RebuildWheelItems(); } - static LocalizedString ENTER_ROOM_NAME( "RoomWheel", "Enter room name" ); bool RoomWheel::Select() { @@ -217,7 +192,6 @@ unsigned int RoomWheel::GetNumItems() const return m_CurWheelItemData.size() - m_offset; } - /* * (c) 2004 Josh Allen * All rights reserved. diff --git a/src/RoomWheel.h b/src/RoomWheel.h index e32a60ede1..9d0d690fd9 100644 --- a/src/RoomWheel.h +++ b/src/RoomWheel.h @@ -30,6 +30,7 @@ public: private: AutoActor m_sprNormalPart; AutoActor m_sprColorPart; + AutoActor m_sprOverPart; BitmapText m_text; BitmapText m_Desc; }; diff --git a/src/ScoreKeeper.h b/src/ScoreKeeper.h index c3fca1d813..3accf2e6fa 100644 --- a/src/ScoreKeeper.h +++ b/src/ScoreKeeper.h @@ -1,4 +1,4 @@ -/* ScoreKeeper - Abstract class to handle scorekeeping, stat-taking, etc. */ +/** @brief ScoreKeeper - Abstract class to handle scorekeeping, stat-taking, etc. */ #ifndef SCORE_KEEPER_H #define SCORE_KEEPER_H @@ -65,8 +65,10 @@ protected: #endif -/* - * (c) 2001-2006 Chris Danford, Glenn Maynard, Steve Checkoway +/** + * @file + * @author Chris Danford, Glenn Maynard, Steve Checkoway (c) 2001-2006 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/Screen.cpp b/src/Screen.cpp index 7b997ece81..2993e684d0 100644 --- a/src/Screen.cpp +++ b/src/Screen.cpp @@ -42,6 +42,7 @@ bool Screen::SortMessagesByDelayRemaining( const Screen::QueuedScreenMessage &m1 void Screen::Init() { ALLOW_OPERATOR_MENU_BUTTON.Load( m_sName, "AllowOperatorMenuButton" ); + HANDLE_BACK_BUTTON.Load( m_sName, "HandleBackButton" ); REPEAT_RATE.Load( m_sName, "RepeatRate" ); REPEAT_DELAY.Load( m_sName, "RepeatDelay" ); LIGHTS_MODE.Load( m_sName, "LightsMode" ); @@ -81,16 +82,16 @@ void Screen::BeginScreen() m_bRunning = true; m_bFirstUpdate = true; - /* Screens set these when they determine their next screen dynamically. Reset them + /* Screens set these when they determine their next screen dynamically. Reset them * here, so a reused screen doesn't inherit these from the last time it was used. */ m_sNextScreen = RString(); - + m_fLockInputSecs = 0; this->RunCommands( THEME->GetMetricA(m_sName, "ScreenOnCommand") ); if( m_fLockInputSecs == 0 ) - m_fLockInputSecs = 0.0001f; // always lock for a tiny amount of time so that we throw away any queued inputs during the load. + m_fLockInputSecs = 0.0001f; // always lock for a tiny amount of time so that we throw away any queued inputs during the load. this->PlayCommand( "Begin" ); } @@ -107,33 +108,28 @@ void Screen::Update( float fDeltaTime ) m_fLockInputSecs = max( 0, m_fLockInputSecs-fDeltaTime ); - /* - * We need to ensure two things: - * 1. Messages must be sent in the order of delay. If two messages are sent - * simultaneously, one with a .001 delay and another with a .002 delay, the - * .001 delay message must be sent first. + /* We need to ensure two things: + * 1. Messages must be sent in the order of delay. If two messages are sent + * simultaneously, one with a .001 delay and another with a .002 delay, + * the .001 delay message must be sent first. * 2. Messages to be delivered simultaneously must be sent in the order queued. * - * Sort by time to ensure #1; use a stable sort to ensure #2. - */ + * Sort by time to ensure #1; use a stable sort to ensure #2. */ stable_sort(m_QueuedMessages.begin(), m_QueuedMessages.end(), SortMessagesByDelayRemaining); - /* Update the times of queued ScreenMessages. */ + // Update the times of queued ScreenMessages. for( unsigned i=0; i 0.0001f ) { m_QueuedMessages[i].fDelayRemaining -= fDeltaTime; @@ -145,8 +141,8 @@ void Screen::Update( float fDeltaTime ) } } - /* Now dispatch messages. If the number of messages on the queue changes - * within HandleScreenMessage, someone cleared messages on the queue. This + /* Now dispatch messages. If the number of messages on the queue changes + * within HandleScreenMessage, someone cleared messages on the queue. This * means we have no idea where 'i' is, so start over. Since we applied time * already, this won't cause messages to be mistimed. */ for( unsigned i=0; i 0.0f ) continue; /* not yet */ - /* Remove the message from the list. */ + // Remove the message from the list. const ScreenMessage SM = m_QueuedMessages[i].SM; m_QueuedMessages.erase( m_QueuedMessages.begin()+i ); i--; @@ -171,10 +167,10 @@ void Screen::Update( float fDeltaTime ) } } -/* ScreenManager sends input here first. Overlay screens can use it to get a first - * pass at input. Return true if the input was handled and should not be passed - * to lower screens, or false if not handled. If true is returned, Input() will - * not be called, either. Normal screens should not overload this function. */ +/* ScreenManager sends input here first. Overlay screens can use it to get a first + * pass at input. Return true if the input was handled and should not be passed + * to lower screens, or false if not handled. If true is returned, Input() will + * not be called, either. Normal screens should not overload this function. */ bool Screen::OverlayInput( const InputEventPlus &input ) { return false; @@ -206,10 +202,13 @@ void Screen::Input( const InputEventPlus &input ) case GAME_BUTTON_MENUDOWN: this->MenuDown ( input ); return; case GAME_BUTTON_MENULEFT: this->MenuLeft ( input ); return; case GAME_BUTTON_MENURIGHT: this->MenuRight ( input ); return; - case GAME_BUTTON_BACK: + case GAME_BUTTON_BACK: // Don't make the user hold the back button if they're pressing escape and escape is the back button. if( !PREFSMAN->m_bDelayedBack || input.type==IET_REPEAT || (input.DeviceI.device == DEVICE_KEYBOARD && input.DeviceI.button == KEY_ESC) ) - this->MenuBack( input ); + { + if( HANDLE_BACK_BUTTON ) + this->MenuBack( input ); + } return; case GAME_BUTTON_START: this->MenuStart ( input ); return; case GAME_BUTTON_SELECT:this->MenuSelect( input ); return; @@ -250,6 +249,8 @@ RString Screen::GetNextScreenName() const RString Screen::GetPrevScreen() const { + if( !m_sPrevScreen.empty() ) + return m_sPrevScreen; return PREV_SCREEN; } diff --git a/src/Screen.h b/src/Screen.h index d8441adae4..837d4114c5 100644 --- a/src/Screen.h +++ b/src/Screen.h @@ -80,12 +80,14 @@ protected: InputQueueCodeSet m_Codes; ThemeMetric ALLOW_OPERATOR_MENU_BUTTON; + ThemeMetric HANDLE_BACK_BUTTON; ThemeMetric REPEAT_RATE; ThemeMetric REPEAT_DELAY; ThemeMetric LIGHTS_MODE; // If left blank, the NextScreen metric will be used. RString m_sNextScreen; + RString m_sPrevScreen; ScreenMessage m_smSendOnPop; float m_fLockInputSecs; diff --git a/src/ScreenAttract.cpp b/src/ScreenAttract.cpp index b5e426edb7..cd65b9bc3f 100644 --- a/src/ScreenAttract.cpp +++ b/src/ScreenAttract.cpp @@ -50,13 +50,13 @@ void ScreenAttract::SetAttractVolume( bool bInAttract ) if( bInAttract ) { if( GAMESTATE->IsTimeToPlayAttractSounds() ) - SOUNDMAN->SetVolumeOfNonCriticalSounds( g_fSoundVolumeAttract ); // unmute attract sounds + SOUNDMAN->SetVolumeOfNonCriticalSounds( g_fSoundVolumeAttract ); // unmute attract sounds else - SOUNDMAN->SetVolumeOfNonCriticalSounds( 0.0f ); // mute attract sounds + SOUNDMAN->SetVolumeOfNonCriticalSounds( 0.0f ); // mute attract sounds } else { - SOUNDMAN->SetVolumeOfNonCriticalSounds( 1.0f ); // unmute all sounds + SOUNDMAN->SetVolumeOfNonCriticalSounds( 1.0f ); // unmute all sounds } } @@ -93,7 +93,7 @@ void ScreenAttract::AttractInput( const InputEventPlus &input, ScreenWithMenuEle if( pScreen->IsTransitioning() ) return; - /* HandleGlobalInputs() already played the coin sound. Don't play it again. */ + // HandleGlobalInputs() already played the coin sound. Don't play it again. if( input.MenuI != GAME_BUTTON_COIN ) SCREENMAN->PlayStartSound(); @@ -138,9 +138,10 @@ void ScreenAttract::HandleScreenMessage( const ScreenMessage SM ) } else if( SM == SM_GoToNextScreen ) { - /* Look at the def of the screen we're going to; if it has a music theme element - * and it's the same as the one we're playing now, don't stop. However, if we're - * going to interrupt it when we fade in, stop the old music before we fade out. */ + /* Look at the def of the screen we're going to; if it has a music theme + * element and it's the same as the one we're playing now, don't stop. + * However, if we're going to interrupt it when we fade in, stop the old + * music before we fade out. */ bool bMusicChanging = false; if( PLAY_MUSIC ) bMusicChanging = THEME->GetPathS(m_sName,"music") != THEME->GetPathS(GetNextScreenName(),"music",true); // GetPath optional on the next screen because it may not have music. @@ -161,7 +162,6 @@ void ScreenAttract::GoToStartScreen( RString sScreenName ) SCREENMAN->SetNewScreen( START_SCREEN(sScreenName) ); } - // lua start #include "LuaBinding.h" diff --git a/src/ScreenAttract.h b/src/ScreenAttract.h index 19ead8bd66..68a2837836 100644 --- a/src/ScreenAttract.h +++ b/src/ScreenAttract.h @@ -16,16 +16,14 @@ public: static void AttractInput( const InputEventPlus &input, ScreenWithMenuElements *pScreen ); static void GoToStartScreen( RString sScreenName ); static void SetAttractVolume( bool bInAttract ); - + virtual void Input( const InputEventPlus &input ); virtual void HandleScreenMessage( const ScreenMessage SM ); virtual void Cancel( ScreenMessage smSendWhenDone ); virtual ScreenType GetScreenType() const { return attract; } - // // Lua - // virtual void PushSelf( lua_State *L ); protected: @@ -34,7 +32,6 @@ protected: ThemeMetric ATTRACT_VOLUME; }; - #endif /* diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index ecede280c6..f2e2594e6c 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -33,6 +33,7 @@ #include "Style.h" #include "ThemeManager.h" #include "ThemeMetric.h" +#include "TimingData.h" #include "Game.h" #include "RageSoundReader.h" @@ -56,10 +57,6 @@ const float RECORD_HOLD_SECONDS = 0.3f; #define PLAY_RECORD_HELP_TEXT THEME->GetString(m_sName,"PlayRecordHelpText") #define EDIT_HELP_TEXT THEME->GetString(m_sName,"EditHelpText") -// FIXME: Remove hard-coded beat values and instead look at the time signature in the song. -static const int BEATS_PER_MEASURE = 4; -static const int ROWS_PER_MEASURE = ROWS_PER_BEAT * BEATS_PER_MEASURE; - AutoScreenMessage( SM_UpdateTextInfo ); AutoScreenMessage( SM_BackFromMainMenu ); AutoScreenMessage( SM_BackFromAreaMenu ); @@ -74,9 +71,13 @@ AutoScreenMessage( SM_BackFromInsertCourseAttackPlayerOptions ); AutoScreenMessage( SM_BackFromCourseModeMenu ); AutoScreenMessage( SM_DoRevertToLastSave ); AutoScreenMessage( SM_DoRevertFromDisk ); +AutoScreenMessage( SM_BackFromTimingDataInformation ); AutoScreenMessage( SM_BackFromBPMChange ); AutoScreenMessage( SM_BackFromStopChange ); AutoScreenMessage( SM_BackFromDelayChange ); +AutoScreenMessage( SM_BackFromTimeSignatureNumeratorChange ); +AutoScreenMessage( SM_BackFromTimeSignatureDenominatorChange ); +AutoScreenMessage( SM_BackFromTickcountChange ); AutoScreenMessage( SM_DoSaveAndExit ); AutoScreenMessage( SM_DoExit ); AutoScreenMessage( SM_SaveSuccessful ); @@ -89,6 +90,7 @@ static const char *EditStateNames[] = { "Playing" }; XToString( EditState ); +LuaXType( EditState ); #if defined(XBOX) void ScreenEdit::InitEditMappings() @@ -141,7 +143,9 @@ void ScreenEdit::InitEditMappings() } m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_UP_PAGE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PGUP); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_UP_PAGE][1] = DeviceInput(DEVICE_KEYBOARD, KEY_SEMICOLON); m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_DOWN_PAGE][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PGDN); + m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_DOWN_PAGE][1] = DeviceInput(DEVICE_KEYBOARD, KEY_SQUOTE); 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); @@ -504,9 +508,7 @@ static MenuDef g_MainMenu( 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_bpm, "Edit BPM change", true, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::edit_stop, "Edit stop", true, EditMode_Full, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::edit_delay, "Edit delay", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::edit_timing_data, "Edit Timing Data", true, EditMode_Full, 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 ) ); @@ -540,6 +542,7 @@ static MenuDef g_StepsInformation( // xxx: this giant list of numbers SUUUUUUUUUUCKS -aj MenuRowDef( ScreenEdit::meter, "Meter", true, EditMode_Practice, true, false, 0, "1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25" ), MenuRowDef( ScreenEdit::description, "Description", 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 ), @@ -567,6 +570,16 @@ static MenuDef g_SongInformation( MenuRowDef( ScreenEdit::last_beat_hint, "Last beat hint", true, EditMode_Full, true, true, 0, NULL ) ); +static MenuDef g_TimingDataInformation( + "ScreenMiniMenuTimingDataInformation", + MenuRowDef( ScreenEdit::bpm, "Edit BPM change", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::stop, "Edit stop", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::delay, "Edit delay", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::time_signature_numerator, "Edit time signature (top)", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::time_signature_denominator, "Edit time signature (bottom)", true, EditMode_Full, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::tickcount, "Edit tickcount", true, EditMode_Full, true, true, 0, NULL ) +); + enum { song_bganimation, song_movie, song_bitmap, global_bganimation, global_movie, global_movie_song_group, global_movie_song_group_and_genre, dynamic_random, baked_random, none }; static bool EnabledIfSet1SongBGAnimation(); static bool EnabledIfSet1SongMovie(); @@ -1196,7 +1209,8 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) m_iShiftAnchor = -1; return; } - + int beatsPerMeasure = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iNumerator; + switch( EditB ) { case EDIT_BUTTON_COLUMN_0: @@ -1345,7 +1359,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) break; case EDIT_BUTTON_SCROLL_UP_PAGE: case EDIT_BUTTON_SCROLL_DOWN_PAGE: - fBeatsToMove = BEATS_PER_MEASURE; + fBeatsToMove = beatsPerMeasure; if( EditB == EDIT_BUTTON_SCROLL_UP_PAGE ) fBeatsToMove *= -1; break; @@ -1362,15 +1376,15 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) break; case EDIT_BUTTON_SCROLL_NEXT_MEASURE: { - float fDestinationBeat = GAMESTATE->m_fSongBeat + BEATS_PER_MEASURE; - fDestinationBeat = ftruncf( fDestinationBeat, (float)BEATS_PER_MEASURE ); + float fDestinationBeat = GAMESTATE->m_fSongBeat + beatsPerMeasure; + fDestinationBeat = ftruncf( fDestinationBeat, (float)beatsPerMeasure ); ScrollTo( fDestinationBeat ); break; } case EDIT_BUTTON_SCROLL_PREV_MEASURE: { - float fDestinationBeat = QuantizeUp( GAMESTATE->m_fSongBeat, (float)BEATS_PER_MEASURE ); - fDestinationBeat -= (float)BEATS_PER_MEASURE; + float fDestinationBeat = QuantizeUp( GAMESTATE->m_fSongBeat, (float)beatsPerMeasure ); + fDestinationBeat -= (float)beatsPerMeasure; ScrollTo( fDestinationBeat ); break; } @@ -2550,6 +2564,10 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) { HandleSongInformationChoice( (SongInformationChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers ); } + else if( SM == SM_BackFromTimingDataInformation ) + { + HandleTimingDataInformationChoice( (TimingDataInformationChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers ); + } else if( SM == SM_BackFromBPMChange ) { float fBPM = StringToFloat( ScreenTextEntry::s_sLastAnswer ); @@ -2571,6 +2589,33 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) m_pSong->m_Timing.SetStopAtBeat( GAMESTATE->m_fSongBeat, fDelay, true ); SetDirty( true ); } + else if( SM == SM_BackFromTimeSignatureNumeratorChange ) + { + int iNum = atoi( ScreenTextEntry::s_sLastAnswer ); + if( iNum > 0 ) + { + m_pSong->m_Timing.SetTimeSignatureNumeratorAtBeat( GAMESTATE->m_fSongBeat, iNum ); + } + SetDirty( true ); + } + else if ( SM == SM_BackFromTimeSignatureDenominatorChange ) + { + int iDen = atoi( ScreenTextEntry::s_sLastAnswer ); + if( iDen > 0) + { + m_pSong->m_Timing.SetTimeSignatureDenominatorAtBeat( GAMESTATE->m_fSongBeat, iDen ); + } + SetDirty( true ); + } + else if ( SM == SM_BackFromTickcountChange ) + { + int iTick = atoi( ScreenTextEntry::s_sLastAnswer ); + if ( iTick >= 1 && iTick <= ROWS_PER_BEAT ) + { + m_pSong->m_Timing.SetTickcountAtBeat( GAMESTATE->m_fSongBeat, iTick ); + } + SetDirty( true ); + } else if( SM == SM_BackFromBGChange ) { HandleBGChangeChoice( (BGChangeChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers ); @@ -2818,6 +2863,12 @@ static void ChangeDescription( const RString &sNew ) pSteps->SetDescription(sNew); } +static void ChangeStepCredit( const RString &sNew ) +{ + Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; + pSteps->SetCredit(sNew); +} + static void ChangeMainTitle( const RString &sNew ) { Song* pSong = GAMESTATE->m_pCurSong; @@ -2877,9 +2928,7 @@ static LocalizedString REVERT_LAST_SAVE ( "ScreenEdit", "Do you want to revert static LocalizedString DESTROY_ALL_UNSAVED_CHANGES ( "ScreenEdit", "This will destroy all unsaved changes." ); static LocalizedString REVERT_FROM_DISK ( "ScreenEdit", "Do you want to revert from disk?" ); static LocalizedString SAVE_CHANGES_BEFORE_EXITING ( "ScreenEdit", "Do you want to save changes before exiting?" ); -static LocalizedString ENTER_BPM_VALUE ( "ScreenEdit", "Enter a new BPM value." ); -static LocalizedString ENTER_STOP_VALUE ( "ScreenEdit", "Enter a new Stop value." ); -static LocalizedString ENTER_DELAY_VALUE ( "ScreenEdit", "Enter a new Delay value." ); + void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAnswers ) { switch( c ) @@ -2961,6 +3010,8 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns g_StepsInformation.rows[predict_meter].SetOneUnthemedChoice( ssprintf("%.2f",pSteps->PredictMeter()) ); g_StepsInformation.rows[description].bEnabled = (EDIT_MODE.GetValue() >= EditMode_Full); g_StepsInformation.rows[description].SetOneUnthemedChoice( pSteps->GetDescription() ); + 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()) ); @@ -3064,34 +3115,22 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns EditMiniMenu( &g_SongInformation, SM_BackFromSongInformation ); } break; - case edit_bpm: - // todo: Call a screen with class ScreenTextEntry instead. -aj - ScreenTextEntry::TextEntry( - SM_BackFromBPMChange, - ENTER_BPM_VALUE, - ssprintf( "%.4f", m_pSong->GetBPMAtBeat(GAMESTATE->m_fSongBeat) ), - 10 - ); - break; - case edit_stop: - // todo: Call a screen with class ScreenTextEntry instead. -aj - bool bThrowaway; // is it? - ScreenTextEntry::TextEntry( - SM_BackFromStopChange, - ENTER_STOP_VALUE, - ssprintf( "%.4f", m_pSong->m_Timing.GetStopAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat), bThrowaway ) ), - 10 - ); - break; - case edit_delay: - // todo: Call a screen with class ScreenTextEntry instead. -aj - ScreenTextEntry::TextEntry( - SM_BackFromDelayChange, - ENTER_DELAY_VALUE, - ssprintf( "%.4f", m_pSong->m_Timing.GetStopAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat), bThrowaway ) ), - 10 - ); + case edit_timing_data: + { + const Song* pSong = GAMESTATE->m_pCurSong; + TimingData pTime = pSong->m_Timing; + const float fBeat = GAMESTATE->m_fSongBeat; + g_TimingDataInformation.rows[bpm].SetOneUnthemedChoice( ssprintf("%.5f", pSong->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_numerator].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTimeSignatureNumeratorAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[time_signature_denominator].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTimeSignatureDenominatorAtBeat( fBeat ) ) ); + g_TimingDataInformation.rows[tickcount].SetOneUnthemedChoice( ssprintf("%d", pTime.GetTickcountAtBeat( fBeat ) ) ); + + EditMiniMenu( &g_TimingDataInformation, SM_BackFromTimingDataInformation ); + } break; + case play_preview_music: PlayPreviewMusic(); break; @@ -3415,8 +3454,8 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns } case convert_pause_to_beat: { - bool bThrowaway; // is it? - float fStopSeconds = m_pSong->m_Timing.GetStopAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat), bThrowaway ); + // TODO: Convert both Delays and Stops at once. + float fStopSeconds = m_pSong->m_Timing.GetStopAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ); m_pSong->m_Timing.SetStopAtBeat( GAMESTATE->m_fSongBeat, 0 ); float fStopBeats = fStopSeconds * m_pSong->GetBPMAtBeat(GAMESTATE->m_fSongBeat) / 60; @@ -3436,6 +3475,7 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns } static LocalizedString ENTER_NEW_DESCRIPTION( "ScreenEdit", "Enter a new description." ); +static LocalizedString ENTER_NEW_STEP_AUTHOR( "ScreenEdit", "Enter the author who made this step pattern." ); void ScreenEdit::HandleStepsInformationChoice( StepsInformationChoice c, const vector &iAnswers ) { Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; @@ -3458,6 +3498,17 @@ void ScreenEdit::HandleStepsInformationChoice( StepsInformationChoice c, const v NULL ); break; + case step_credit: + ScreenTextEntry::TextEntry( + SM_None, + ENTER_NEW_STEP_AUTHOR, + m_pSteps->GetCredit(), + 255, + SongUtil::ValidateCurrentStepsCredit, + ChangeStepCredit, + NULL + ); + break; } } @@ -3508,6 +3559,71 @@ void ScreenEdit::HandleSongInformationChoice( SongInformationChoice c, const vec }; } +static LocalizedString ENTER_BPM_VALUE ( "ScreenEdit", "Enter a new BPM value." ); +static LocalizedString ENTER_STOP_VALUE ( "ScreenEdit", "Enter a new Stop value." ); +static LocalizedString ENTER_DELAY_VALUE ( "ScreenEdit", "Enter a new Delay value." ); +static LocalizedString ENTER_TIME_SIGNATURE_NUMERATOR_VALUE ( "ScreenEdit", "Enter a new Time Signature numerator value." ); +static LocalizedString ENTER_TIME_SIGNATURE_DENOMINATOR_VALUE ( "ScreenEdit", "Enter a new Time Signature denominator value." ); +static LocalizedString ENTER_TICKCOUNT_VALUE ( "ScreenEdit", "Enter a new Tickcount value." ); +void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice c, const vector &iAnswers ) +{ + switch( c ) + { + DEFAULT_FAIL( c ); + case bpm: + // todo: Call a screen with class ScreenTextEntry instead. -aj + ScreenTextEntry::TextEntry( + SM_BackFromBPMChange, + ENTER_BPM_VALUE, + ssprintf( "%.4f", m_pSong->GetBPMAtBeat(GAMESTATE->m_fSongBeat) ), + 10 + ); + break; + case stop: + // todo: Call a screen with class ScreenTextEntry instead. -aj + ScreenTextEntry::TextEntry( + SM_BackFromStopChange, + ENTER_STOP_VALUE, + ssprintf( "%.4f", m_pSong->m_Timing.GetStopAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ) ), + 10 + ); + break; + case delay: + // todo: Call a screen with class ScreenTextEntry instead. -aj + ScreenTextEntry::TextEntry( + SM_BackFromDelayChange, + ENTER_DELAY_VALUE, + ssprintf( "%.4f", m_pSong->m_Timing.GetDelayAtRow( BeatToNoteRow(GAMESTATE->m_fSongBeat) ) ), + 10 + ); + break; + case time_signature_numerator: + ScreenTextEntry::TextEntry( + SM_BackFromTimeSignatureNumeratorChange, + ENTER_TIME_SIGNATURE_NUMERATOR_VALUE, + ssprintf( "%d", m_pSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iNumerator ), + 3 + ); + break; + case time_signature_denominator: + ScreenTextEntry::TextEntry( + SM_BackFromTimeSignatureDenominatorChange, + ENTER_TIME_SIGNATURE_DENOMINATOR_VALUE, + ssprintf( "%d", m_pSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iDenominator ), + 3 + ); + break; + case tickcount: + ScreenTextEntry::TextEntry( + SM_BackFromTickcountChange, + ENTER_TICKCOUNT_VALUE, + ssprintf( "%d", m_pSong->m_Timing.GetTickcountAtBeat( GAMESTATE->m_fSongBeat ) ), + 2 + ); + break; + } +} + void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, const vector &iAnswers ) { BackgroundChange newChange; @@ -3707,11 +3823,14 @@ void ScreenEdit::CheckNumberOfNotesAndUndo() { if( EDIT_MODE.GetValue() != EditMode_Home ) return; + + TimeSignatureSegment curTime = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ); + int rowsPerMeasure = curTime.m_iDenominator * curTime.m_iNumerator; - for( int row=0; row<=m_NoteDataEdit.GetLastRow(); row+=ROWS_PER_MEASURE ) + for( int row=0; row<=m_NoteDataEdit.GetLastRow(); row+=rowsPerMeasure ) { int iNumNotesThisMeasure = 0; - FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( m_NoteDataEdit, r, row, row+ROWS_PER_MEASURE ) + FOREACH_NONEMPTY_ROW_ALL_TRACKS_RANGE( m_NoteDataEdit, r, row, row+rowsPerMeasure ) iNumNotesThisMeasure += m_NoteDataEdit.GetNumTapNonEmptyTracks( r ); if( iNumNotesThisMeasure > MAX_NOTES_PER_MEASURE ) { @@ -3757,8 +3876,9 @@ float ScreenEdit::GetMaximumBeatForNewNote() const /* Round up to the next measure end. Some songs end on weird beats * mid-measure, and it's odd to have movement capped to these weird * beats. */ - fEndBeat += BEATS_PER_MEASURE; - fEndBeat = ftruncf( fEndBeat, (float)BEATS_PER_MEASURE ); + int beatsPerMeasure = GAMESTATE->m_pCurSong->m_Timing.GetTimeSignatureSegmentAtBeat( GAMESTATE->m_fSongBeat ).m_iNumerator; + fEndBeat += beatsPerMeasure; + fEndBeat = ftruncf( fEndBeat, (float)beatsPerMeasure ); return fEndBeat; } @@ -3843,6 +3963,7 @@ static const EditHelpLine g_EditHelpLines[] = EditHelpLine( "Lay mine", EDIT_BUTTON_LAY_MINE_OR_ROLL ), EditHelpLine( "Lay lift", EDIT_BUTTON_LAY_LIFT ), EditHelpLine( "Add to/remove from right half", EDIT_BUTTON_RIGHT_SIDE ), + EditHelpLine( "Switch player (Routine only)", EDIT_BUTTON_SWITCH_PLAYERS ), }; static bool IsMapped( EditButton eb, const MapEditToDI &editmap ) @@ -3919,6 +4040,21 @@ void ScreenEdit::DoHelp() EditMiniMenu( &g_EditHelp ); } +// lua start +#include "LuaBinding.h" + +class LunaScreenEdit: public Luna +{ +public: + DEFINE_METHOD( GetEditState, GetEditState() ) + LunaScreenEdit() + { + ADD_METHOD( GetEditState ); + } +}; + +LUA_REGISTER_DERIVED_CLASS( ScreenEdit, ScreenWithMenuElements ) + /* * (c) 2001-2004 Chris Danford * All rights reserved. diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h index fef5ba076e..4d7999b277 100644 --- a/src/ScreenEdit.h +++ b/src/ScreenEdit.h @@ -18,6 +18,7 @@ #include "GameInput.h" #include "GameplayAssist.h" #include "AutoKeysounds.h" +#include "EnumHelper.h" #include @@ -33,6 +34,8 @@ enum EditState NUM_EditState, EditState_Invalid }; +const RString& EditStateToString( EditState es ); +LuaDeclareType( EditState ); enum EditButton { @@ -189,6 +192,11 @@ public: void SetDirty( bool bDirty ) { m_bDirty = bDirty; } bool IsDirty() const { return m_bDirty; } + EditState GetEditState(){ return m_EditState; } + + // Lua + virtual void PushSelf( lua_State *L ); + protected: virtual ScreenType GetScreenType() const { return m_EditState==STATE_PLAYING ? gameplay : ScreenWithMenuElements::GetScreenType(); } @@ -302,9 +310,7 @@ public: revert_from_disk, options, edit_song_info, - edit_bpm, - edit_stop, - edit_delay, + edit_timing_data, play_preview_music, exit, save_on_exit, @@ -401,6 +407,7 @@ public: difficulty, meter, description, + step_credit, predict_meter, tap_notes, jumps, @@ -431,6 +438,20 @@ public: NUM_SONG_INFORMATION_CHOICES }; void HandleSongInformationChoice( SongInformationChoice c, const vector &iAnswers ); + + enum TimingDataInformationChoice + { + bpm, + stop, + delay, +// time_signature, + time_signature_numerator, + time_signature_denominator, + tickcount, + NUM_TIMING_DATA_INFORMATION_CHOICES + }; + + void HandleTimingDataInformationChoice ( TimingDataInformationChoice c, const vector &iAnswers ); enum BGChangeChoice { diff --git a/src/ScreenExit.cpp b/src/ScreenExit.cpp index 0c10f923af..cad8057174 100644 --- a/src/ScreenExit.cpp +++ b/src/ScreenExit.cpp @@ -7,10 +7,10 @@ #include "RageLog.h" #include "arch/ArchHooks/ArchHooks.h" -/* This screen used to wait for sounds to stop. However, implementing GetPlayingSounds() - * is annoying, because sounds might be deleted at any time; they aren't ours to have - * references to. Also, it's better to quit on command instead of waiting several seconds - * for a sound to stop. */ +/* This screen used to wait for sounds to stop. However, implementing + * GetPlayingSounds() is annoying, because sounds might be deleted at any time; + * they aren't ours to have references to. Also, it's better to quit on command + * instead of waiting several seconds for a sound to stop. */ REGISTER_SCREEN_CLASS( ScreenExit ); void ScreenExit::Init() @@ -20,46 +20,6 @@ void ScreenExit::Init() m_Exited = false; ArchHooks::SetUserQuit(); - - /* It'd be better for any previous screen playing music to fade it out as it fades - * out the screen. XXX: Check to see if it's fading out; if it'll stop playing in - * reasonable time, let it. */ -// SOUND->StopMusic(); -} - -void ScreenExit::Update( float fDelta ) -{ -#if 0 - if( m_Exited ) - return; - - // Grab the list of playing sounds, and see if it's empty. - const set &PlayingSounds = SOUNDMAN->GetPlayingSounds(); - bool DoQuit = PlayingSounds.empty(); - - /* As a safety precaution, don't wait indefinitely, in case some sound was - * inadvertently set to play too long. */ - if( !DoQuit && m_ShutdownTimer.PeekDeltaTime() > 3 ) - { - DoQuit = true; - RString warn = ssprintf("ScreenExit: %i sound%s failed to finish playing quickly: ", - (int) PlayingSounds.size(), (PlayingSounds.size()==1?"":"s") ); - for( set::const_iterator i = PlayingSounds.begin(); - i != PlayingSounds.end(); ++i ) - { - warn += (*i)->GetLoadedFilePath() + "; "; - } - - LOG->Warn("%s", warn.c_str() ); - } - - if( DoQuit ) - { - m_Exited = true; - LOG->Trace("ScreenExit: shutting down"); - ArchHooks::SetUserQuit(); - } -#endif } /* diff --git a/src/ScreenExit.h b/src/ScreenExit.h index cd8534549f..fc8fe99f88 100644 --- a/src/ScreenExit.h +++ b/src/ScreenExit.h @@ -8,11 +8,9 @@ class ScreenExit: public Screen { public: void Init(); - void Update( float fDelta ); private: bool m_Exited; - RageTimer m_ShutdownTimer; }; #endif diff --git a/src/ScreenGameplay.cpp b/src/ScreenGameplay.cpp index d8717a790e..7978ab8b8c 100644 --- a/src/ScreenGameplay.cpp +++ b/src/ScreenGameplay.cpp @@ -1856,7 +1856,7 @@ void ScreenGameplay::Update( float fDeltaTime ) case PLAY_MODE_RAVE: if( GAMESTATE->OneIsHot() ) PlayAnnouncer( "gameplay comment hot", SECONDS_BETWEEN_COMMENTS ); - else if( GAMESTATE->AllAreInDangerOrWorse() ) + else if( GAMESTATE->AllAreInDangerOrWorse() ) PlayAnnouncer( "gameplay comment danger", SECONDS_BETWEEN_COMMENTS ); else PlayAnnouncer( "gameplay comment good", SECONDS_BETWEEN_COMMENTS ); @@ -2578,7 +2578,7 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) } else if( SM >= SM_100Combo && SM <= SM_1000Combo ) { - int iCombo = (SM-SM_100Combo+1)*100; + int iCombo = ( SM-(SM_100Combo+1) ) * 100; PlayAnnouncer( ssprintf("gameplay %d combo",iCombo), 2 ); } else if( SM == SM_ComboStopped ) diff --git a/src/ScreenGameplaySyncMachine.cpp b/src/ScreenGameplaySyncMachine.cpp index eecdbc7eef..62ca1d3d29 100644 --- a/src/ScreenGameplaySyncMachine.cpp +++ b/src/ScreenGameplaySyncMachine.cpp @@ -1,6 +1,6 @@ #include "global.h" #include "ScreenGameplaySyncMachine.h" -#include "NotesLoaderSM.h" +#include "NotesLoaderSSC.h" #include "GameState.h" #include "GameManager.h" #include "PrefsManager.h" @@ -18,14 +18,17 @@ void ScreenGameplaySyncMachine::Init() GAMESTATE->SetCurrentStyle( GAMEMAN->GetHowToPlayStyleForGame(GAMESTATE->m_pCurGame) ); AdjustSync::ResetOriginalSyncData(); - RString sFile = THEME->GetPathO("ScreenGameplaySyncMachine","music.sm"); - SMLoader::LoadFromSMFile( sFile, m_Song ); + RString sFile = THEME->GetPathO("ScreenGameplaySyncMachine","music"); + SSCLoader::LoadFromSSCFile( sFile, m_Song ); m_Song.SetSongDir( Dirname(sFile) ); m_Song.TidyUpData(); GAMESTATE->m_pCurSong.Set( &m_Song ); - Steps *pSteps = SongUtil::GetOneSteps( &m_Song ); - ASSERT( pSteps ); + // needs proper StepsType - freem + vector vpSteps; + SongUtil::GetPlayableSteps( &m_Song, vpSteps ); + ASSERT(vpSteps.size() > 0); + Steps *pSteps = vpSteps[0]; GAMESTATE->m_pCurSteps[0].Set( pSteps ); GamePreferences::m_AutoPlay.Set( PC_HUMAN ); diff --git a/src/ScreenHowToPlay.cpp b/src/ScreenHowToPlay.cpp index f54d18084e..16ddba07a2 100644 --- a/src/ScreenHowToPlay.cpp +++ b/src/ScreenHowToPlay.cpp @@ -5,6 +5,7 @@ #include "Steps.h" #include "GameManager.h" #include "NotesLoaderSM.h" +#include "NotesLoaderSSC.h" #include "GameSoundManager.h" #include "Model.h" #include "ThemeMetric.h" @@ -20,9 +21,10 @@ static const ThemeMetric NUM_W2S ("ScreenHowToPlay","NumW2s"); static const ThemeMetric NUM_MISSES ("ScreenHowToPlay","NumMisses"); -static const ThemeMetric USE_CHARACTER ("ScreenHowToPlay","UseCharacter"); -static const ThemeMetric USE_PAD ("ScreenHowToPlay","UsePad"); -static const ThemeMetric USE_PLAYER ("ScreenHowToPlay","UsePlayer"); +static const ThemeMetric USE_CHARACTER ("ScreenHowToPlay","UseCharacter"); +static const ThemeMetric USE_PAD ("ScreenHowToPlay","UsePad"); +static const ThemeMetric USE_PLAYER ("ScreenHowToPlay","UsePlayer"); +static const ThemeMetric CHARACTER_NAME("ScreenHowToPlay","CharacterName"); enum Animation { @@ -47,7 +49,6 @@ static const RString anims[NUM_ANIMATIONS] = "BeginnerHelper_step-jumplr.bones.txt" }; - static RString GetAnimPath( Animation a ) { return RString("Characters/") + anims[a]; @@ -82,40 +83,46 @@ void ScreenHowToPlay::Init() m_pmDancePad = new Model; m_pmDancePad->SetName( "Pad" ); m_pmDancePad->LoadMilkshapeAscii( GetAnimPath(ANIM_DANCE_PAD) ); + // xxx: hardcoded rotation. can be undone, but still. -freem m_pmDancePad->SetRotationX( 35 ); - LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_pmDancePad ); + ActorUtil::LoadAllCommandsAndSetXY( m_pmDancePad, m_sName ); } - - // Display random character + + // Display a character vector vpCharacters; CHARMAN->GetCharacters( vpCharacters ); if( (bool)USE_CHARACTER && vpCharacters.size() && HaveAllCharAnimations() ) { - Character* rndchar = CHARMAN->GetRandomCharacter(); + Character* displayChar; + if( !CHARACTER_NAME.GetValue().empty() && CHARMAN->GetCharacterFromID(CHARACTER_NAME) ) + displayChar = CHARMAN->GetCharacterFromID(CHARACTER_NAME); + else + displayChar = CHARMAN->GetRandomCharacter(); - RString sModelPath = rndchar->GetModelPath(); + RString sModelPath = displayChar->GetModelPath(); if( sModelPath != "" ) { m_pmCharacter = new Model; m_pmCharacter->SetName( "Character" ); - m_pmCharacter->LoadMilkshapeAscii( rndchar->GetModelPath() ); + m_pmCharacter->LoadMilkshapeAscii( displayChar->GetModelPath() ); m_pmCharacter->LoadMilkshapeAsciiBones( "Step-LEFT", GetAnimPath( ANIM_LEFT ) ); m_pmCharacter->LoadMilkshapeAsciiBones( "Step-DOWN", GetAnimPath( ANIM_DOWN ) ); m_pmCharacter->LoadMilkshapeAsciiBones( "Step-UP", GetAnimPath( ANIM_UP ) ); m_pmCharacter->LoadMilkshapeAsciiBones( "Step-RIGHT", GetAnimPath( ANIM_RIGHT ) ); m_pmCharacter->LoadMilkshapeAsciiBones( "Step-JUMPLR", GetAnimPath( ANIM_JUMPLR ) ); - RString sRestFile = rndchar->GetRestAnimationPath(); + RString sRestFile = displayChar->GetRestAnimationPath(); ASSERT( !sRestFile.empty() ); - m_pmCharacter->LoadMilkshapeAsciiBones( "rest",rndchar->GetRestAnimationPath() ); + m_pmCharacter->LoadMilkshapeAsciiBones( "rest",displayChar->GetRestAnimationPath() ); m_pmCharacter->SetDefaultAnimation( "rest" ); - m_pmCharacter->PlayAnimation( "rest" ); // Stay bouncing after a step has finished animating. - + m_pmCharacter->PlayAnimation( "rest" ); // Stay bouncing after a step has finished animating. + + // xxx: hardcoded rotation. can be undone, but still. -freem m_pmCharacter->SetRotationX( 40 ); - m_pmCharacter->SetCullMode( CULL_NONE ); // many of the models floating around have the vertex order flipped - LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_pmCharacter ); + m_pmCharacter->SetCullMode( CULL_NONE ); // many of the models floating around have the vertex order flipped + ActorUtil::LoadAllCommandsAndSetXY( m_pmCharacter, m_sName ); } } - + GAMESTATE->SetCurrentStyle( GAMEMAN->GetHowToPlayStyleForGame(GAMESTATE->m_pCurGame) ); if( USE_PLAYER ) @@ -123,17 +130,20 @@ void ScreenHowToPlay::Init() m_pLifeMeterBar = new LifeMeterBar; m_pLifeMeterBar->SetName("LifeMeterBar"); m_pLifeMeterBar->Load( GAMESTATE->m_pPlayerState[PLAYER_1], &STATSMAN->m_CurStageStats.m_player[PLAYER_1] ); - LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_pLifeMeterBar ); + ActorUtil::LoadAllCommandsAndSetXY( m_pLifeMeterBar, m_sName ); m_pLifeMeterBar->FillForHowToPlay( NUM_W2S, NUM_MISSES ); - - SMLoader::LoadFromSMFile( THEME->GetPathO(m_sName, "steps"), m_Song, false ); + // Allow themers to use .ssc and .sm files. -aj + bool bLoadedSSCFile = SSCLoader::LoadFromSSCFile( THEME->GetPathO(m_sName, "steps"), m_Song, false ); + if( !bLoadedSSCFile ) + SMLoader::LoadFromSMFile( THEME->GetPathO(m_sName, "steps"), m_Song, false ); m_Song.AddAutoGenNotes(); const Style* pStyle = GAMESTATE->GetCurrentStyle(); - + Steps *pSteps = SongUtil::GetStepsByDescription( &m_Song, pStyle->m_StepsType, "" ); - ASSERT_M( pSteps != NULL, ssprintf("%i", pStyle->m_StepsType) ); + // todo: make StepsType human readable. -aj + ASSERT_M( pSteps != NULL, ssprintf("StepsType %i is NULL", pStyle->m_StepsType) ); NoteData tempNoteData; pSteps->GetNoteData( tempNoteData ); @@ -157,7 +167,7 @@ void ScreenHowToPlay::Init() m_Player.Load( m_NoteData ); m_Player->SetName( "Player" ); this->AddChild( m_Player ); - LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_Player ); + ActorUtil::LoadAllCommandsAndSetXY( m_Player, m_sName ); // Don't show judgement PO_GROUP_ASSIGN( GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions, ModsLevel_Stage, m_fBlind, 1.0f ); @@ -188,6 +198,7 @@ ScreenHowToPlay::~ScreenHowToPlay() void ScreenHowToPlay::Step() { +// xxx: assumes dance. -freem #define ST_LEFT 0x01 #define ST_DOWN 0x02 #define ST_UP 0x04 @@ -215,7 +226,7 @@ void ScreenHowToPlay::Step() case ST_JUMPUD: // Until I can get an UP+DOWN jump animation, this will have to do. m_pmCharacter->PlayAnimation( "Step-JUMPLR", 1.8f ); - + m_pmCharacter->StopTweening(); m_pmCharacter->BeginTweening( GAMESTATE->m_fCurBPS /8, TWEEN_LINEAR ); m_pmCharacter->SetRotationY( 90 ); @@ -250,14 +261,20 @@ void ScreenHowToPlay::Update( float fDelta ) iLastNoteRowCounted = iCurNoteRow; } - // once we hit the number of perfects we want, we want to fail. - // switch the controller to HUMAN. since we aren't taking input, - // the steps will always be misses. + // Once we hit the number of perfects we want, we want to fail. Switch + // the controller to HUMAN. Since we aren't taking input, the steps will + // always be misses. if( m_iW2s > m_iNumW2s ) GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerController = PC_HUMAN; + // Per the above code, we don't always want the character stepping. + // If they try to make all of the steps in the miss part, they look + // silly. Have then stand still instead. - freem if ( m_pmCharacter ) - Step(); + { + if( m_iW2s <= m_iNumW2s ) + Step(); + } } ScreenAttract::Update( fDelta ); @@ -267,7 +284,7 @@ void ScreenHowToPlay::HandleScreenMessage( const ScreenMessage SM ) { if( SM == SM_GainFocus ) { - /* We do this ourself. */ + // We do this ourself. SOUND->HandleSongTimer( false ); } else if( SM == SM_LoseFocus ) @@ -281,7 +298,6 @@ void ScreenHowToPlay::HandleScreenMessage( const ScreenMessage SM ) ScreenAttract::HandleScreenMessage( SM ); } - // lua start #include "LuaBinding.h" diff --git a/src/ScreenHowToPlay.h b/src/ScreenHowToPlay.h index 55acfd43c9..d3eb7a6a65 100644 --- a/src/ScreenHowToPlay.h +++ b/src/ScreenHowToPlay.h @@ -14,24 +14,21 @@ public: ScreenHowToPlay(); virtual void Init(); ~ScreenHowToPlay(); - + virtual void Update( float fDelta ); virtual void HandleScreenMessage( const ScreenMessage SM ); - // // Lua - // virtual void PushSelf( lua_State *L ); - - LifeMeterBar *m_pLifeMeterBar; + protected: virtual void Step(); PlayerPlus m_Player; Model *m_pmCharacter; Model *m_pmDancePad; - int m_iW2s; - int m_iNumW2s; + int m_iW2s; + int m_iNumW2s; Song m_Song; NoteData m_NoteData; float m_fFakeSecondsIntoSong; diff --git a/src/ScreenInstallOverlay.cpp b/src/ScreenInstallOverlay.cpp index 4841a10d2d..adbe4cbf0f 100644 --- a/src/ScreenInstallOverlay.cpp +++ b/src/ScreenInstallOverlay.cpp @@ -248,11 +248,14 @@ public: } break; } - bool bFinsihed = m_DownloadState == packages && + bool bFinished = m_DownloadState == packages && m_vsQueuedPackageUrls.empty() && m_pTransfer == NULL; - if( bFinsihed ) + if( bFinished ) { + Message msg( "DownloadFinished" ); + MESSAGEMAN->Broadcast(msg); + playAfterLaunchInfo = m_playAfterLaunchInfo; return true; } @@ -370,7 +373,9 @@ void ScreenInstallOverlay::Update( float fDeltaTime ) sInitialScreen = StepMania::GetInitialScreen(); } - SCREENMAN->SetNewScreen( sInitialScreen ); + Screen *curScreen = SCREENMAN->GetTopScreen(); + if(curScreen->GetScreenType() == game_menu || curScreen->GetScreenType() == attract) + SCREENMAN->SetNewScreen( sInitialScreen ); } } diff --git a/src/ScreenJukebox.cpp b/src/ScreenJukebox.cpp index c2ee7cd358..7ad7555687 100644 --- a/src/ScreenJukebox.cpp +++ b/src/ScreenJukebox.cpp @@ -42,7 +42,6 @@ void ScreenJukebox::SetSong() if ( vSongs.size() == 0 ) vSongs = SONGMAN->GetSongs( GAMESTATE->m_sPreferredSongGroup ); - // Calculate what difficulties to show vector vDifficultiesToShow; if( m_bDemonstration ) @@ -186,9 +185,8 @@ void ScreenJukebox::Init() int Benchmark = 0; if( Benchmark ) { - /* Note that you also need to make sure you benchmark with the - * same notes. I (who? -aj) use a copy of Maxx Unlimited with only heavy notes - * included.*/ + /* Note that you also need to make sure you benchmark with the same notes. + * I (who? -aj) use a copy of Maxx Unlimited with only heavy notes included.*/ FOREACH_EnabledPlayer( p ) { /* Lots and lots of arrows. This might even bias to arrows a little @@ -206,6 +204,7 @@ void ScreenJukebox::Init() // Reset score between songs. STATSMAN->m_CurStageStats.m_player[p].ResetScoreForLesson(); + // This eats any noteskins that may have been set in ScreenJukeboxMenu. -aj if( GAMESTATE->m_bJukeboxUsesModifiers ) { PlayerOptions po; diff --git a/src/ScreenManager.cpp b/src/ScreenManager.cpp index 2d7bc9e720..b10963b20f 100644 --- a/src/ScreenManager.cpp +++ b/src/ScreenManager.cpp @@ -67,6 +67,7 @@ #include "SongManager.h" #include "RageTextureManager.h" #include "ThemeManager.h" +#include "FontManager.h" #include "Screen.h" #include "ScreenDimensions.h" #include "Foreach.h" @@ -75,6 +76,7 @@ ScreenManager* SCREENMAN = NULL; // global and accessable from anywhere in our program static Preference g_bDelayedScreenLoad( "DelayedScreenLoad", false ); +static Preference g_bPruneFonts( "PruneFonts", true ); // Screen registration static map *g_pmapRegistrees = NULL; @@ -305,6 +307,28 @@ void ScreenManager::ThemeChanged() this->RefreshCreditsMessages(); } +void ScreenManager::ReloadOverlayScreens() +{ + // unload overlay screens + for( unsigned i=0; iGetMetric( "Common","OverlayScreens" ); + vector asOverlays; + split( sOverlays, ",", asOverlays ); + for( unsigned i=0; iGetName() ); + pScreen->BeginScreen(); + g_OverlayScreens.push_back( pScreen ); + } + + this->RefreshCreditsMessages(); +} + Screen *ScreenManager::GetTopScreen() { if( g_ScreenStack.empty() ) @@ -566,6 +590,11 @@ void ScreenManager::PrepareScreen( const RString &sScreenName ) } } + // Prune any unused fonts now that we have had a chance to reference the fonts + if(g_bPruneFonts) { + FONT->PruneFonts(); + } + TEXTUREMAN->DiagnosticOutput(); } @@ -660,19 +689,17 @@ void ScreenManager::LoadDelayedScreen() * cleanup, so it doesn't get deleted by cleanup. */ bool bLoaded = ActivatePreparedScreenAndBackground( sScreenName ); - vector apActorsToDelete; - if( g_setGroupedScreens.find(sScreenName) == g_setGroupedScreens.end() ) - { - /* It's time to delete all old prepared screens. Depending on DelayedScreenLoad, - * we can either delete the screens before or after we load the new screen. - * Either way, we must remove them from the prepared list before we prepare - * new screens. - * If DelayedScreenLoad is true, delete them now; this lowers memory - * requirements, but results in redundant loads as we unload common data. */ - if( g_bDelayedScreenLoad ) - DeletePreparedScreens(); - else - GrabPreparedActors( apActorsToDelete ); + bool deletePrepared=g_setGroupedScreens.find(sScreenName) == g_setGroupedScreens.end(); + + /* It's time to delete all old prepared screens. Depending on DelayedScreenLoad, + * we can either delete the screens before or after we load the new screen. + * Either way, we must remove them from the prepared list before we prepare + * new screens. + * If DelayedScreenLoad is true, delete them now; this lowers memory + * requirements, but results in redundant loads as we unload common data. */ + if( deletePrepared && g_bDelayedScreenLoad ) { + DeletePreparedScreens(); + deletePrepared=false; } // If the screen wasn't already prepared, load it. @@ -689,12 +716,9 @@ void ScreenManager::LoadDelayedScreen() ASSERT( bLoaded ); } - if( !apActorsToDelete.empty() ) + if( deletePrepared ) { - BeforeDeleteScreen(); - FOREACH( Actor*, apActorsToDelete, a ) - SAFE_DELETE( *a ); - AfterDeleteScreen(); + DeletePreparedScreens(); } MESSAGEMAN->Broadcast( Message_ScreenChanged ); @@ -862,6 +886,7 @@ public: static int ScreenClassExists( T* p, lua_State *L ) { lua_pushboolean( L, g_pmapRegistrees->find( SArg(1) ) != g_pmapRegistrees->end() ); return 1; } static int AddNewScreenToTop( T* p, lua_State *L ) { p->AddNewScreenToTop( SArg(1) ); return 0; } //static int GetScreenStackSize( T* p, lua_State *L ) { lua_pushnumber( L, ScreenManagerUtil::g_ScreenStack.size() ); return 1; } + static int ReloadOverlayScreens( T* p, lua_State *L ) { p->ReloadOverlayScreens(); return 0; } LunaScreenManager() { @@ -872,6 +897,7 @@ public: ADD_METHOD( ScreenClassExists ); ADD_METHOD( AddNewScreenToTop ); //ADD_METHOD( GetScreenStackSize ); + ADD_METHOD( ReloadOverlayScreens ); } }; diff --git a/src/ScreenManager.h b/src/ScreenManager.h index 8f143ecbfe..d665dc2b6c 100644 --- a/src/ScreenManager.h +++ b/src/ScreenManager.h @@ -46,7 +46,7 @@ public: void RefreshCreditsMessages(); void ThemeChanged(); - + void ReloadOverlayScreens(); /* Return true if the given screen is in the main screen stack, but not the * bottommost screen. If true, the screen should usually exit by popping diff --git a/src/ScreenNetSelectMusic.cpp b/src/ScreenNetSelectMusic.cpp index 6d36ef14af..4cbc1e8733 100644 --- a/src/ScreenNetSelectMusic.cpp +++ b/src/ScreenNetSelectMusic.cpp @@ -24,6 +24,7 @@ #include "SongUtil.h" #include "RageInput.h" #include "SongManager.h" +#include "CodeDetector.h" AutoScreenMessage( SM_NoSongs ) AutoScreenMessage( SM_ChangeSong ) @@ -34,58 +35,44 @@ AutoScreenMessage( SM_SongChanged ) AutoScreenMessage( SM_UsersUpdate ) AutoScreenMessage( SM_BackFromPlayerOptions ) -// todo: metric this? -const RString AllGroups = "[ALL MUSIC]"; - -#define DIFFBG_WIDTH THEME->GetMetricF(m_sName,"DiffBGWidth") -#define DIFFBG_HEIGHT THEME->GetMetricF(m_sName,"DiffBGHeight") - REGISTER_SCREEN_CLASS( ScreenNetSelectMusic ); void ScreenNetSelectMusic::Init() { - /* Finish any previous stage. It's OK to call this when we haven't played a stage yet. */ + // Finish any previous stage. It's OK to call this when we haven't played a stage yet. GAMESTATE->FinishStage(); ScreenNetSelectBase::Init(); SAMPLE_MUSIC_PREVIEW_MODE.Load( m_sName, "SampleMusicPreviewMode" ); + MUSIC_WHEEL_TYPE.Load( m_sName, "MusicWheelType" ); FOREACH_EnabledPlayer (p) { - /* - m_DifficultyIcon[p].SetName( ssprintf("DifficultyIconP%d",p+1) ); - m_DifficultyIcon[p].Load( THEME->GetPathG( "ScreenSelectMusic", - ssprintf("difficulty icons 1x%d", - NUM_Difficulty)) ); - LOAD_ALL_COMMANDS_AND_SET_XY( m_DifficultyIcon[p] ); - this->AddChild( &m_DifficultyIcon[p] ); - ON_COMMAND( m_DifficultyIcon[p] ); - */ m_DC[p] = GAMESTATE->m_PreferredDifficulty[p]; m_StepsDisplays[p].SetName( ssprintf("StepsDisplayP%d",p+1) ); - m_StepsDisplays[p].Load( "StepsDisplay", NULL ); + m_StepsDisplays[p].Load( "StepsDisplayNet", NULL ); LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND( m_StepsDisplays[p] ); this->AddChild( &m_StepsDisplays[p] ); } m_MusicWheel.SetName( "MusicWheel" ); - m_MusicWheel.Load( "OnlineMusicWheel" ); + m_MusicWheel.Load( MUSIC_WHEEL_TYPE ); LOAD_ALL_COMMANDS_AND_SET_XY( m_MusicWheel ); m_MusicWheel.BeginScreen(); ON_COMMAND( m_MusicWheel ); this->AddChild( &m_MusicWheel ); this->MoveToHead( &m_MusicWheel ); - // todo: lua me? + // 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: lua me + // todo: handle me theme-side -aj FOREACH_EnabledPlayer( p ) { m_ModIconRow[p].SetName( ssprintf("ModIconsP%d",p+1) ); @@ -114,7 +101,7 @@ void ScreenNetSelectMusic::Input( const InputEventPlus &input ) if( !m_bAllowInput || IsTransitioning() ) return; - if ( input.type == IET_RELEASE ) + if( input.type == IET_RELEASE ) { m_MusicWheel.Move(0); return; @@ -126,21 +113,22 @@ void ScreenNetSelectMusic::Input( const InputEventPlus &input ) bool bHoldingCtrl = INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL)) || INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL)) || - (!NSMAN->useSMserver); //If we are disconnected, assume no chatting + (!NSMAN->useSMserver); // If we are disconnected, assume no chatting wchar_t c = INPUTMAN->DeviceInputToChar(input.DeviceI,false); MakeUpper( &c, 1 ); - if ( bHoldingCtrl && ( c >= 'A' ) && ( c <= 'Z' ) ) + // Ctrl+[A-Z] to go to that letter of the alphabet + if( bHoldingCtrl && ( c >= 'A' ) && ( c <= 'Z' ) ) { SortOrder so = GAMESTATE->m_SortOrder; - if ( ( so != SORT_TITLE ) && ( so != SORT_ARTIST ) ) + if( ( so != SORT_TITLE ) && ( so != SORT_ARTIST ) ) { so = SORT_TITLE; GAMESTATE->m_PreferredSortOrder = so; GAMESTATE->m_SortOrder.Set( so ); - //Odd, changing the sort order requires us to call SetOpenSection more than once + // Odd, changing the sort order requires us to call SetOpenSection more than once m_MusicWheel.ChangeSort( so ); m_MusicWheel.SetOpenSection( ssprintf("%c", c ) ); } @@ -174,14 +162,13 @@ void ScreenNetSelectMusic::HandleScreenMessage( const ScreenMessage SM ) } else if( SM == SM_ChangeSong ) { - //First check to see if this song is already selected. - //This is so that if you multiple copies of the "same" song - //you can chose which copy to play. + // First check to see if this song is already selected. This is so that if + // you have multiple copies of the "same" song you can chose which copy to play. Song* CurSong = m_MusicWheel.GetSelectedSong(); - if (CurSong != NULL ) + if(CurSong != NULL ) - if ( ( !CurSong->GetTranslitArtist().CompareNoCase( NSMAN->m_sArtist ) ) && + if( ( !CurSong->GetTranslitArtist().CompareNoCase( NSMAN->m_sArtist ) ) && ( !CurSong->GetTranslitMainTitle().CompareNoCase( NSMAN->m_sMainTitle ) ) && ( !CurSong->GetTranslitSubTitle().CompareNoCase( NSMAN->m_sSubTitle ) ) ) { @@ -192,8 +179,8 @@ void ScreenNetSelectMusic::HandleScreenMessage( const ScreenMessage SM ) NSMAN->m_iSelectMode = 0; NSMAN->SelectUserSong(); break; - case 2: //Proper starting of song - case 3: //Blind starting of song + case 2: // Proper starting of song + case 3: // Blind starting of song StartSelectedSong(); goto done; } @@ -204,7 +191,7 @@ void ScreenNetSelectMusic::HandleScreenMessage( const ScreenMessage SM ) for( i=0; i < AllSongs.size(); i++ ) { m_cSong = AllSongs[i]; - if ( ( !m_cSong->GetTranslitArtist().CompareNoCase( NSMAN->m_sArtist ) ) && + if( ( !m_cSong->GetTranslitArtist().CompareNoCase( NSMAN->m_sArtist ) ) && ( !m_cSong->GetTranslitMainTitle().CompareNoCase( NSMAN->m_sMainTitle ) ) && ( !m_cSong->GetTranslitSubTitle().CompareNoCase( NSMAN->m_sSubTitle ) ) ) break; @@ -217,10 +204,10 @@ void ScreenNetSelectMusic::HandleScreenMessage( const ScreenMessage SM ) case 3: StartSelectedSong(); break; - case 2: //We need to do cmd 1 as well here - if (haveSong) + case 2: // We need to do cmd 1 as well here + if(haveSong) { - if (!m_MusicWheel.SelectSong( m_cSong ) ) + if(!m_MusicWheel.SelectSong( m_cSong ) ) { m_MusicWheel.ChangeSort( SORT_GROUP ); m_MusicWheel.FinishTweening(); @@ -233,10 +220,10 @@ void ScreenNetSelectMusic::HandleScreenMessage( const ScreenMessage SM ) m_MusicWheel.Select(); } break; - case 1: //Scroll to song as well - if (haveSong) + case 1: // Scroll to song as well + if(haveSong) { - if (!m_MusicWheel.SelectSong( m_cSong ) ) + if(!m_MusicWheel.SelectSong( m_cSong ) ) { //m_MusicWheel.ChangeSort( SORT_GROUP ); //m_MusicWheel.FinishTweening(); @@ -250,16 +237,16 @@ void ScreenNetSelectMusic::HandleScreenMessage( const ScreenMessage SM ) m_MusicWheel.Move(1); m_MusicWheel.Select(); } - //don't break here - case 0: //See if client has song - if (haveSong) + // don't break here + case 0: // See if client has song + if(haveSong) NSMAN->m_iSelectMode = 0; else NSMAN->m_iSelectMode = 1; NSMAN->SelectUserSong(); } } - else if( SM == SM_SetWheelSong ) //After we're done the sort on wheel, select song. + else if( SM == SM_SetWheelSong ) // After we've done the sort on wheel, select song. { m_MusicWheel.SelectSong( m_cSong ); } @@ -289,7 +276,7 @@ void ScreenNetSelectMusic::HandleScreenMessage( const ScreenMessage SM ) } else if( SM == SM_SMOnlinePack ) { - if ( NSMAN->m_SMOnlinePacket.Read1() == 1 ) + if( NSMAN->m_SMOnlinePacket.Read1() == 1 ) { switch ( NSMAN->m_SMOnlinePacket.Read1() ) { @@ -298,7 +285,7 @@ void ScreenNetSelectMusic::HandleScreenMessage( const ScreenMessage SM ) RString titleSub; titleSub = NSMAN->m_SMOnlinePacket.ReadNT() + "\n"; titleSub += NSMAN->m_SMOnlinePacket.ReadNT(); - if ( NSMAN->m_SMOnlinePacket.Read1() != 1 ) + if( NSMAN->m_SMOnlinePacket.Read1() != 1 ) { RString SMOnlineSelectScreen = THEME->GetMetric( m_sName, "RoomSelectScreen" ); SCREENMAN->SetNewScreen( SMOnlineSelectScreen ); @@ -314,15 +301,17 @@ done: ScreenNetSelectBase::HandleScreenMessage( SM ); } +bool ScreenNetSelectMusic::LeftAndRightPressed( const PlayerNumber pn ) +{ + return INPUTMAPPER->IsBeingPressed( GAME_BUTTON_LEFT, pn ) + && INPUTMAPPER->IsBeingPressed( GAME_BUTTON_RIGHT, pn ); +} + void ScreenNetSelectMusic::MenuLeft( const InputEventPlus &input ) { PlayerNumber pn = input.pn; - bool bLeftPressed = INPUTMAPPER->IsBeingPressed( GAME_BUTTON_LEFT, pn ); - bool bRightPressed = INPUTMAPPER->IsBeingPressed( GAME_BUTTON_RIGHT, pn ); - bool bLeftAndRightPressed = bLeftPressed && bRightPressed; - - if ( bLeftAndRightPressed ) + if( LeftAndRightPressed(pn) ) m_MusicWheel.ChangeSort( SORT_MODE_MENU ); else m_MusicWheel.Move( -1 ); @@ -332,12 +321,8 @@ void ScreenNetSelectMusic::MenuRight( const InputEventPlus &input ) { PlayerNumber pn = input.pn; - bool bLeftPressed = INPUTMAPPER->IsBeingPressed( GAME_BUTTON_LEFT, pn ); - bool bRightPressed = INPUTMAPPER->IsBeingPressed( GAME_BUTTON_RIGHT, pn ); - bool bLeftAndRightPressed = bLeftPressed && bRightPressed; - - if ( bLeftAndRightPressed ) - m_MusicWheel.ChangeSort( SORT_MODE_MENU ); + if( LeftAndRightPressed(pn) ) + m_MusicWheel.ChangeSort( SORT_MODE_MENU ); else m_MusicWheel.Move( +1 ); } @@ -357,16 +342,16 @@ void ScreenNetSelectMusic::MenuDown( const InputEventPlus &input ) // I agree, that's a stupid idea -aj PlayerNumber pn = input.pn; - if ( GAMESTATE->IsPlayerEnabled( PLAYER_2 ) && + if( GAMESTATE->IsPlayerEnabled( PLAYER_2 ) && !GAMESTATE->IsPlayerEnabled( PLAYER_1 ) ) pn = PLAYER_2; - if ( GAMESTATE->m_pCurSong == NULL ) + if( GAMESTATE->m_pCurSong == NULL ) return; StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; vector MultiSteps; MultiSteps = GAMESTATE->m_pCurSong->GetStepsByStepsType( st ); - if (MultiSteps.size() == 0) + if(MultiSteps.size() == 0) m_DC[pn] = NUM_Difficulty; else { @@ -374,26 +359,26 @@ void ScreenNetSelectMusic::MenuDown( const InputEventPlus &input ) bool dcs[NUM_Difficulty]; - for ( i=0; iGetDifficulty()] = true; - for ( i=0; i m_DC[pn]) ) + if( (dcs[i]) && (i > m_DC[pn]) ) { m_DC[pn] = (Difficulty)i; break; } } // If failed to go up, loop - if ( i == NUM_Difficulty ) + if( i == NUM_Difficulty ) { - for (i = 0;im_pCurSong.Set( pSong ); - if ( NSMAN->useSMserver ) + if( NSMAN->useSMserver ) { - //int j = m_iSongNum % m_vSongs.size(); NSMAN->m_sArtist = pSong->GetTranslitArtist(); NSMAN->m_sMainTitle = pSong->GetTranslitMainTitle(); NSMAN->m_sSubTitle = pSong->GetTranslitSubTitle(); - NSMAN->m_iSelectMode = 2; //Command for user selecting song + NSMAN->m_iSelectMode = 2; // Command for user selecting song NSMAN->SelectUserSong (); } else @@ -444,7 +428,6 @@ void ScreenNetSelectMusic::MenuBack( const InputEventPlus &input ) Cancel( SM_GoToPrevScreen ); } - void ScreenNetSelectMusic::TweenOffScreen() { ScreenNetSelectBase::TweenOffScreen(); @@ -479,8 +462,8 @@ void ScreenNetSelectMusic::StartSelectedSong() GAMESTATE->m_PreferredSortOrder = GAMESTATE->m_SortOrder; GAMESTATE->m_pPreferredSong = pSong; - - //force event mode + + // force event mode GAMESTATE->m_bTemporaryEventMode = true; TweenOffScreen(); @@ -489,31 +472,19 @@ void ScreenNetSelectMusic::StartSelectedSong() void ScreenNetSelectMusic::UpdateDifficulties( PlayerNumber pn ) { - if ( GAMESTATE->m_pCurSong == NULL ) + if( GAMESTATE->m_pCurSong == NULL ) { m_StepsDisplays[pn].SetFromStepsTypeAndMeterAndDifficultyAndCourseType( StepsType_Invalid, 0, Difficulty_Beginner, CourseType_Invalid ); - //m_DifficultyIcon[pn].SetFromSteps( pn, NULL ); //It will blank it out + //m_DifficultyIcon[pn].SetFromSteps( pn, NULL ); // It will blank it out return; } - if ( m_DC[pn] < Difficulty_Edit && m_DC[pn] >= Difficulty_Beginner ) - { - /* - m_DifficultyIcon[pn].SetPlayer( pn ); - m_DifficultyIcon[pn].SetFromDifficulty( m_DC[pn] ); - */ - } - else - { - //m_DifficultyIcon[pn].SetFromSteps( pn, NULL ); //It will blank it out - } - StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; Steps * pSteps = SongUtil::GetStepsByDifficulty( GAMESTATE->m_pCurSong, st, m_DC[pn] ); GAMESTATE->m_pCurSteps[pn].Set( pSteps ); - if ( ( m_DC[pn] < NUM_Difficulty ) && ( m_DC[pn] >= Difficulty_Beginner ) ) + if( ( m_DC[pn] < NUM_Difficulty ) && ( m_DC[pn] >= Difficulty_Beginner ) ) m_StepsDisplays[pn].SetFromSteps( pSteps ); else m_StepsDisplays[pn].SetFromStepsTypeAndMeterAndDifficultyAndCourseType( StepsType_Invalid, 0, Difficulty_Beginner, CourseType_Invalid ); @@ -521,14 +492,15 @@ void ScreenNetSelectMusic::UpdateDifficulties( PlayerNumber pn ) void ScreenNetSelectMusic::MusicChanged() { - if ( GAMESTATE->m_pCurSong == NULL ) + if( GAMESTATE->m_pCurSong == NULL ) { m_BPMDisplay.NoBPM(); FOREACH_EnabledPlayer (pn) UpdateDifficulties( pn ); SOUND->StopMusic(); - // xxx: it should play the menu music instead. -aj + // todo: handle playing section music correctly. -aj + // SOUND->PlayMusic( m_sSectionMusicPath, NULL, true, 0, -1 ); return; } m_BPMDisplay.SetBpmFromSong( GAMESTATE->m_pCurSong ); @@ -539,7 +511,7 @@ void ScreenNetSelectMusic::MusicChanged() StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; vector MultiSteps; MultiSteps = GAMESTATE->m_pCurSong->GetStepsByStepsType( st ); - if (MultiSteps.size() == 0) + if(MultiSteps.size() == 0) m_DC[pn] = NUM_Difficulty; else { @@ -548,24 +520,24 @@ void ScreenNetSelectMusic::MusicChanged() bool dcs[NUM_Difficulty]; - for ( i=0; iGetDifficulty()] = true; - for ( i=0; i= m_DC[pn] ) + if( i >= m_DC[pn] ) { m_DC[pn] = (Difficulty)i; break; } } - if ( i == NUM_Difficulty ) + if( i == NUM_Difficulty ) m_DC[pn] = Target; } UpdateDifficulties( pn ); @@ -576,7 +548,8 @@ void ScreenNetSelectMusic::MusicChanged() SOUND->StopMusic(); if( GAMESTATE->m_pCurSong->HasMusic() ) { - if(SOUND->GetMusicPath().CompareNoCase(GAMESTATE->m_pCurSong->GetMusicPath())) // dont play the same sound over and over + // don't play the same sound over and over + if(SOUND->GetMusicPath().CompareNoCase(GAMESTATE->m_pCurSong->GetMusicPath())) { SOUND->StopMusic(); SOUND->PlayMusic( @@ -591,7 +564,7 @@ void ScreenNetSelectMusic::MusicChanged() void ScreenNetSelectMusic::Update( float fDeltaTime ) { - if (!m_bInitialSelect) + if(!m_bInitialSelect) { m_bInitialSelect = true; SCREENMAN->PostMessageToTopScreen( SM_RefreshWheelLocation, 1.0f ); @@ -599,9 +572,8 @@ void ScreenNetSelectMusic::Update( float fDeltaTime ) ScreenNetSelectBase::Update( fDeltaTime ); } - #endif - + /* * (c) 2004-2005 Charles Lohr * All rights reserved. diff --git a/src/ScreenNetSelectMusic.h b/src/ScreenNetSelectMusic.h index 7f9e79abad..57d749fb24 100644 --- a/src/ScreenNetSelectMusic.h +++ b/src/ScreenNetSelectMusic.h @@ -21,37 +21,16 @@ public: virtual void Input( const InputEventPlus &input ); virtual void HandleScreenMessage( const ScreenMessage SM ); - void UpdateSongsListPos(); - void UpdateGroupsListPos(); - void UpdateSongsList(); - void UpdateTextInput(); - void StartSelectedSong(); -private: - int m_iSongNum; - int m_iShowSongs; //The number of songs to display to each side - int m_iGroupNum; - int m_iShowGroups; //The number of groups to display to each side - - enum NetScreenSelectModes - { - SelectGroup = 0, - SelectSong, - SelectDifficulty, - SelectOptions, - SelectModes, - }; - - NetScreenSelectModes m_SelectMode; - protected: virtual void MenuStart( const InputEventPlus &input ); + virtual void MenuBack( const InputEventPlus &input ); virtual void MenuLeft( const InputEventPlus &input ); + virtual void MenuRight( const InputEventPlus &input ); virtual void MenuUp( const InputEventPlus &input ); virtual void MenuDown( const InputEventPlus &input ); - virtual void MenuRight( const InputEventPlus &input ); - virtual void MenuBack( const InputEventPlus &input ); + bool LeftAndRightPressed( const PlayerNumber pn ); virtual void Update( float fDeltaTime ); @@ -64,20 +43,20 @@ protected: RString m_sRouletteMusicPath; RString m_sRandomMusicPath; + ThemeMetric MUSIC_WHEEL_TYPE; + private: MusicWheel m_MusicWheel; - // todo: replace difficulty icons with StepsDisplay out the ass - //Difficulty Icon(s) - //DifficultyIcon m_DifficultyIcon[NUM_PLAYERS]; + StepsDisplay m_StepsDisplays[NUM_PLAYERS]; Difficulty m_DC[NUM_PLAYERS]; void UpdateDifficulties( PlayerNumber pn ); - StepsDisplay m_StepsDisplays[NUM_PLAYERS]; RageSound m_soundChangeOpt; RageSound m_soundChangeSel; + // todo: do these theme-side instead. -aj BPMDisplay m_BPMDisplay; ModIconRow m_ModIconRow[NUM_PLAYERS]; diff --git a/src/ScreenNetworkOptions.cpp b/src/ScreenNetworkOptions.cpp index e88b49b679..51d8dff800 100644 --- a/src/ScreenNetworkOptions.cpp +++ b/src/ScreenNetworkOptions.cpp @@ -22,7 +22,7 @@ static LocalizedString DISCONNECTED ( "ScreenNetworkOptions", "Disconnected fro static LocalizedString ENTER_NETWORK_ADDRESS ( "ScreenNetworkOptions", "Enter a network address." ); static LocalizedString CONNECT_TO_YOURSELF ( "ScreenNetworkOptions", "Use 127.0.0.1 to connect to yourself." ); -enum +enum NetworkOptionRow { PO_CONNECTION, PO_SCOREBOARD, @@ -30,7 +30,7 @@ enum NUM_NETWORK_OPTIONS_LINES }; -enum +enum DisplayScoreboard { NO_SCOREBOARD_OFF=0, NO_SCOREBOARD_ON @@ -128,7 +128,7 @@ void ScreenNetworkOptions::MenuStart( const InputEventPlus &input ) PREFSMAN->m_bEnableScoreboard.Set(false); break; /* - case PO_SERVERS: + case NetworkOptionRow::PO_SERVERS: if ( !AllServers.empty() ) { string sNewName = AllServers[m_pRows[GetCurrentRow()]->GetOneSharedSelection()].Address; diff --git a/src/ScreenOptionsEditCourse.cpp b/src/ScreenOptionsEditCourse.cpp index 5f05f33830..82ee683d89 100644 --- a/src/ScreenOptionsEditCourse.cpp +++ b/src/ScreenOptionsEditCourse.cpp @@ -394,7 +394,10 @@ void ScreenOptionsEditCourse::SetCurrentSong() if( index != 0 ) pSong = m_vpSongs[ index - 1 ]; } - GAMESTATE->m_pCurSong.Set( pSong ); + if ( pSong != NULL ) + { + GAMESTATE->m_pCurSong.Set( pSong ); + } } } diff --git a/src/ScreenOptionsExportPackage.cpp b/src/ScreenOptionsExportPackage.cpp index b47e4f2e10..c6858a2571 100644 --- a/src/ScreenOptionsExportPackage.cpp +++ b/src/ScreenOptionsExportPackage.cpp @@ -25,6 +25,8 @@ void ScreenOptionsExportPackage::Init() void ScreenOptionsExportPackage::BeginScreen() { // Fill m_vsPossibleDirsToExport + // todo: split these out over multiple screens so the scroller + // isn't so overloaded. -freem { // Add themes { diff --git a/src/ScreenOptionsManageCourses.cpp b/src/ScreenOptionsManageCourses.cpp index 11473ee05a..cbf20336d9 100644 --- a/src/ScreenOptionsManageCourses.cpp +++ b/src/ScreenOptionsManageCourses.cpp @@ -21,7 +21,6 @@ REGISTER_SCREEN_CLASS( ScreenOptionsManageCourses ); - struct StepsTypeAndDifficulty { StepsType st; @@ -50,8 +49,6 @@ static void SetNextCombination() GAMESTATE->m_stEdit.Set( curVal.st ); GAMESTATE->m_cdEdit.Set( curVal.cd ); - // XXX Testing. - SCREENMAN->SystemMessage( ssprintf("%s, %s", GAMEMAN->GetStepsTypeInfo(curVal.st).szName, DifficultyToString(curVal.cd).c_str()) ); EditCourseUtil::UpdateAndSetTrail(); } @@ -69,28 +66,27 @@ void ScreenOptionsManageCourses::Init() } void ScreenOptionsManageCourses::BeginScreen() -{ +{ vector vpStyles; GAMEMAN->GetStylesForGame( GAMESTATE->m_pCurGame, vpStyles ); const Style *pStyle = vpStyles[0]; GAMESTATE->SetCurrentStyle( pStyle ); - if( GAMESTATE->m_stEdit == StepsType_Invalid || GAMESTATE->m_cdEdit == Difficulty_Invalid ) { SetNextCombination(); } - - // Remember the current course. All Course pointers will be invalidated when we load the machine profile below. + // Remember the current course. All Course pointers will be invalidated when + // we load the machine profile below. CourseID cidLast; cidLast.FromCourse( GAMESTATE->m_pCurCourse ); vector vHands; - + int iIndex = 0; - + { vHands.push_back( OptionRowHandlerUtil::MakeNull() ); OptionRowDefinition &def = vHands.back()->m_Def; @@ -101,7 +97,7 @@ void ScreenOptionsManageCourses::BeginScreen() def.m_vsChoices.clear(); def.m_vsChoices.push_back( "" ); iIndex++; - } + } m_vpCourses.clear(); // XXX: Why are we flushing here? @@ -119,12 +115,12 @@ void ScreenOptionsManageCourses::BeginScreen() SONGMAN->GetAllCourses( m_vpCourses, false ); break; } - + FOREACH_CONST( Course*, m_vpCourses, p ) { vHands.push_back( OptionRowHandlerUtil::MakeNull() ); OptionRowDefinition &def = vHands.back()->m_Def; - + def.m_sName = (*p)->GetDisplayFullTitle(); def.m_bAllowThemeTitle = false; // not themable def.m_sExplanationName = "Select Course"; @@ -133,11 +129,11 @@ void ScreenOptionsManageCourses::BeginScreen() def.m_bAllowThemeItems = false; // already themed iIndex++; } - + ScreenOptions::InitMenu( vHands ); - + ScreenOptions::BeginScreen(); - + // select the last chosen course GAMESTATE->m_pCurCourse.Set( cidLast.ToCourse() ); if( GAMESTATE->m_pCurCourse ) @@ -172,12 +168,12 @@ void ScreenOptionsManageCourses::HandleScreenMessage( const ScreenMessage SM ) EditCourseUtil::UpdateAndSetTrail(); SCREENMAN->SetNewScreen( CREATE_NEW_SCREEN ); - return; // don't call base + return; // don't call base } else if( m_pRows[iCurRow]->GetRowType() == OptionRow::RowType_Exit ) { this->HandleScreenMessage( SM_GoToPrevScreen ); - return; // don't call base + return; // don't call base } else { @@ -195,12 +191,12 @@ void ScreenOptionsManageCourses::HandleScreenMessage( const ScreenMessage SM ) ScreenOptions::HandleScreenMessage( SM ); } - + void ScreenOptionsManageCourses::AfterChangeRow( PlayerNumber pn ) { Course *pCourse = GetCourseWithFocus(); Trail *pTrail = pCourse ? pCourse->GetTrail( GAMESTATE->m_stEdit, GAMESTATE->m_cdEdit ) : NULL; - + GAMESTATE->m_pCurCourse.Set( pCourse ); GAMESTATE->m_pCurTrail[PLAYER_1].Set( pTrail ); @@ -213,7 +209,6 @@ void ScreenOptionsManageCourses::MenuSelect( const InputEventPlus &input ) return; SetNextCombination(); m_soundDifficultyChanged.Play(); - } static LocalizedString YOU_HAVE_MAX( "ScreenOptionsManageCourses", "You have %d, the maximum number allowed." ); @@ -269,7 +264,7 @@ Course *ScreenOptionsManageCourses::GetCourseWithFocus() const return NULL; else if( m_pRows[iCurRow]->GetRowType() == OptionRow::RowType_Exit ) return NULL; - + // a course int index = iCurRow - 1; return m_vpCourses[index]; diff --git a/src/ScreenOptionsMasterPrefs.cpp b/src/ScreenOptionsMasterPrefs.cpp index e84bb685a0..1fc7fc6b9e 100644 --- a/src/ScreenOptionsMasterPrefs.cpp +++ b/src/ScreenOptionsMasterPrefs.cpp @@ -431,17 +431,25 @@ static void SongsPerPlayOrEventMode( int &sel, bool ToSel, const ConfOption *pCo } // Machine options +/** @brief Timing Window scale */ static void TimingWindowScale( int &sel, bool ToSel, const ConfOption *pConfOption ) { + // StepMania 5 values (implemented 2008/03/12) //const float mapping[] = { 2.0f,1.66f,1.33f,1.00f,0.75f,0.50f,0.25f }; + // StepMania 3.9 and 4.0 values: const float mapping[] = { 1.50f,1.33f,1.16f,1.00f,0.84f,0.66f,0.50f,0.33f,0.20f }; MoveMap( sel, pConfOption, ToSel, mapping, ARRAYLEN(mapping) ); } +/** @brief Life Difficulty scale */ static void LifeDifficulty( int &sel, bool ToSel, const ConfOption *pConfOption ) { + // StepMania 5 values (implemented 2008/03/12) //const float mapping[] = { 2.0f,1.50f,1.00f,0.66f,0.33f }; - const float mapping[] = { 1.60f,1.40f,1.20f,1.00f,0.80f,0.60f,0.40f }; + // StepMania 3.9 and 4.0 values: + //const float mapping[] = { 1.60f,1.40f,1.20f,1.00f,0.80f,0.60f,0.40f }; + // 3.9 modified so that L6 is L4 + const float mapping[] = { 1.20f,1.00f,0.80f,0.60f,0.40f,0.33f,0.25f }; MoveMap( sel, pConfOption, ToSel, mapping, ARRAYLEN(mapping) ); } @@ -610,7 +618,7 @@ static void SoundVolumeAttract( int &sel, bool ToSel, const ConfOption *pConfOpt static void VisualDelaySeconds( int &sel, bool ToSel, const ConfOption *pConfOption ) { - const float mapping[] = { -0.125f,-0.1f,-0.075f,-0.05f,0.025f,0.0f,0.025f,0.05f,0.075f,0.1f,0.125f }; + const float mapping[] = { -0.125f,-0.1f,-0.075f,-0.05f,-0.025f,0.0f,0.025f,0.05f,0.075f,0.1f,0.125f }; MoveMap( sel, pConfOption, ToSel, mapping, ARRAYLEN(mapping) ); } @@ -712,12 +720,12 @@ static void InitializeConfOptions() ADD( ConfOption( "EventMode", MovePref, "Off","On (recommended)" ) ); ADD( ConfOption( "ScoringType", MovePref, "New","Old","Custom" ) ); ADD( ConfOption( "TimingWindowScale", TimingWindowScale, "|1","|2","|3","|4","|5","|6","|7","|8","Justice" ) ); - ADD( ConfOption( "LifeDifficulty", LifeDifficulty, "|1","|2","|3","|4","|5","|6","|7" ) ); + ADD( ConfOption( "LifeDifficulty", LifeDifficulty, "|1.2","|1.0","|0.8","|0.6","|0.4","|0.33","|0.25" ) ); g_ConfOptions.back().m_sPrefName = "LifeDifficultyScale"; ADD( ConfOption( "ProgressiveLifebar", MovePref, "Off","|1","|2","|3","|4","|5","|6","|7","|8") ); ADD( ConfOption( "ProgressiveStageLifebar", MovePref, "Off","|1","|2","|3","|4","|5","|6","|7","|8","Insanity") ); ADD( ConfOption( "ProgressiveNonstopLifebar", MovePref, "Off","|1","|2","|3","|4","|5","|6","|7","|8","Insanity") ); - ADD( ConfOption( "DefaultFailType", DefaultFailType, "Immediate","ImmediateContinue","End of Song","Off" ) ); + ADD( ConfOption( "DefaultFailType", DefaultFailType, "Immediate","ImmediateContinue","EndOfSong","Off" ) ); ADD( ConfOption( "CoinsPerCredit", CoinsPerCredit, "|1","|2","|3","|4","|5","|6","|7","|8","|9","|10","|11","|12","|13","|14","|15","|16" ) ); ADD( ConfOption( "Premium", MovePref, "Off","Double for 1 Credit","2 Players for 1 Credit" ) ); ADD( ConfOption( "JointPremium", JointPremium, "Off","2 Players for 1 Credit" ) ); @@ -816,8 +824,10 @@ void ConfOption::MakeOptionsList( vector &out ) const out = names; } -/* - * (c) 2003-2004 Glenn Maynard +/** + * @file + * @author Glenn Maynard (c) 2003-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/ScreenOptionsMasterPrefs.h b/src/ScreenOptionsMasterPrefs.h index fa3bd0a987..662552eae1 100644 --- a/src/ScreenOptionsMasterPrefs.h +++ b/src/ScreenOptionsMasterPrefs.h @@ -70,8 +70,10 @@ struct ConfOption #endif -/* - * (c) 2003-2004 Glenn Maynard +/** + * @file + * @author Glenn Maynard (c) 2003-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/ScreenOptionsMemoryCard.cpp b/src/ScreenOptionsMemoryCard.cpp index c4b7b186a1..02e1ed832b 100644 --- a/src/ScreenOptionsMemoryCard.cpp +++ b/src/ScreenOptionsMemoryCard.cpp @@ -9,7 +9,6 @@ #include "LocalizedString.h" #include "OptionRowHandler.h" - REGISTER_SCREEN_CLASS( ScreenOptionsMemoryCard ); void ScreenOptionsMemoryCard::Init() @@ -42,22 +41,24 @@ bool ScreenOptionsMemoryCard::UpdateCurrentUsbStorageDevices() return aOldDevices != m_CurrentUsbStorageDevices; } +static LocalizedString NO_LABEL ("ScreenOptionsMemoryCard", "(no label)" ); +static LocalizedString SIZE_UNKNOWN ("ScreenOptionsMemoryCard", "size ???" ); +static LocalizedString VOLUME_SIZE ("ScreenOptionsMemoryCard", "%dMB" ); void ScreenOptionsMemoryCard::CreateMenu() { vector vHands; FOREACH_CONST( UsbStorageDevice, m_CurrentUsbStorageDevices, iter ) { - // TODO: Make these strings themable vector vs; if( iter->sVolumeLabel.empty() ) - vs.push_back( "(no label)" ); + vs.push_back( NO_LABEL ); else vs.push_back( iter->sVolumeLabel ); if( iter->iVolumeSizeMB == 0 ) - vs.push_back( "size ???" ); + vs.push_back( SIZE_UNKNOWN ); else - vs.push_back( ssprintf("%dMB",iter->iVolumeSizeMB) ); + vs.push_back( ssprintf(RString(VOLUME_SIZE).c_str(),iter->iVolumeSizeMB) ); vHands.push_back( OptionRowHandlerUtil::MakeNull() ); diff --git a/src/ScreenPackagesSSC.cpp b/src/ScreenPackagesSSC.cpp index 7e8123d3f1..be7fb3a8bc 100644 --- a/src/ScreenPackagesSSC.cpp +++ b/src/ScreenPackagesSSC.cpp @@ -4,7 +4,6 @@ #include "RageDisplay.h" #include "RageLog.h" #include "ScreenManager.h" -//#include "jsonxx.h" REGISTER_SCREEN_CLASS( ScreenPackagesSSC ); diff --git a/src/ScreenPrompt.cpp b/src/ScreenPrompt.cpp index f52dc4cfc1..f963c11cd8 100644 --- a/src/ScreenPrompt.cpp +++ b/src/ScreenPrompt.cpp @@ -248,6 +248,22 @@ void ScreenPrompt::TweenOffScreen() ScreenWithMenuElements::TweenOffScreen(); } +// lua start +/* +#include "LuaBinding.h" +class LunaScreenPrompt: public Luna +{ +public: + + LunaScreenPrompt() + { + + } +}; +LUA_REGISTER_DERIVED_CLASS( ScreenPrompt, ScreenWithMenuElements ) +*/ +// lua end + /* * (c) 2001-2004 Chris Danford * All rights reserved. diff --git a/src/ScreenPrompt.h b/src/ScreenPrompt.h index e5ae97bc8b..0273f230f7 100644 --- a/src/ScreenPrompt.h +++ b/src/ScreenPrompt.h @@ -35,6 +35,9 @@ public: static PromptAnswer s_LastAnswer; static bool s_bCancelledLast; + // Lua + //virtual void PushSelf( lua_State *L ); + protected: bool CanGoLeft() { return m_Answer > 0; } bool CanGoRight(); diff --git a/src/ScreenSelect.h b/src/ScreenSelect.h index d3174e3f9a..efdc9e92ab 100644 --- a/src/ScreenSelect.h +++ b/src/ScreenSelect.h @@ -23,14 +23,9 @@ public: protected: virtual int GetSelectionIndex( PlayerNumber pn ) = 0; - virtual void UpdateSelectableChoices() = 0; // derived screens must handle this + virtual void UpdateSelectableChoices() = 0; // derived screens must handle this - vector m_aGameCommands; // derived classes should look here for what choices are available -#if defined(SSC_FUTURES) - // this is gonna become awkward... -aj -#else - vector m_aGameCommandsB; // only used if the theme requires a second list -#endif + vector m_aGameCommands; // derived classes should look here for what choices are available vector m_asSubscribedMessages; diff --git a/src/ScreenSelectLanguage.cpp b/src/ScreenSelectLanguage.cpp index d362f69d68..d07336ec26 100644 --- a/src/ScreenSelectLanguage.cpp +++ b/src/ScreenSelectLanguage.cpp @@ -25,7 +25,7 @@ void ScreenSelectLanguage::Init() gc.m_sText = THEME->GetString("NativeLanguageNames", pLI->szEnglishName); else gc.m_sText = *s; - + m_aGameCommands.push_back( gc ); } diff --git a/src/ScreenSelectMaster.cpp b/src/ScreenSelectMaster.cpp index 08d66a588c..1d0b7d4343 100644 --- a/src/ScreenSelectMaster.cpp +++ b/src/ScreenSelectMaster.cpp @@ -223,7 +223,7 @@ void ScreenSelectMaster::Init() } m_mapCurrentChoiceToNextChoice[dir][c] = c + add; - /* Always wrap around MenuDir_Auto. */ + // Always wrap around MenuDir_Auto. if( dir == MenuDir_Auto || (bool)WRAP_CURSOR ) wrap( m_mapCurrentChoiceToNextChoice[dir][c], m_aGameCommands.size() ); else @@ -392,7 +392,7 @@ try_again: return false; // went full circle and none found seen.insert( iSwitchToIndex ); - if( !m_aGameCommands[iSwitchToIndex].IsPlayable() ) + if( !m_aGameCommands[iSwitchToIndex].IsPlayable() && !DO_SWITCH_ANYWAYS ) goto try_again; return ChangeSelection( pn, dir, iSwitchToIndex ); @@ -551,14 +551,17 @@ bool ScreenSelectMaster::ChangePage( int iNewChoice ) FOREACH( PlayerNumber, vpns, p ) { - if( SHOW_CURSOR ) + if( GAMESTATE->IsHumanPlayer(*p) ) { - m_sprCursor[*p]->HandleMessage( msg ); - m_sprCursor[*p]->SetXY( GetCursorX(*p), GetCursorY(*p) ); - } + if( SHOW_CURSOR ) + { + m_sprCursor[*p]->HandleMessage( msg ); + m_sprCursor[*p]->SetXY( GetCursorX(*p), GetCursorY(*p) ); + } - if( SHOW_SCROLLER ) - m_vsprScroll[*p][m_iChoice[*p]]->HandleMessage( msg ); + if( SHOW_SCROLLER ) + m_vsprScroll[*p][m_iChoice[*p]]->HandleMessage( msg ); + } } if( newPage == PAGE_2 ) @@ -649,8 +652,11 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew if( SHOW_CURSOR ) { - m_sprCursor[*p]->PlayCommand( "Change" ); - m_sprCursor[*p]->SetXY( GetCursorX(*p), GetCursorY(*p) ); + if( GAMESTATE->IsHumanPlayer(*p) ) + { + m_sprCursor[*p]->PlayCommand( "Change" ); + m_sprCursor[*p]->SetXY( GetCursorX(*p), GetCursorY(*p) ); + } } if( SHOW_SCROLLER ) @@ -785,7 +791,6 @@ void ScreenSelectMaster::MenuStart( const InputEventPlus &input ) return; } - const GameCommand &mc = m_aGameCommands[m_iChoice[pn]]; /* If no options are playable, then we're just waiting for one to become available. @@ -802,6 +807,11 @@ void ScreenSelectMaster::MenuStart( const InputEventPlus &input ) if( mc.m_sScreen.empty() ) { mc.ApplyToAllPlayers(); + // We want to be able to broadcast a Start message to the theme, in + // case a themer wants to handle something. -aj + // TODO: Find a way to differentiate this from the message below, for + // less ambiguousness? + MESSAGEMAN->Broadcast( (MessageID)(Message_MenuStartP1+pn) ); return; } @@ -825,7 +835,11 @@ void ScreenSelectMaster::MenuStart( const InputEventPlus &input ) } if( bAllDone ) + { + // broadcast MenuStart just like MenuLeft/Right/etc. + MESSAGEMAN->Broadcast( (MessageID)(Message_MenuStartP1+pn) ); this->PostScreenMessage( SM_BeginFadingOut, fSecs );// tell our owner it's time to move on + } } /* We want all items to always run OnCommand and either GainFocus or LoseFocus @@ -872,7 +886,8 @@ void ScreenSelectMaster::TweenOnScreen() { FOREACH( PlayerNumber, vpns, p ) { - m_sprCursor[*p]->SetXY( GetCursorX(*p), GetCursorY(*p) ); + if( GAMESTATE->IsHumanPlayer(*p) ) + m_sprCursor[*p]->SetXY( GetCursorX(*p), GetCursorY(*p) ); } } @@ -930,7 +945,7 @@ float ScreenSelectMaster::GetCursorY( PlayerNumber pn ) class LunaScreenSelectMaster: public Luna { public: - static int GetSelectionIndex( T* p, lua_State *L ) { lua_pushnumber( L, p->GetSelectionIndexOfPlayer(Enum::Check(L, 1)) ); return 1; } + static int GetSelectionIndex( T* p, lua_State *L ) { lua_pushnumber( L, p->GetPlayerSelectionIndex(Enum::Check(L, 1)) ); return 1; } // should I even bother adding this? -aj // would have to make a public function to get this in ssmaster.h: // m_aGameCommands[i].m_sName diff --git a/src/ScreenSelectMaster.h b/src/ScreenSelectMaster.h index ce94e7bf69..b2f1e30cd1 100644 --- a/src/ScreenSelectMaster.h +++ b/src/ScreenSelectMaster.h @@ -40,7 +40,7 @@ public: virtual bool AllowLateJoin() const { return true; } // sm-ssc additions: - int GetSelectionIndexOfPlayer(PlayerNumber pn){ return GetSelectionIndex(pn); } + int GetPlayerSelectionIndex(PlayerNumber pn){ return GetSelectionIndex(pn); } // Lua virtual void PushSelf( lua_State *L ); diff --git a/src/ScreenSelectMusic.cpp b/src/ScreenSelectMusic.cpp index 0b632f26cb..7f1fe3abaa 100644 --- a/src/ScreenSelectMusic.cpp +++ b/src/ScreenSelectMusic.cpp @@ -76,6 +76,7 @@ void ScreenSelectMusic::Init() SAMPLE_MUSIC_PREVIEW_MODE.Load( m_sName, "SampleMusicPreviewMode" ); SAMPLE_MUSIC_FALLBACK_FADE_IN_SECONDS.Load( m_sName, "SampleMusicFallbackFadeInSeconds" ); DO_ROULETTE_ON_MENU_TIMER.Load( m_sName, "DoRouletteOnMenuTimer" ); + ROULETTE_TIMER_SECONDS.Load( m_sName, "RouletteTimerSeconds" ); ALIGN_MUSIC_BEATS.Load( m_sName, "AlignMusicBeat" ); CODES.Load( m_sName, "Codes" ); MUSIC_WHEEL_TYPE.Load( m_sName, "MusicWheelType" ); @@ -126,11 +127,11 @@ void ScreenSelectMusic::Init() -- Midiman */ m_sSectionMusicPath = THEME->GetPathS(m_sName,"section music"); - m_sSortMusicPath = THEME->GetPathS(m_sName,"sort music"); + m_sSortMusicPath = THEME->GetPathS(m_sName,"sort music"); m_sRouletteMusicPath = THEME->GetPathS(m_sName,"roulette music"); m_sRandomMusicPath = THEME->GetPathS(m_sName,"random music"); m_sCourseMusicPath = THEME->GetPathS(m_sName,"course music"); - m_sLoopMusicPath = THEME->GetPathS(m_sName,"loop music"); + m_sLoopMusicPath = THEME->GetPathS(m_sName,"loop music"); m_sFallbackCDTitlePath = THEME->GetPathG(m_sName,"fallback cdtitle"); @@ -392,7 +393,7 @@ void ScreenSelectMusic::Input( const InputEventPlus &input ) wchar_t c = INPUTMAN->DeviceInputToChar(input.DeviceI,false); MakeUpper( &c, 1 ); - if ( bHoldingCtrl && ( c >= 'A' ) && ( c <= 'Z' ) ) + if( bHoldingCtrl && ( c >= 'A' ) && ( c <= 'Z' ) ) { // Only allow changing the sort order if the wheel is not locked // and we're not in course mode. -aj @@ -1035,14 +1036,11 @@ void ScreenSelectMusic::HandleMessage( const Message &msg ) ASSERT( b ); // load player profiles - // (this could be a possible cause of the screenshot bug. I'm not sure. -aj) - /* if( GAMESTATE->HaveProfileToLoad() ) { GAMESTATE->LoadProfiles( true ); // I guess you could always load edits here... SCREENMAN->ZeroNextUpdate(); // be kind, don't skip frames if you can avoid it } - */ m_iSelection[pn] = iSel; if( GAMESTATE->IsCourseMode() ) @@ -1071,15 +1069,13 @@ void ScreenSelectMusic::HandleScreenMessage( const ScreenMessage SM ) if( m_MusicWheel.IsRouletting() ) { MenuStart( InputEventPlus() ); - // todo: make this value a metric -aj - m_MenuTimer->SetSeconds( 15 ); + m_MenuTimer->SetSeconds( ROULETTE_TIMER_SECONDS ); m_MenuTimer->Start(); } else if( DO_ROULETTE_ON_MENU_TIMER && m_MusicWheel.GetSelectedSong() == NULL && m_MusicWheel.GetSelectedCourse() == NULL ) { m_MusicWheel.StartRoulette(); - // todo: make this value a metric -aj - m_MenuTimer->SetSeconds( 15 ); + m_MenuTimer->SetSeconds( ROULETTE_TIMER_SECONDS ); m_MenuTimer->Start(); } else @@ -1673,49 +1669,61 @@ void ScreenSelectMusic::AfterMusicChange() g_sCDTitlePath = ""; // none - if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong ) + if( SAMPLE_MUSIC_PREVIEW_MODE == SampleMusicPreviewMode_LastSong ) { - m_fSampleStartSeconds = 0; - m_fSampleLengthSeconds = -1; - } - else - { - // HACK: Make random music work in LastSong mode (IDK if this is - // accurate or not) -aj + // HACK: Make random music work in LastSong mode. -aj if( m_sSampleMusicToPlay == m_sRandomMusicPath ) { m_fSampleStartSeconds = 0; m_fSampleLengthSeconds = -1; } } + else + { + m_fSampleStartSeconds = 0; + m_fSampleLengthSeconds = -1; + } switch( m_MusicWheel.GetSelectedType() ) { - case TYPE_SECTION: - g_sBannerPath = SONGMAN->GetSongGroupBannerPath( m_MusicWheel.GetSelectedSection() ); - if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong ) - m_sSampleMusicToPlay = m_sSectionMusicPath; - break; - case TYPE_SORT: - bWantBanner = false; // we load it ourself - m_Banner.LoadMode(); - if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong ) - m_sSampleMusicToPlay = m_sSortMusicPath; - break; - case TYPE_ROULETTE: - bWantBanner = false; // we load it ourself - m_Banner.LoadRoulette(); - if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong ) - m_sSampleMusicToPlay = m_sRouletteMusicPath; - break; - case TYPE_RANDOM: - bWantBanner = false; // we load it ourself - m_Banner.LoadRandom(); - //if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong ) - m_sSampleMusicToPlay = m_sRandomMusicPath; - break; - default: - ASSERT(0); + case TYPE_SECTION: + // reduce scope + { + SortOrder curSort = GAMESTATE->m_SortOrder; + if( curSort == SORT_GROUP) + { + g_sBannerPath = SONGMAN->GetSongGroupBannerPath( m_MusicWheel.GetSelectedSection() ); + } + else + { + bWantBanner = false; // we load it ourself + m_Banner.LoadFromSortOrder(curSort); + } + + if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong ) + m_sSampleMusicToPlay = m_sSectionMusicPath; + } + break; + case TYPE_SORT: + bWantBanner = false; // we load it ourself + m_Banner.LoadMode(); + if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong ) + m_sSampleMusicToPlay = m_sSortMusicPath; + break; + case TYPE_ROULETTE: + bWantBanner = false; // we load it ourself + m_Banner.LoadRoulette(); + if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong ) + m_sSampleMusicToPlay = m_sRouletteMusicPath; + break; + case TYPE_RANDOM: + bWantBanner = false; // we load it ourself + m_Banner.LoadRandom(); + //if( SAMPLE_MUSIC_PREVIEW_MODE != SampleMusicPreviewMode_LastSong ) + m_sSampleMusicToPlay = m_sRandomMusicPath; + break; + default: + ASSERT(0); } // override this if the sample music mode wants to. /* diff --git a/src/ScreenSelectMusic.h b/src/ScreenSelectMusic.h index c69425bc9e..89ab2aec16 100644 --- a/src/ScreenSelectMusic.h +++ b/src/ScreenSelectMusic.h @@ -73,6 +73,7 @@ protected: ThemeMetric SAMPLE_MUSIC_PREVIEW_MODE; ThemeMetric SAMPLE_MUSIC_FALLBACK_FADE_IN_SECONDS; ThemeMetric DO_ROULETTE_ON_MENU_TIMER; + ThemeMetric ROULETTE_TIMER_SECONDS; ThemeMetric ALIGN_MUSIC_BEATS; ThemeMetric CODES; ThemeMetric MUSIC_WHEEL_TYPE; diff --git a/src/ScreenSelectProfile.cpp b/src/ScreenSelectProfile.cpp index 6f51733e2d..cdf1bfd21d 100644 --- a/src/ScreenSelectProfile.cpp +++ b/src/ScreenSelectProfile.cpp @@ -279,4 +279,4 @@ LUA_REGISTER_DERIVED_CLASS( ScreenSelectProfile, ScreenWithMenuElements ) * 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. - */ \ No newline at end of file + */ diff --git a/src/ScreenServiceAction.cpp b/src/ScreenServiceAction.cpp index 638d8bd4b1..d223c52299 100644 --- a/src/ScreenServiceAction.cpp +++ b/src/ScreenServiceAction.cpp @@ -15,7 +15,7 @@ #include "PlayerState.h" #include "LocalizedString.h" #include "StepMania.h" -#include "NotesLoaderSM.h" +#include "NotesLoaderSSC.h" static LocalizedString BOOKKEEPING_DATA_CLEARED( "ScreenServiceAction", "Bookkeeping data cleared." ); static RString ClearBookkeepingData() @@ -197,7 +197,7 @@ 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( !SMLoader::LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) ) + if( !SSCLoader::LoadEditFromFile( sFromDir+*i, ProfileSlot_Machine, false ) ) { iNumIgnored++; continue; diff --git a/src/ScreenTextEntry.cpp b/src/ScreenTextEntry.cpp index a1e318b207..e074d4baa0 100644 --- a/src/ScreenTextEntry.cpp +++ b/src/ScreenTextEntry.cpp @@ -11,6 +11,8 @@ #include "InputEventPlus.h" #include "RageInput.h" #include "LocalizedString.h" +#include "RageLog.h" +#include "LuaBinding.h" static const char* g_szKeys[NUM_KeyboardRow][KEYS_PER_ROW] = { @@ -26,7 +28,7 @@ static const char* g_szKeys[NUM_KeyboardRow][KEYS_PER_ROW] = RString ScreenTextEntry::s_sLastAnswer = ""; -/* Settings: */ +// Settings: namespace { RString g_sQuestion; @@ -38,6 +40,13 @@ namespace bool g_bPassword; bool (*g_pValidateAppend)(const RString &sAnswerBeforeChar, RString &sAppend); RString (*g_pFormatAnswerForDisplay)(const RString &sAnswer); + + // Lua bridge + LuaReference g_ValidateFunc; + LuaReference g_OnOKFunc; + LuaReference g_OnCancelFunc; + LuaReference g_ValidateAppendFunc; + LuaReference g_FormatAnswerForDisplayFunc; }; void ScreenTextEntry::SetTextEntrySettings( @@ -74,7 +83,7 @@ void ScreenTextEntry::TextEntry( bool (*ValidateAppend)(const RString &sAnswerBeforeChar, RString &sAppend), RString (*FormatAnswerForDisplay)(const RString &sAnswer) ) -{ +{ g_sQuestion = sQuestion; g_sInitialAnswer = sInitialAnswer; g_iMaxInputLength = iMaxInputLength; @@ -100,13 +109,11 @@ bool ScreenTextEntry::FloatValidate( const RString &sAnswer, RString &sErrorOut bool ScreenTextEntry::s_bCancelledLast = false; -/* - * Handle UTF-8. Right now, we need to at least be able to backspace - * a whole UTF-8 character. Better would be to operate in wchar_t. +/* Handle UTF-8. Right now, we need to at least be able to backspace a whole + * UTF-8 character. Better would be to operate in wchar_t. * - * XXX: Don't allow internal-use codepoints (above 0xFFFF); those are - * subject to change and shouldn't be written to disk. - */ + * XXX: Don't allow internal-use codepoints (above 0xFFFF); those are subject to + * change and shouldn't be written to disk. */ REGISTER_SCREEN_CLASS( ScreenTextEntry ); REGISTER_SCREEN_CLASS( ScreenTextEntryVisual ); @@ -297,6 +304,262 @@ void ScreenTextEntry::MenuBack( const InputEventPlus &input ) End( true ); } +void ScreenTextEntry::TextEntrySettings::FromStack( lua_State *L ) +{ + if( lua_type(L, 1) != LUA_TTABLE ) + { + LOG->Trace("not a table"); + return; + } + + lua_pushvalue( L, 1 ); + const int iTab = lua_gettop( L ); + + // Get ScreenMessage + lua_getfield( L, iTab, "SendOnPop" ); + const char *pStr = lua_tostring( L, -1 ); + if( pStr == NULL ) + smSendOnPop = SM_None; + else + smSendOnPop = ScreenMessageHelpers::ToScreenMessage( pStr ); + lua_settop( L, iTab ); + + // Get Question + lua_getfield( L, iTab, "Question" ); + pStr = lua_tostring( L, -1 ); + if( pStr == NULL ) + RageException::Throw( "\"Question\" entry is not a string." ); + sQuestion = pStr; + lua_settop( L, iTab ); + + // Get Initial Answer + lua_getfield( L, iTab, "InitialAnswer" ); + pStr = lua_tostring( L, -1 ); + if( pStr == NULL ) + pStr = ""; + sInitialAnswer = pStr; + lua_settop( L, iTab ); + + // Get Max Input Length + lua_getfield( L, iTab, "MaxInputLength" ); + iMaxInputLength = lua_tointeger( L, -1 ); + lua_settop( L, iTab ); + + // Get Password + lua_getfield( L, iTab, "Password" ); + bPassword = !!lua_toboolean( L, -1 ); + lua_settop( L, iTab ); + + // and now the hard part, the functions. + // Validate + lua_getfield( L, iTab, "Validate" ); + if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) ) + RageException::Throw( "\"Validate\" is not a function." ); + Validate.SetFromStack( L ); + lua_settop( L, iTab ); + + // OnOK + lua_getfield( L, iTab, "OnOK" ); + if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) ) + RageException::Throw( "\"OnOK\" is not a function." ); + OnOK.SetFromStack( L ); + lua_settop( L, iTab ); + + // OnCancel + lua_getfield( L, iTab, "OnCancel" ); + if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) ) + RageException::Throw( "\"OnCancel\" is not a function." ); + OnCancel.SetFromStack( L ); + lua_settop( L, iTab ); + + // ValidateAppend + lua_getfield( L, iTab, "ValidateAppend" ); + if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) ) + RageException::Throw( "\"ValidateAppend\" is not a function." ); + ValidateAppend.SetFromStack( L ); + lua_settop( L, iTab ); + + // FormatAnswerForDisplay + lua_getfield( L, iTab, "FormatAnswerForDisplay" ); + if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) ) + RageException::Throw( "\"FormatAnswerForDisplay\" is not a function." ); + FormatAnswerForDisplay.SetFromStack( L ); + lua_settop( L, iTab ); +} + +// Lua bridges +static bool ValidateFromLua( const RString &sAnswer, RString &sErrorOut ) +{ + Lua *L = LUA->Get(); + + if( g_ValidateFunc.IsNil() ) + { + LUA->Release(L); + return true; + } + + g_ValidateFunc.PushSelf( L ); + + // Argument 1 (answer): + lua_pushstring( L, sAnswer ); + + // Argument 2 (error out): + lua_pushstring( L, sErrorOut ); + + lua_call( L, 2, 2 ); // call function with 2 arguments and 2 results + + if( !lua_isstring(L, -1) ) + RageException::Throw( "\"Validate\" did not return a string." ); + + if( !lua_isboolean(L, -2) ) + RageException::Throw( "\"Validate\" did not return a boolean." ); + + RString sErrorFromLua; + LuaHelpers::Pop( L, sErrorFromLua ); + if( !sErrorFromLua.empty() ) + sErrorOut = sErrorFromLua; + + bool bValidate; + LuaHelpers::Pop( L, bValidate ); + + LUA->Release(L); + return bValidate; +} + +static void OnOKFromLua( const RString &sAnswer ) +{ + Lua *L = LUA->Get(); + + if( g_OnOKFunc.IsNil() ) + { + LUA->Release(L); + return; + } + + g_OnOKFunc.PushSelf( L ); + // Argument 1 (answer): + lua_pushstring( L, sAnswer ); + lua_call( L, 1, 0 ); // call function with 1 argument and 0 results + + LUA->Release(L); +} + +static void OnCancelFromLua() +{ + Lua *L = LUA->Get(); + + if( g_OnCancelFunc.IsNil() ) + { + LUA->Release(L); + return; + } + + g_OnCancelFunc.PushSelf( L ); + lua_call( L, 0, 0 ); // call function with 0 arguments and 0 results + + LUA->Release(L); +} + +static bool ValidateAppendFromLua( const RString &sAnswerBeforeChar, RString &sAppend ) +{ + Lua *L = LUA->Get(); + + if( g_ValidateAppendFunc.IsNil() ) + { + LUA->Release(L); + return true; + } + + g_ValidateAppendFunc.PushSelf( L ); + + // Argument 1 (AnswerBeforeChar): + lua_pushstring( L, sAnswerBeforeChar ); + + // Argument 2 (Append): + lua_pushstring( L, sAppend ); + lua_call( L, 2, 1 ); // call function with 2 arguments and 1 result + + if( !lua_isboolean(L, -1) ) + RageException::Throw( "\"ValidateAppend\" did not return a boolean." ); + + bool bAppend; + LuaHelpers::Pop( L, bAppend ); + + LUA->Release(L); + return bAppend; +} + +static RString FormatAnswerForDisplayFromLua( const RString &sAnswer ) +{ + Lua *L = LUA->Get(); + + if( g_FormatAnswerForDisplayFunc.IsNil() ) + { + LUA->Release(L); + return sAnswer; + } + + g_FormatAnswerForDisplayFunc.PushSelf( L ); + // Argument 1 (Answer): + lua_pushstring( L, sAnswer ); + lua_call( L, 1, 1 ); // call function with 1 argument and 1 result + + if( !lua_isstring(L, -1) ) + RageException::Throw( "\"FormatAnswerForDisplay\" did not return a string." ); + + RString sAnswerFromLua; + LuaHelpers::Pop( L, sAnswerFromLua ); + + LUA->Release(L); + return sAnswerFromLua; +} + +void ScreenTextEntry::LoadFromTextEntrySettings( const TextEntrySettings &settings ) +{ + g_ValidateFunc = settings.Validate; + g_OnOKFunc = settings.OnOK; + g_OnCancelFunc = settings.OnCancel; + g_ValidateAppendFunc = settings.ValidateAppend; + g_FormatAnswerForDisplayFunc = settings.FormatAnswerForDisplay; + + // set functions + SetTextEntrySettings( + settings.sQuestion, + settings.sInitialAnswer, + settings.iMaxInputLength, + ValidateFromLua, // Validate + OnOKFromLua, // OnOK + OnCancelFromLua, // OnCancel + settings.bPassword, + ValidateAppendFromLua, // ValidateAppend + FormatAnswerForDisplayFromLua // FormatAnswerForDisplay + ); + + // Hack: reload screen with new info + BeginScreen(); +} + +// lua start +class LunaScreenTextEntry: public Luna +{ +public: + static int Load( T* p, lua_State *L ) + { + ScreenTextEntry::TextEntrySettings settings; + settings.FromStack( L ); + p->LoadFromTextEntrySettings(settings); + return 0; + } + + LunaScreenTextEntry() + { + ADD_METHOD( Load ); + } +}; +LUA_REGISTER_DERIVED_CLASS( ScreenTextEntry, ScreenWithMenuElements ) +// lua end + +// begin ScreenTextEntryVisual void ScreenTextEntryVisual::Init() { ROW_START_X.Load( m_sName, "RowStartX" ); diff --git a/src/ScreenTextEntry.h b/src/ScreenTextEntry.h index a1a87c0249..04d2b0ffe0 100644 --- a/src/ScreenTextEntry.h +++ b/src/ScreenTextEntry.h @@ -58,6 +58,26 @@ public: TextEntry( smSendOnPop, sQuestion, "", 255, NULL, OnOK, OnCancel, true ); } + struct TextEntrySettings { + TextEntrySettings() { } + ScreenMessage smSendOnPop; + RString sQuestion; + RString sInitialAnswer; + int iMaxInputLength; + bool bPassword; // (optional) + LuaReference Validate; // (RString sAnswer, RString sErrorOut; optional) + LuaReference OnOK; // (RString sAnswer; optional) + LuaReference OnCancel; // (optional) + LuaReference ValidateAppend; // (RString sAnswerBeforeChar, RString sAppend; optional) + LuaReference FormatAnswerForDisplay; // (RString sAnswer; optional) + + // see BitmapText.cpp Attribute::FromStack() and + // OptionRowHandler.cpp LoadInternal() for ideas on how to implement the + // main part, and ImportOption() from OptionRowHandler.cpp for functions. + void FromStack( lua_State *L ); + }; + void LoadFromTextEntrySettings( const TextEntrySettings &settings ); + static bool FloatValidate( const RString &sAnswer, RString &sErrorOut ); virtual void Init(); @@ -69,6 +89,9 @@ public: static RString s_sLastAnswer; static bool s_bCancelledLast; + // Lua + virtual void PushSelf( lua_State *L ); + protected: void TryAppendToAnswer( RString s ); void BackspaceInAnswer(); @@ -81,16 +104,16 @@ private: void UpdateAnswerText(); - wstring m_sAnswer; - bool m_bShowAnswerCaret; + wstring m_sAnswer; + bool m_bShowAnswerCaret; - BitmapText m_textQuestion; - BitmapText m_textAnswer; + BitmapText m_textQuestion; + BitmapText m_textAnswer; - RageSound m_sndType; - RageSound m_sndBackspace; + RageSound m_sndType; + RageSound m_sndBackspace; - RageTimer m_timerToggleCursor; + RageTimer m_timerToggleCursor; }; class ScreenTextEntryVisual: public ScreenTextEntry @@ -107,20 +130,20 @@ protected: virtual void TextEnteredDirectly(); - virtual void MenuLeft( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveX(-1); } - virtual void MenuRight( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveX(+1); } - virtual void MenuUp( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveY(-1); } - virtual void MenuDown( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveY(+1); } + virtual void MenuLeft( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveX(-1); } + virtual void MenuRight( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveX(+1); } + virtual void MenuUp( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveY(-1); } + virtual void MenuDown( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveY(+1); } virtual void MenuStart( const InputEventPlus &input ); int m_iFocusX; - KeyboardRow m_iFocusY; + KeyboardRow m_iFocusY; - AutoActor m_sprCursor; - BitmapText *m_ptextKeys[NUM_KeyboardRow][KEYS_PER_ROW]; + AutoActor m_sprCursor; + BitmapText *m_ptextKeys[NUM_KeyboardRow][KEYS_PER_ROW]; - RageSound m_sndChange; + RageSound m_sndChange; ThemeMetric ROW_START_X; ThemeMetric ROW_START_Y; diff --git a/src/Song.cpp b/src/Song.cpp index 9860db5b50..b4e7fe088d 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -25,8 +25,10 @@ #include "SpecialFiles.h" #include "NotesLoader.h" #include "NotesLoaderSM.h" +#include "NotesLoaderSSC.h" #include "NotesWriterDWI.h" #include "NotesWriterSM.h" +#include "NotesWriterSSC.h" #include "UnlockManager.h" #include "LyricsLoader.h" @@ -34,13 +36,14 @@ #include #include -const int FILE_CACHE_VERSION = 161; // increment this to invalidate cache +const static float VERSION_NUMBER = 0.51f; +const int FILE_CACHE_VERSION = 163; // increment this to invalidate cache const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f; -static Preference g_fLongVerSongSeconds( "LongVerSongSeconds", 60*2.5f ); -static Preference g_fMarathonVerSongSeconds( "MarathonVerSongSeconds", 60*5.f ); -static Preference g_BackUpAllSongSaves( "BackUpAllSongSaves", false ); +static Preference g_fLongVerSongSeconds( "LongVerSongSeconds", 60*2.5f ); +static Preference g_fMarathonVerSongSeconds( "MarathonVerSongSeconds", 60*5.f ); +static Preference g_BackUpAllSongSaves( "BackUpAllSongSaves", false ); static const char *InstrumentTrackNames[] = { "Guitar", @@ -57,6 +60,7 @@ Song::Song() m_ForegroundChanges = AutoPtrCopyOnWrite(new VBackgroundChange); m_LoadedFromProfile = ProfileSlot_Invalid; + m_fVersion = VERSION_NUMBER; m_fMusicSampleStartSeconds = -1; m_fMusicSampleLengthSeconds = DEFAULT_MUSIC_SAMPLE_LENGTH; m_fMusicLengthSeconds = 0; @@ -91,7 +95,7 @@ void Song::DetachSteps() m_vpStepsByType[st].clear(); } -/* Reset to an empty song. */ +// Reset to an empty song. void Song::Reset() { FOREACH( Steps*, m_vpSteps, s ) @@ -166,23 +170,20 @@ RString Song::GetCacheFilePath() const return SongCacheIndex::GetCacheFilePath( "Songs", m_sSongDir ); } -/* Get a path to the SM containing data for this song. It might - * be a cache file. */ +// 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() ); return m_sSongFileName; } -/* Hack: This should be a parameter to TidyUpData, but I don't want to - * pull in into Song.h, which is heavily used. */ +/* Hack: This should be a parameter to TidyUpData, but I don't want to pull in + * into Song.h, which is heavily used. */ static set BlacklistedImages; -/* - * If PREFSMAN->m_bFastLoad is true, always load from cache if possible. Don't read - * the contents of sDir if we can avoid it. That means we can't call HasMusic(), - * HasBanner() or GetHashForDirectory(). - * +/* If PREFSMAN->m_bFastLoad is true, always load from cache if possible. + * Don't read the contents of sDir if we can avoid it. That means we can't call + * HasMusic(), HasBanner() or GetHashForDirectory(). * If true, check the directory hash and reload the song from scratch if it's changed. */ bool Song::LoadFromSongDir( RString sDir ) @@ -204,9 +205,7 @@ bool Song::LoadFromSongDir( RString sDir ) m_sGroupName = sDirectoryParts[sDirectoryParts.size()-3]; // second from last item ASSERT( m_sGroupName != "" ); - // - // First look in the cache for this song (without loading NoteData) - // + // First, look in the cache for this song (without loading NoteData) unsigned uCacheHash = SONGINDEX->GetCacheHash(m_sSongDir); bool bUseCache = true; RString sCacheFilePath = GetCacheFilePath(); @@ -219,16 +218,14 @@ bool Song::LoadFromSongDir( RString sDir ) if( bUseCache ) { // LOG->Trace( "Loading '%s' from cache file '%s'.", m_sSongDir.c_str(), GetCacheFilePath().c_str() ); - SMLoader::LoadFromSMFile( sCacheFilePath, *this, true ); - SMLoader::TidyUpData( *this, true ); + SSCLoader::LoadFromSSCFile( sCacheFilePath, *this, true ); + SSCLoader::TidyUpData( *this, true ); } else { - // // There was no entry in the cache for this song, or it was out of date. // Let's load it from a file, then write a cache entry. - // - + if( !NotesLoader::LoadFromDir(sDir, *this, BlacklistedImages) ) { LOG->UserLog( "Song", sDir, "has no SM, DWI, BMS, or KSF files." ); @@ -254,27 +251,25 @@ bool Song::LoadFromSongDir( RString sDir ) sCacheFilePath = RString(); } - - 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. */ + /* Compress all Steps. During initial caching, this will remove cached + * NoteData; during cached loads, this will just remove cached SMData. */ (*s)->Compress(); } - /* Load the cached banners, if it's not loaded already. */ + // Load the cached banners, if it's not loaded already. if( PREFSMAN->m_BannerCache == BNCACHE_LOW_RES_PRELOAD && m_bHasBanner ) BANNERCACHE->LoadBanner( GetBannerPath() ); - /* Load the cached background, if it's not loaded already. */ + // Load the cached background, if it's not loaded already. /* if( PREFSMAN->m_BackgroundCache == BGCACHE_LOW_RES_PRELOAD && m_bHasBackground ) BACKGROUNDCACHE->LoadBackground( GetBackgroundPath() ); */ - /* Add AutoGen pointers. (These aren't cached.) */ + // Add AutoGen pointers. (These aren't cached.) AddAutoGenNotes(); if( !m_bHasMusic ) @@ -356,31 +351,33 @@ static void GetImageDirListing( RString sPath, vector &AddTo ) GetDirListing( sPath + ".gif", AddTo, false, false ); } -/* Fix up song paths. If there's a leading "./", be sure to keep it: it's +/* Fix up song paths. If there's a leading "./", be sure to keep it: it's * a signal that the path is from the root directory, not the song directory. * Other than a leading "./", song paths must never contain "." or "..". */ void FixupPath( RString &path, const RString &sSongPath ) { - /* Replace backslashes with slashes in all paths. */ + // Replace backslashes with slashes in all paths. FixSlashesInPlace( path ); /* Many imported files contain erroneous whitespace before or after - * filenames. Paths usually don't actually start or end with spaces, + * filenames. Paths usually don't actually start or end with spaces, * so let's just remove it. */ Trim( path ); } -/* Songs in BlacklistImages will never be autodetected as song images. */ +// Songs in BlacklistImages will never be autodetected as song images. void Song::TidyUpData() { - /* We need to do this before calling any of HasMusic, HasHasCDTitle, etc. */ - ASSERT_M( m_sSongDir.Left(3) != "../", m_sSongDir ); /* meaningless */ + // We need to do this before calling any of HasMusic, HasHasCDTitle, etc. + ASSERT_M( m_sSongDir.Left(3) != "../", m_sSongDir ); // meaningless FixupPath( m_sSongDir, "" ); FixupPath( m_sMusicFile, m_sSongDir ); FOREACH_ENUM( InstrumentTrack, i ) if( !m_sInstrumentTrackFile[i].empty() ) FixupPath( m_sInstrumentTrackFile[i], m_sSongDir ); FixupPath( m_sBannerFile, m_sSongDir ); + //FixupPath( m_sJacketFile, m_sSongDir ); + //FixupPath( m_sDiscFile, m_sSongDir ); FixupPath( m_sLyricsFile, m_sSongDir ); FixupPath( m_sBackgroundFile, m_sSongDir ); FixupPath( m_sCDTitleFile, m_sSongDir ); @@ -397,7 +394,8 @@ void Song::TidyUpData() { int idx = 0; /* If the first song is "intro", and we have more than one available, - * don't use it--it's probably a KSF intro music file, which we don't support. */ + * don't use it--it's probably a KSF intro music file, which we don't + * (yet) support. */ if( arrayPossibleMusic.size() > 1 && !arrayPossibleMusic[0].Left(5).CompareNoCase("intro") ) ++idx; @@ -407,18 +405,19 @@ void Song::TidyUpData() } } - /* This must be done before radar calculation. */ + // This must be done before radar calculation. if( HasMusic() ) { RString error; RageSoundReader *Sample = RageSoundReader_FileReader::OpenFile( GetMusicPath(), error ); - /* XXX: Checking if the music file exists eliminates a warning originating from BMS files - * (which have no music file, per se) but it's something of a hack. */ + /* XXX: Checking if the music file exists eliminates a warning + * originating from BMS files (which have no music file, per se) + * but it's something of a hack. */ if( Sample == NULL && m_sMusicFile != "" ) { LOG->UserLog( "Sound file", GetMusicPath(), "couldn't be opened: %s", error.c_str() ); - /* Don't use this file. */ + // Don't use this file. m_sMusicFile = ""; } else if ( Sample != NULL ) @@ -428,7 +427,7 @@ void Song::TidyUpData() if( m_fMusicLengthSeconds < 0 ) { - /* It failed; bad file or something. It's already logged a warning. */ + // It failed; bad file or something. It's already logged a warning. m_fMusicLengthSeconds = 100; // guess } else if( m_fMusicLengthSeconds == 0 ) @@ -439,7 +438,7 @@ void Song::TidyUpData() } else // ! HasMusic() { - m_fMusicLengthSeconds = 100; // guess + m_fMusicLengthSeconds = 100; // guess LOG->UserLog( "Song", GetSongDir(), "has no music file; guessing at %f seconds", m_fMusicLengthSeconds ); } @@ -457,7 +456,7 @@ void Song::TidyUpData() Trim( m_sSubTitle ); Trim( m_sArtist ); - /* Fall back on the song directory name. */ + // Fall back on the song directory name. if( m_sMainTitle == "" ) NotesLoader::GetMainAndSubTitlesFromFullTitle( Basename(this->GetSongDir()), m_sMainTitle, m_sSubTitle ); @@ -471,8 +470,8 @@ void Song::TidyUpData() m_Timing.AddBPMSegment( BPMSegment(0, 60) ); } - - /* Make sure the first BPM segment starts at beat 0. */ + + // Make sure the first BPM segment starts at beat 0. if( m_Timing.m_BPMSegments[0].m_iStartRow != 0 ) m_Timing.m_BPMSegments[0].m_iStartRow = 0; @@ -490,33 +489,31 @@ void Song::TidyUpData() m_fMusicSampleStartSeconds = this->GetElapsedTimeFromBeat( (float)iBeat ); } } - - /* Some DWIs have lengths in ms when they meant seconds, eg. #SAMPLELENGTH:10;. - * If the sample length is way too short, change it. */ - // oh also this means that if you try to have a sample length longer - // than 30 seconds, it won't work. -aj - if( m_fMusicSampleLengthSeconds < 3 || m_fMusicSampleLengthSeconds > 30 ) + // The old logic meant that you couldn't have sample lengths that go forever, + // e.g. those in Donkey Konga. I never liked that. -freem + if( m_fMusicSampleLengthSeconds <= 0.00f ) m_fMusicSampleLengthSeconds = DEFAULT_MUSIC_SAMPLE_LENGTH; - // Here's the problem: We have a directory full of images. We want to determine which - // image is the banner, which is the background, and which is the CDTitle. + // Here's the problem: We have a directory full of images. We want to + // determine which image is the banner, which is the background, and which + // is the CDTitle. CHECKPOINT_M( "Looking for images..." ); // First, check the file name for hints. if( !HasBanner() ) { - /* If a nonexistant banner file is specified, and we can't find a replacement, - * don't wipe out the old value. */ + /* If a nonexistant banner file is specified, and we can't find a + * replacement, don't wipe out the old value. */ // m_sBannerFile = ""; // find an image with "banner" in the file name vector arrayPossibleBanners; GetImageDirListing( m_sSongDir + "*banner*", arrayPossibleBanners ); - /* Some people do things differently for the sake of being different. Don't - * match eg. abnormal, numbness. */ + /* Some people do things differently for the sake of being different. + * Don't match eg. abnormal, numbness. */ GetImageDirListing( m_sSongDir + "* BN", arrayPossibleBanners ); if( !arrayPossibleBanners.empty() ) @@ -535,6 +532,38 @@ void Song::TidyUpData() m_sBackgroundFile = arrayPossibleBGs[0]; } + /* + if( !HasJacket() ) + { + // find an image with "jacket" or "albumart" in the filename. + vector arrayPossibleJackets; + GetImageDirListing( m_sSongDir + "jk_*", arrayPossibleJackets ); + GetImageDirListing( m_sSongDir + "*jacket*", arrayPossibleJackets ); + GetImageDirListing( m_sSongDir + "*albumart*", arrayPossibleJackets ); + if( !arrayPossibleJackets.empty() ) + m_sJacketFile = arrayPossibleJackets[0]; + } + */ + + /* + if( !HasCDImage() ) + { + // CD image, a la ddr 1st-3rd (not to be confused with CDTitles) + // find an image with "cd" at the end of the filename. + vector arrayPossibleCDImages; + GetImageDirListing( m_sSongDir + "* CD", arrayPossibleCDImages ); + if( !arrayPossibleCDImages.empty() ) + m_sCDFile = arrayPossibleCDImages[0]; + } + */ + + /* + if( !HasDisc() ) + { + // a rectangular graphic, not to be confused with CDImage above. + } + */ + if( !HasCDTitle() ) { // find an image with "cdtitle" in the file name @@ -560,14 +589,14 @@ void Song::TidyUpData() for( unsigned i=0; i 200 && float(width) / height > 2.0f ) { m_sBannerFile = arrayImages[i]; continue; } - /* Agh. DWI's inline title images are triggering this, resulting in kanji, - * etc., being used as a CDTitle for songs with none. Some sample data - * from random incarnations: + /* Agh. DWI's inline title images are triggering this, resulting in + * kanji, etc., being used as a CDTitle for songs with none. Some + * sample data from random incarnations: * 42x50 35x50 50x50 144x49 * It looks like ~50 height is what people use to align to DWI's font. * - * My tallest CDTitle is 44. Let's cut off in the middle and hope for - * the best. */ + * My tallest CDTitle is 44. Let's cut off in the middle and hope for + * the best. -(who? -aj) */ /* The proper size of a CDTitle is 64x48 or sometihng. Simfile artists * typically don't give a shit about this (see Cetaka's fucking banner * -sized CDTitle). This is also subverted in certain designs (beta @@ -640,9 +671,11 @@ void Song::TidyUpData() m_sCDTitleFile = arrayImages[i]; continue; } + + // todo: add checks for Jacket, Disc, and CDImage -aj } - /* These will be written to cache, for Song::LoadFromSongDir to use later. */ + // These will be written to cache, for Song::LoadFromSongDir to use later. m_bHasMusic = HasMusic(); m_bHasBanner = HasBanner(); m_bHasBackground = HasBackground(); @@ -670,20 +703,21 @@ void Song::TidyUpData() } - /* Don't allow multiple Steps of the same StepsType and Difficulty (except for edits). - * We should be able to use difficulty names as unique identifiers for steps. */ + /* Don't allow multiple Steps of the same StepsType and Difficulty (except + * 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 an .SM. + * 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 + * 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 + * 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. * @@ -691,29 +725,37 @@ void Song::TidyUpData() * but not KSFs and BMSs. * * So, let's do this (by priority): - * 1. If there's an .SM file, use that filename. No reason to use anything + * 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 a .DWI, use it with a changed extension. - * 3. 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). - */ + * 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; - GetDirListing( m_sSongDir+"*.sm", asFileNames ); + GetDirListing( m_sSongDir+"*.ssc", asFileNames ); if( !asFileNames.empty() ) + { m_sSongFileName += asFileNames[0]; - else { - GetDirListing( m_sSongDir+"*.dwi", asFileNames ); - if( !asFileNames.empty() ) { - m_sSongFileName += SetExtension( asFileNames[0], "sm" ); - } else { - m_sSongFileName += Basename(m_sSongDir); - m_sSongFileName += ".sm"; + } + else + { + GetDirListing( m_sSongDir+"*.sm", asFileNames ); + if( !asFileNames.empty() ) + m_sSongFileName += SetExtension( asFileNames[0], "ssc" ); + else { + GetDirListing( m_sSongDir+"*.dwi", asFileNames ); + if( !asFileNames.empty() ) { + m_sSongFileName += SetExtension( asFileNames[0], "ssc" ); + } else { + m_sSongFileName += Basename(m_sSongDir); + m_sSongFileName += ".ssc"; + } } } } - /* If no time signature specified, assume 4/4 time for the whole song. */ + // If no time signature specified, assume 4/4 time for the whole song. if( m_Timing.m_vTimeSignatureSegments.empty() ) { TimeSignatureSegment seg; @@ -722,6 +764,19 @@ void Song::TidyUpData() seg.m_iDenominator = 4; m_Timing.m_vTimeSignatureSegments.push_back( seg ); } + + /* + * 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_Timing.m_TickcountSegments.empty() ) + { + TickcountSegment seg; + seg.m_iStartRow = 0; + seg.m_iTicks = 2; + m_Timing.m_TickcountSegments.push_back( seg ); + } } void Song::TranslateTitles() @@ -736,7 +791,7 @@ void Song::TranslateTitles() void Song::ReCalculateRadarValuesAndLastBeat() { - float fFirstBeat = FLT_MAX; /* inf */ + float fFirstBeat = FLT_MAX; // inf float fLastBeat = m_fSpecifiedLastBeat; // Make sure we're at least as long as the specified amount. for( unsigned i=0; iGetNoteData( tempNoteData ); - /* Many songs have stray, empty song patterns. Ignore them, so - * they don't force the first beat of the whole song to 0. */ + /* 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; @@ -778,7 +833,7 @@ void Song::ReCalculateRadarValuesAndLastBeat() m_fLastBeat = fLastBeat; } -/* Return whether the song is playable in the given style. */ +// Return whether the song is playable in the given style. bool Song::SongCompleteForStyle( const Style *st ) const { return HasStepsType( st->m_StepsType ); @@ -801,14 +856,15 @@ void Song::Save() ReCalculateRadarValuesAndLastBeat(); TranslateTitles(); - /* Save the new files. These calls make backups on their own. */ - if( !SaveToSMFile(GetSongFilePath(), false) ) + // Save the new files. These calls make backups on their own. + if( !SaveToSSCFile(GetSongFilePath(), false) ) return; - SaveToDWIFile(); + SaveToSMFile(); + //SaveToDWIFile(); SaveToCacheFile(); - /* We've safely written our files and created backups. Rename non-SM and non-DWI - * files to avoid confusion. */ + /* We've safely written our files and created backups. Rename non-SM and + * non-DWI files to avoid confusion. */ vector arrayOldFileNames; GetDirListing( m_sSongDir + "*.bms", arrayOldFileNames ); GetDirListing( m_sSongDir + "*.pms", arrayOldFileNames ); @@ -822,19 +878,30 @@ void Song::Save() if( !FileCopy( sOldPath, sNewPath ) ) { LOG->UserLog( "Song file", sOldPath, "couldn't be backed up." ); - /* Don't remove. */ + // Don't remove. } else FILEMAN->Remove( sOldPath ); } } - -bool Song::SaveToSMFile( RString sPath, bool bSavingCache ) +bool Song::SaveToSMFile() { - LOG->Trace( "Song::SaveToSMFile('%s')", sPath.c_str() ); + const RString sPath = SetExtension( GetSongFilePath(), "sm" ); + LOG->Trace( "Song::SaveToSMFile(%s)", sPath.c_str() ); + + // If the file exists, make a backup. + if( IsAFile(sPath) ) + FileCopy( sPath, sPath + ".old" ); + return NotesWriterSM::Write( sPath, *this ); - /* If the file exists, make a backup. */ +} + +bool Song::SaveToSSCFile( RString sPath, bool bSavingCache ) +{ + LOG->Trace( "Song::SaveToSSCFile('%s')", sPath.c_str() ); + + // If the file exists, make a backup. if( !bSavingCache && IsAFile(sPath) ) FileCopy( sPath, sPath + ".old" ); @@ -852,7 +919,7 @@ bool Song::SaveToSMFile( RString sPath, bool bSavingCache ) vpStepsToSave.push_back( pSteps ); } - if( !NotesWriterSM::Write(sPath, *this, vpStepsToSave, bSavingCache) ) + if( !NotesWriterSSC::Write(sPath, *this, vpStepsToSave, bSavingCache) ) return false; if( !bSavingCache && g_BackUpAllSongSaves.Get() ) @@ -878,7 +945,7 @@ bool Song::SaveToSMFile( RString sPath, bool bSavingCache ) if( !bSavingCache ) { - /* Mark these steps saved to disk. */ + // Mark these steps saved to disk. FOREACH( Steps*, vpStepsToSave, s ) (*s)->SetSavedToDisk( true ); } @@ -890,7 +957,7 @@ bool Song::SaveToCacheFile() { SONGINDEX->AddCacheIndex(m_sSongDir, GetHashForDirectory(m_sSongDir)); const RString sPath = GetCacheFilePath(); - if( !SaveToSMFile(sPath, true) ) + if( !SaveToSSCFile(sPath, true) ) return false; FOREACH( Steps*, m_vpSteps, pSteps ) @@ -904,7 +971,7 @@ bool Song::SaveToDWIFile() const RString sPath = SetExtension( GetSongFilePath(), "dwi" ); LOG->Trace( "Song::SaveToDWIFile(%s)", sPath.c_str() ); - /* If the file exists, make a backup. */ + // If the file exists, make a backup. if( IsAFile(sPath) ) FileCopy( sPath, sPath + ".old" ); @@ -965,7 +1032,7 @@ void Song::AddAutoGenNotes() void Song::AutoGen( StepsType ntTo, StepsType ntFrom ) { -// int iNumTracksOfTo = GAMEMAN->StepsTypeToNumTracks(ntTo); + // int iNumTracksOfTo = GAMEMAN->StepsTypeToNumTracks(ntTo); for( unsigned int j=0; jGetDisplayBpms(bpms); if( bpms.GetMax() >= 250 || bpms.GetMax() - bpms.GetMin() >= 75 ) return false; - /* The easy marker indicates which songs a beginner, having selected "beginner", - * can play and actually get a very easy song: if there are actual beginner - * steps, or if the light steps are 1- or 2-foot. */ + /* The easy marker indicates which songs a beginner, having selected + * "beginner", can play and actually get a very easy song: if there are + * actual beginner steps, or if the light steps are 1- or 2-foot. */ const Steps* pBeginnerNotes = SongUtil::GetStepsByDifficulty( this, st, Difficulty_Beginner ); if( pBeginnerNotes ) return true; @@ -1037,11 +1104,11 @@ bool Song::IsEasy( StepsType st ) const bool Song::IsTutorial() const { - // A Song is a tutorial song is it has only Beginner steps. + // A Song is considered a Tutorial if it has only Beginner steps. FOREACH_CONST( Steps*, m_vpSteps, s ) { if( (*s)->m_StepsType == StepsType_lights_cabinet ) - continue; // ignore + continue; // ignore if( (*s)->GetDifficulty() != Difficulty_Beginner ) return false; } @@ -1060,7 +1127,7 @@ bool Song::HasEdits( StepsType st ) const return true; } } - + return false; } @@ -1075,10 +1142,10 @@ bool Song::NormallyDisplayed() const bool Song::ShowInDemonstrationAndRanking() const { return !IsTutorial() && NormallyDisplayed(); } -/* Hack: see Song::TidyUpData comments. */ +// Hack: see Song::TidyUpData comments. bool Song::HasMusic() const { - /* If we have keys, we always have music. */ + // If we have keys, we always have music. if( m_vsKeysoundFile.size() != 0 ) return true; @@ -1102,6 +1169,7 @@ bool Song::HasBGChanges() const return false; } bool Song::HasAttacks() const {return !m_Attacks.empty(); } +// todo: add checks for Jacket, Disc, and CDImage -aj const vector &Song::GetBackgroundChanges( BackgroundLayer bl ) const { @@ -1127,31 +1195,30 @@ RString GetSongAssetPath( RString sPath, const RString &sSongPath ) if( sPath == "" ) return RString(); - /* If there's no path in the file, the file is in the same directory - * as the song. (This is the preferred configuration.) */ + /* If there's no path in the file, the file is in the same directory as the + * song. (This is the preferred configuration.) */ if( sPath.find('/') == string::npos ) return sSongPath+sPath; - /* The song contains a path; treat it as relative to the top SM directory. */ + // The song contains a path; treat it as relative to the top SM directory. if( sPath.Left(3) == "../" ) { - /* The path begins with "../". Resolve it wrt. the song directory. */ + // The path begins with "../". Resolve it wrt. the song directory. sPath = sSongPath + sPath; } CollapsePath( sPath ); /* If the path still begins with "../", then there were an unreasonable number - * of them at the beginning of the path. Ignore the path entirely. */ + * of them at the beginning of the path. Ignore the path entirely. */ if( sPath.Left(3) == "../" ) return RString(); return sPath; } - -/* Note that supplying a path relative to the top-level directory is only for compatibility - * with DWI. We prefer paths relative to the song directory. */ +/* Note that supplying a path relative to the top-level directory is only for + * compatibility with DWI. We prefer paths relative to the song directory. */ RString Song::GetMusicPath() const { return GetSongAssetPath( m_sMusicFile, m_sSongDir ); @@ -1182,6 +1249,8 @@ RString Song::GetBackgroundPath() const return GetSongAssetPath( m_sBackgroundFile, m_sSongDir ); } +// todo: add checks for Jacket, Disc, and CDImage -aj + RString Song::GetDisplayMainTitle() const { if(!PREFSMAN->m_bShowNativeLanguage) return GetTranslitMainTitle(); @@ -1200,7 +1269,6 @@ RString Song::GetDisplayArtist() const return m_sArtist; } - RString Song::GetDisplayFullTitle() const { RString Title = GetDisplayMainTitle(); @@ -1270,7 +1338,7 @@ bool Song::Matches(RString sGroup, RString sSong) const sDir.Replace("\\","/"); vector bits; split( sDir, "/", bits ); - ASSERT(bits.size() >= 2); /* should always have at least two parts */ + ASSERT(bits.size() >= 2); // should always have at least two parts const RString &sLastBit = bits[bits.size()-1]; // match on song dir or title (ala DWI) @@ -1282,8 +1350,8 @@ bool Song::Matches(RString sGroup, RString sSong) const return false; } -/* If apInUse is set, it contains a list of steps which are in use elsewhere, and - * should not be deleted. */ +/* If apInUse is set, it contains a list of steps which are in use elsewhere, + * and should not be deleted. */ void Song::FreeAllLoadedFromProfile( ProfileSlot slot, const set *setInUse ) { /* DeleteSteps will remove and recreate autogen notes, which may reorder @@ -1503,6 +1571,11 @@ public: lua_pushboolean( L, temp.BpmIsConstant() ); return 1; } + static int IsDisplayBpmRandom( T* p, lua_State *L ) + { + lua_pushboolean( L, p->m_DisplayBPMType == Song::DISPLAY_RANDOM ); + return 1; + } LunaSong() { @@ -1551,6 +1624,7 @@ public: ADD_METHOD( GetDisplayBpms ); ADD_METHOD( IsDisplayBpmSecret ); ADD_METHOD( IsDisplayBpmConstant ); + ADD_METHOD( IsDisplayBpmRandom ); } }; diff --git a/src/Song.h b/src/Song.h index 319c113d5c..942534491c 100644 --- a/src/Song.h +++ b/src/Song.h @@ -61,7 +61,7 @@ public: enum SelectionDisplay { SHOW_ALWAYS, // always - SHOW_NEVER // never (unless song hiding is turned off) + SHOW_NEVER // never (unless song hiding is turned off) } m_SelectionDisplay; Song(); @@ -78,9 +78,10 @@ public: void ReCalculateRadarValuesAndLastBeat(); // called by TidyUpData, and after saving void TranslateTitles(); // called by TidyUpData - bool SaveToSMFile( RString sPath, bool bSavingCache ); - void Save(); // saves SM and DWI + bool SaveToSSCFile( RString sPath, bool bSavingCache ); + void Save(); // saves SSC and SM guaranteed. bool SaveToCacheFile(); + bool SaveToSMFile(); bool SaveToDWIFile(); const RString &GetSongFilePath() const; @@ -93,10 +94,9 @@ public: // Directory this song data came from: const RString &GetSongDir() const { return m_sSongDir; } - /* Filename associated with this file. This will always have - * an .SM extension. If we loaded an .SM, this will point to - * it, but if we loaded any other type, this will point to a - * generated .SM filename. */ + /* Filename associated with this file. This will always have a .SSC + * extension. If we loaded a .SSC, this will point to it, but if we loaded + * any other type, this will point to a generated .SSC filename. */ RString m_sSongFileName; RString m_sGroupName; @@ -123,6 +123,9 @@ public: RString GetDisplayFullTitle() const; RString GetTranslitFullTitle() const; + // allow versioning with the song. + float m_fVersion; + RString m_sGenre; // This is read and saved, but never actually used. @@ -141,10 +144,13 @@ public: float m_fSpecifiedBPMMin; float m_fSpecifiedBPMMax; // if a range, then Min != Max - RString m_sBannerFile; + RString m_sBannerFile; // typically a 16:5 ratio graphic (e.g. 256x80) + //RString m_sJacketFile; // typically square (e.g. 192x192, 256x256) + //RString m_sCDFile; // square (e.g. 128x128 [DDR 1st-3rd]) + //RString m_sDiscFile; // rectangular (e.g. 256x192 [Pump], 200x150 [MGD3]) RString m_sLyricsFile; - RString m_sBackgroundFile; - RString m_sCDTitleFile; + RString m_sBackgroundFile; + RString m_sCDTitleFile; AttackArray m_Attacks; vector m_sAttackString; @@ -152,6 +158,9 @@ public: RString GetMusicPath() const; RString GetInstrumentTrackPath( InstrumentTrack it ) const; RString GetBannerPath() const; + //RString GetJacketPath() const; + //RString GetCDImagePath() const; + //RString GetDiscPath() const; RString GetLyricsPath() const; RString GetBackgroundPath() const; RString GetCDTitlePath() const; @@ -163,6 +172,9 @@ public: bool HasInstrumentTrack( InstrumentTrack it ) const; bool HasBanner() const; bool HasBackground() const; + //bool HasJacket() const; + //bool HasCDImage() const; + //bool HasDisc() const; bool HasCDTitle() const; bool HasMovieBackground() const; bool HasBGChanges() const; diff --git a/src/SongManager.cpp b/src/SongManager.cpp index 273f25ff32..7ed727cd74 100644 --- a/src/SongManager.cpp +++ b/src/SongManager.cpp @@ -15,7 +15,7 @@ #include "MsdFile.h" #include "NoteSkinManager.h" #include "NotesLoaderDWI.h" -#include "NotesLoaderSM.h" +#include "NotesLoaderSSC.h" #include "PrefsManager.h" #include "Profile.h" #include "ProfileManager.h" @@ -41,6 +41,7 @@ const RString ADDITIONAL_SONGS_DIR = "/AdditionalSongs/"; const RString ADDITIONAL_COURSES_DIR = "/AdditionalCourses/"; const RString EDIT_SUBDIR = "Edits/"; +/** @brief The file that contains various random attacks. */ const RString ATTACK_FILE = "/Data/RandomAttacks.txt"; static const ThemeMetric EXTRA_COLOR ( "SongManager", "ExtraColor" ); @@ -163,7 +164,7 @@ void SongManager::AddGroup( RString sDir, RString sGroupDirName ) break; if( j != m_sSongGroupNames.size() ) - return; /* the group is already added */ + return; // the group is already added // Look for a group banner in this group folder vector arrayGroupBanners; @@ -221,7 +222,7 @@ void SongManager::AddGroup( RString sDir, RString sGroupDirName ) static LocalizedString LOADING_SONGS ( "SongManager", "Loading songs..." ); void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) { - /* Make sure sDir has a trailing slash. */ + // Make sure sDir has a trailing slash. if( sDir.Right(1) != "/" ) sDir += "/"; @@ -255,7 +256,7 @@ void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) { RString sSongDirName = arraySongDirs[j]; - // this is a song directory. Load a new song! + // this is a song directory. Load a new song. if( ld ) { ld->SetText( LOADING_SONGS.GetValue()+ssprintf("\n%s\n%s", @@ -266,11 +267,11 @@ void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) Song* pNewSong = new Song; if( !pNewSong->LoadFromSongDir( sSongDirName ) ) { - /* The song failed to load. */ + // The song failed to load. delete pNewSong; continue; } - + m_pSongs.push_back( pNewSong ); index_entry.push_back( pNewSong ); loaded++; @@ -278,16 +279,16 @@ void SongManager::LoadStepManiaSongDir( RString sDir, LoadingWindow *ld ) LOG->Trace("Loaded %i songs from \"%s\"", loaded, (sDir+sGroupDirName).c_str() ); - /* Don't add the group name if we didn't load any songs in this group. */ + // Don't add the group name if we didn't load any songs in this group. if(!loaded) continue; - /* Add this group to the group array. */ + // Add this group to the group array. AddGroup(sDir, sGroupDirName); - // Cache and load the group banner. (and background if it has one) + // Cache and load the group banner. (and background if it has one -aj) BANNERCACHE->CacheBanner( GetSongGroupBannerPath(sGroupDirName) ); - /* Load the group sym links (if any)*/ + // Load the group sym links (if any) LoadGroupSymLinks(sDir, sGroupDirName); } @@ -308,7 +309,7 @@ void SongManager::LoadGroupSymLinks(RString sDir, RString sGroupFolder) MsdFile msdF; msdF.ReadFile( sDir+sGroupFolder+"/"+arraySymLinks[s].c_str(), false ); // don't unescape RString sSymDestination = msdF.GetParam(0,1); // Should only be 1 vale¶m...period. - + Song* pNewSong = new Song; if( !pNewSong->LoadFromSongDir( sSymDestination ) ) { @@ -802,11 +803,11 @@ void SongManager::InitAutogenCourses() CourseUtil::AutogenEndlessFromGroup( "", Difficulty_Medium, *pCourse ); m_pCourses.push_back( pCourse ); - /* Generate Oni courses from artists. Only create courses if we have at least + /* Generate Oni courses from artists. Only create courses if we have at least * four songs from an artist; create 3- and 4-song courses. */ { - /* We normally sort by translit artist. However, display artist is more - * consistent. For example, transliterated Japanese names are alternately + /* We normally sort by translit artist. However, display artist is more + * consistent. For example, transliterated Japanese names are alternately * spelled given- and family-name first, but display titles are more consistent. */ vector apSongs = this->GetAllSongs(); SongUtil::SortSongPointerArrayByDisplayArtist( apSongs ); @@ -827,8 +828,8 @@ void SongManager::InitAutogenCourses() continue; } - /* Different artist, or we're at the end. If we have enough entries for - * the last artist, add it. Skip blanks and "Unknown artist". */ + /* Different artist, or we're at the end. If we have enough entries for + * the last artist, add it. Skip blanks and "Unknown artist". */ if( iCurArtistCount >= 3 && sCurArtistTranslit != "" && sCurArtistTranslit.CompareNoCase("Unknown artist") && sCurArtist.CompareNoCase("Unknown artist") ) @@ -952,8 +953,8 @@ void SongManager::InvalidateCachedTrails() } } -/* Called periodically to wipe out cached NoteData. This is called when we change - * screens. */ +/* Called periodically to wipe out cached NoteData. This is called when we + * change screens. */ void SongManager::Cleanup() { for( unsigned i=0; im_bAutogenSteps may have changed. */ + // PREFSMAN->m_bAutogenSteps may have changed. m_pSongs[i]->RemoveAutoGenNotes(); m_pSongs[i]->AddAutoGenNotes(); } @@ -1118,7 +1119,7 @@ bool SongManager::GetExtraStageInfoFromCourse( bool bExtra2, RString sPreferredG const RString sCourseSuffix = sPreferredGroup + (bExtra2 ? "/extra2.crs" : "/extra1.crs"); RString sCoursePath = SpecialFiles::SONGS_DIR + sCourseSuffix; - /* Couldn't find course in DWI path or alternative song folders */ + // Couldn't find course in DWI path or alternative song folders if( !DoesFileExist(sCoursePath) ) { sCoursePath = ADDITIONAL_SONGS_DIR + sCourseSuffix; @@ -1139,20 +1140,20 @@ bool SongManager::GetExtraStageInfoFromCourse( bool bExtra2, RString sPreferredG return true; } -/* Return true if n1 < n2. */ +// Return true if n1 < n2. bool CompareNotesPointersForExtra(const Steps *n1, const Steps *n2) { - /* Equate CHALLENGE to HARD. */ + // Equate CHALLENGE to HARD. Difficulty d1 = min(n1->GetDifficulty(), Difficulty_Hard); Difficulty d2 = min(n2->GetDifficulty(), Difficulty_Hard); if(d1 < d2) return true; if(d1 > d2) return false; - /* n1 difficulty == n2 difficulty */ + // n1 difficulty == n2 difficulty if(StepsUtil::CompareNotesPointersByMeter(n1,n2)) return true; if(StepsUtil::CompareNotesPointersByMeter(n2,n1)) return false; - /* n1 meter == n2 meter */ + // n1 meter == n2 meter return StepsUtil::CompareNotesPointersByRadarValues(n1,n2); } @@ -1164,7 +1165,7 @@ void SongManager::GetExtraStageInfo( bool bExtra2, const Style *sd, Song*& pSong { if( GAMESTATE->m_pCurSong == NULL ) { - /* This normally shouldn't happen, but it's helpful to permit it for testing. */ + // This normally shouldn't happen, but it's helpful to permit it for testing. LOG->Warn( "GetExtraStageInfo() called in GROUP_ALL, but GAMESTATE->m_pCurSong == NULL" ); GAMESTATE->m_pCurSong.Set( GetRandomSong() ); } @@ -1176,9 +1177,14 @@ void SongManager::GetExtraStageInfo( bool bExtra2, const Style *sd, Song*& pSong GAMESTATE->m_pCurSong? GAMESTATE->m_pCurSong->GetSongDir().c_str():"", GAMESTATE->m_pCurSong? GAMESTATE->m_pCurSong->m_sGroupName.c_str():"") ); + // Check preferred group if( GetExtraStageInfoFromCourse(bExtra2, sGroup, pSongOut, pStepsOut) ) return; - + + // Optionally, check the Songs folder for extra1/2.crs files. + if( GetExtraStageInfoFromCourse(bExtra2, "", pSongOut, pStepsOut) ) + return; + // Choose a hard song for the extra stage Song* pExtra1Song = NULL; // the absolute hardest Song and Steps. Use this for extra stage 1. Steps* pExtra1Notes = NULL; @@ -1315,22 +1321,18 @@ Course* SongManager::GetCourseFromName( RString sName ) const } -/* - * GetSongDir() contains a path to the song, possibly a full path, eg: +/* GetSongDir() contains a path to the song, possibly a full path, eg: * Songs\Group\SongName or * My Other Song Folder\Group\SongName or * c:\Corny J-pop\Group\SongName * - * Most course group names are "Group\SongName", so we want to - * match against the last two elements. Let's also support - * "SongName" alone, since the group is only important when it's - * potentially ambiguous. + * Most course group names are "Group\SongName", so we want to match against the + * last two elements. Let's also support "SongName" alone, since the group is + * only important when it's potentially ambiguous. * - * Let's *not* support "Songs\Group\SongName" in course files. - * That's probably a common error, but that would result in - * course files floating around that only work for people who put - * songs in "Songs"; we don't want that. - */ + * Let's *not* support "Songs\Group\SongName" in course files. That's probably + * a common error, but that would result in course files floating around that + * only work for people who put songs in "Songs"; we don't want that. */ Song *SongManager::FindSong( RString sPath ) const { @@ -1404,7 +1406,7 @@ void SongManager::UpdatePopular() } SongUtil::SortSongPointerArrayByTitle( apBestSongs ); - + vector apBestCourses[NUM_CourseType]; FOREACH_ENUM( CourseType, ct ) { @@ -1605,8 +1607,8 @@ void SongManager::SortSongs() void SongManager::UpdateRankingCourses() { - /* Updating the ranking courses data is fairly expensive - * since it involves comparing strings. Do so sparingly. */ + /* Updating the ranking courses data is fairly expensive since it involves + * comparing strings. Do so sparingly. */ vector RankingCourses; split( THEME->GetMetric("ScreenRanking","CoursesToShow"),",", RankingCourses); @@ -1652,7 +1654,7 @@ void SongManager::LoadStepEditsFromProfileDir( const RString &sProfileDir, Profi { RString fn = vsFiles[i]; - SMLoader::LoadEditFromFile( fn, slot, true ); + SSCLoader::LoadEditFromFile( fn, slot, true ); } } } @@ -1774,6 +1776,11 @@ int FindCourseIndexOfSameMode( T begin, T end, const Course *p ) return -1; } +int SongManager::GetSongRank(Song* pSong) +{ + const int index = FindIndex( m_pPopularSongs.begin(), m_pPopularSongs.end(), pSong ); + return index; // -1 means we didn't find it +} // lua start #include "LuaBinding.h" @@ -1844,22 +1851,17 @@ public: DEFINE_METHOD( GetSongGroupColor, GetSongGroupColor( SArg(1) ) ) DEFINE_METHOD( GetCourseColor, GetCourseColor( Luna::check(L,1) ) ) - // this binding has ABYSMAL performance, most likely due to the whole "hey - // let's keep repopulating the vector every time this is called" thing. - // gg whitehouse maybe if you included global variables in your terror - // alerts this wouldn't have happened ffffffffffffff -aj - /* static int GetSongRank( T* p, lua_State *L ) { Song *pSong = Luna::check(L,1); - vector apPopularSongs; - p->GetPopularSongs(apPopularSongs,GROUP_ALL); - const int index = FindIndex( apPopularSongs.begin(), apPopularSongs.end(), pSong ); + int index = p->GetSongRank(pSong); if( index != -1 ) lua_pushnumber(L, index+1); - else lua_pushnil(L); + else + lua_pushnil(L); return 1; } + /* static int GetSongRankFromProfile( T* p, lua_State *L ) { // it's like the above but also takes in a ProfileSlot as well. @@ -1904,7 +1906,7 @@ public: ADD_METHOD( GetSongColor ); ADD_METHOD( GetSongGroupColor ); ADD_METHOD( GetCourseColor ); - //ADD_METHOD( GetSongRank ); + ADD_METHOD( GetSongRank ); ADD_METHOD( GetSongGroupNames ); ADD_METHOD( GetSongsInGroup ); ADD_METHOD( ShortenGroupName ); diff --git a/src/SongManager.h b/src/SongManager.h index 4d5e80be4a..c62df7f23f 100644 --- a/src/SongManager.h +++ b/src/SongManager.h @@ -1,4 +1,4 @@ -/* SongManager - Holder for all Songs and Steps. */ +/** @brief SongManager - Holder for all Songs and Steps. */ #ifndef SONGMANAGER_H #define SONGMANAGER_H @@ -21,9 +21,12 @@ struct lua_State; #include "RageTexturePreloader.h" #include "RageUtil.h" +/** @brief The max number of edit steps a profile can have. */ const int MAX_EDIT_STEPS_PER_PROFILE = 200; +/** @brief The max number of edit courses a profile can have. */ const int MAX_EDIT_COURSES_PER_PROFILE = 20; +/** @brief The holder for the Songs and its Steps. */ class SongManager { public: @@ -102,6 +105,7 @@ public: Course* GetRandomCourse(); // sm-ssc addition: RString GetSongGroupByIndex(unsigned index) { return m_sSongGroupNames[index]; } + int GetSongRank(Song* pSong); void GetStepsLoadedFromProfile( vector &AddTo, ProfileSlot slot ) const; Song *GetSongFromSteps( Steps *pSteps ) const; @@ -180,8 +184,10 @@ extern SongManager* SONGMAN; // global and accessable from anywhere in our progr #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/SongUtil.cpp b/src/SongUtil.cpp index 0a23678477..6e075c3334 100644 --- a/src/SongUtil.cpp +++ b/src/SongUtil.cpp @@ -97,7 +97,8 @@ void SongUtil::GetSteps( Difficulty dc, int iMeterLow, int iMeterHigh, - const RString &sDescription, + const RString &sDescription, + const RString &sCredit, bool bIncludeAutoGen, unsigned uHash, int iMaxToGet @@ -119,6 +120,8 @@ void SongUtil::GetSteps( continue; if( sDescription.size() && sDescription != pSteps->GetDescription() ) continue; + if( sCredit.size() && sCredit != pSteps->GetCredit() ) + continue; if( uHash != 0 && uHash != pSteps->GetHash() ) continue; if( !bIncludeAutoGen && pSteps->IsAutogen() ) @@ -141,13 +144,14 @@ Steps* SongUtil::GetOneSteps( Difficulty dc, int iMeterLow, int iMeterHigh, - const RString &sDescription, + const RString &sDescription, + const RString &sCredit, unsigned uHash, bool bIncludeAutoGen ) { vector vpSteps; - GetSteps( pSong, vpSteps, st, dc, iMeterLow, iMeterHigh, sDescription, bIncludeAutoGen, uHash, 1 ); // get max 1 + GetSteps( pSong, vpSteps, st, dc, iMeterLow, iMeterHigh, sDescription, sCredit, bIncludeAutoGen, uHash, 1 ); // get max 1 if( vpSteps.empty() ) return NULL; else @@ -193,13 +197,23 @@ Steps* SongUtil::GetStepsByMeter( const Song *pSong, StepsType st, int iMeterLow Steps* SongUtil::GetStepsByDescription( const Song *pSong, StepsType st, RString sDescription ) { vector vNotes; - GetSteps( pSong, vNotes, st, Difficulty_Invalid, -1, -1, sDescription ); + GetSteps( pSong, vNotes, st, Difficulty_Invalid, -1, -1, sDescription, "" ); if( vNotes.size() == 0 ) return NULL; else return vNotes[0]; } +Steps* SongUtil::GetStepsByCredit( const Song *pSong, StepsType st, RString sCredit ) +{ + vector vNotes; + GetSteps(pSong, vNotes, st, Difficulty_Invalid, -1, -1, "", sCredit ); + if( vNotes.size() == 0 ) + return NULL; + else + return vNotes[0]; +} + Steps* SongUtil::GetClosestNotes( const Song *pSong, StepsType st, Difficulty dc, bool bIgnoreLocked ) { @@ -266,7 +280,11 @@ void SongUtil::AdjustDuplicateSteps( Song *pSong ) * These are confusing, and they're ambiguous when passed to GetStepsByID. */ } } - +/** + * @brief Remove the initial whitespace characters. + * @param s the string to left trim. + * @return the trimmed string. + */ static RString RemoveInitialWhitespace( RString s ) { size_t i = s.find_first_not_of(" \t\r\n"); @@ -279,7 +297,7 @@ static RString RemoveInitialWhitespace( RString s ) void SongUtil::DeleteDuplicateSteps( Song *pSong, vector &vSteps ) { /* vSteps have the same StepsType and Difficulty. Delete them if they have the - * same m_sDescription, m_iMeter and SMNoteData. */ + * same m_sDescription, m_sCredit, m_iMeter and SMNoteData. */ CHECKPOINT; for( unsigned i=0; i &vSteps ) if( s1->GetDescription() != s2->GetDescription() ) continue; + if( s1->GetCredit() != s2->GetCredit() ) + continue; if( s1->GetMeter() != s2->GetMeter() ) continue; /* Compare, ignoring whitespace. */ @@ -303,8 +323,8 @@ void SongUtil::DeleteDuplicateSteps( Song *pSong, vector &vSteps ) if( RemoveInitialWhitespace(sSMNoteData1) != RemoveInitialWhitespace(sSMNoteData2) ) continue; - LOG->Trace("Removed %p duplicate steps in song \"%s\" with description \"%s\" and meter \"%i\"", - s2, pSong->GetSongDir().c_str(), s1->GetDescription().c_str(), s1->GetMeter() ); + LOG->Trace("Removed %p duplicate steps in song \"%s\" with description \"%s\", step author \"%s\", and meter \"%i\"", + s2, pSong->GetSongDir().c_str(), s1->GetDescription().c_str(), s1->GetCredit().c_str(), s1->GetMeter() ); pSong->DeleteSteps( s2, false ); @@ -649,9 +669,9 @@ void SongUtil::SortSongPointerArrayBySectionName( vector &vpSongsInOut, S { RString val = GetSectionNameFromSongAndSort( vpSongsInOut[i], so ); - /* Make sure 0-9 comes first and OTHER comes last. */ + // Make sure 0-9 comes first and OTHER comes last. if( val == "0-9" ) val = "0"; - else if( val == sOther ) val = "2"; + else if( val == sOther ) val = "2"; else val = "1" + MakeSortString(val); g_mapSongSortVal[vpSongsInOut[i]] = val; @@ -666,25 +686,20 @@ void SongUtil::SortSongPointerArrayByStepsTypeAndMeter( vector &vpSongsIn g_mapSongSortVal.clear(); for(unsigned i = 0; i < vpSongsInOut.size(); ++i) { - /* Ignore locked steps. */ + // Ignore locked steps. const Steps* pSteps = GetClosestNotes( vpSongsInOut[i], st, dc, true ); RString &s = g_mapSongSortVal[vpSongsInOut[i]]; s = ssprintf("%03d", pSteps ? pSteps->GetMeter() : 0); - /* - * pSteps may not be exactly the difficulty we want; for example, we may - * be sorting by Hard difficulty and a song may have no Hard steps. - * + /* pSteps may not be exactly the difficulty we want; for example, we + * may be sorting by Hard difficulty and a song may have no Hard steps. * In this case, we can end up with unintuitive ties; for example, pSteps * may be Medium with a meter of 5, which will sort it among the 5-meter * Hard songs. Break the tie, by adding the difficulty to the sort as - * well. That way, we'll always put Medium 5s before Hard 5s. If all - * songs are using the preferred difficulty (dc), this will be a no-op. - */ + * well. That way, we'll always put Medium 5s before Hard 5s. If all + * songs are using the preferred difficulty (dc), this will be a no-op. */ s += ssprintf( "%c", (pSteps? pSteps->GetDifficulty():0) + '0' ); - // ???: will this cause a crash with player 2 only? -aj - // no, but I'm not sure if it causes problems either... if( PREFSMAN->m_bSubSortByNumSteps ) s += ssprintf("%06.0f",pSteps ? pSteps->GetRadarValues(PLAYER_1)[RadarCategory_TapsAndHolds] : 0); } @@ -775,7 +790,7 @@ bool SongUtil::ValidateCurrentEditStepsDescription( const RString &sAnswer, RStr FOREACH_CONST( Steps*, v, s ) { if( pSteps == *s ) - continue; // don't compare name against ourself + continue; // don't compare name against ourself if( (*s)->GetDescription() == sAnswer ) { @@ -792,11 +807,11 @@ bool SongUtil::ValidateCurrentStepsDescription( const RString &sAnswer, RString if( sAnswer.empty() ) return true; - /* Don't allow duplicate edit names within the same StepsType; edit names uniquely - * identify the edit. */ + /* Don't allow duplicate edit names within the same StepsType; edit names + * uniquely identify the edit. */ Steps *pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; - /* If unchanged: */ + // If unchanged: if( pSteps->GetDescription() == sAnswer ) return true; @@ -808,6 +823,29 @@ bool SongUtil::ValidateCurrentStepsDescription( const RString &sAnswer, RString return true; } +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 ) +{ + if( sAnswer.empty() ) + return true; + + Steps *pSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; + // If unchanged: + if( pSteps->GetCredit() == sAnswer ) + return true; + + // Borrow from EditDescription testing. Perhaps this should be abstracted? -Wolfman2000 + static const RString sInvalidChars = "\\/:*?\"<>|"; + if( strpbrk(sAnswer, sInvalidChars) != NULL ) + { + sErrorOut = ssprintf( AUTHOR_NAME_CANNOT_CONTAIN.GetValue(), sInvalidChars.c_str() ); + return false; + } + + return true; +} + void SongUtil::GetAllSongGenres( vector &vsOut ) { set genres; @@ -867,8 +905,8 @@ void SongUtil::GetPlayableStepsTypes( const Song *pSong, set &vOut ) FOREACH( const Style*, vpPossibleStyles, s ) vStepsTypes.insert( (*s)->m_StepsType ); - /* filter out hidden StepsTypes, and remove steps that we don't - * have enough stages left to play. */ + /* filter out hidden StepsTypes, and remove steps that we don't have enough + * stages left to play. */ // this being const may have caused some problems... -aj const vector &vstToShow = CommonMetrics::STEPS_TYPES_TO_SHOW.GetValue(); FOREACHS( StepsType, vStepsTypes, st ) @@ -989,8 +1027,8 @@ Song *SongID::ToSong() const Song *pRet = NULL; if( !m_Cache.Get(&pRet) ) { - // HACK for backwards compatibility: - // Re-add the leading "/". 2005/05/21 file layer changes added a leading slash. + // HACK for backwards compatibility: Re-add the leading "/". + // 2005/05/21 file layer changes added a leading slash. RString sDir2 = sDir; if( sDir2.Left(1) != "/" ) sDir2 = "/" + sDir2; @@ -1005,9 +1043,7 @@ Song *SongID::ToSong() const XNode* SongID::CreateNode() const { XNode* pNode = new XNode( "Song" ); - pNode->AppendAttr( "Dir", sDir ); - return pNode; } @@ -1060,7 +1096,6 @@ namespace LUA_REGISTER_NAMESPACE( SongUtil ) - /* * (c) 2001-2004 Chris Danford, Glenn Maynard * All rights reserved. diff --git a/src/SongUtil.h b/src/SongUtil.h index 7dabb69e88..3d2aa5956e 100644 --- a/src/SongUtil.h +++ b/src/SongUtil.h @@ -1,4 +1,4 @@ -/* SongUtil - Utility functions that deal with Song. */ +/** @brief SongUtil - Utility functions that deal with Song. */ #ifndef SONG_UTIL_H #define SONG_UTIL_H @@ -13,6 +13,7 @@ class Steps; class Profile; class XNode; +/** @brief The criteria for dealing with songs. */ class SongCriteria { public: @@ -22,12 +23,26 @@ public: enum Selectable { Selectable_Yes, Selectable_No, Selectable_DontCare } m_Selectable; bool m_bUseSongAllowedList; vector m_vpSongAllowedList; + /** @brief How many songs does this take max? Don't use this if it's -1. */ int m_iMaxStagesForSong; // don't filter if -1 // float m_fMinBPM; // don't filter if -1 // float m_fMaxBPM; // don't filter if -1 - enum Tutorial { Tutorial_Yes, Tutorial_No, Tutorial_DontCare } m_Tutorial; - enum Locked { Locked_Locked, Locked_Unlocked, Locked_DontCare } m_Locked; + /** @brief Is this song used for tutorial purposes? */ + enum Tutorial + { + Tutorial_Yes, /**< This song is used for tutorial purposes. */ + Tutorial_No, /**< This song is not used for tutorial purposes. */ + Tutorial_DontCare /**< This song can or cannot be used for tutorial purposes. */ + } m_Tutorial; + /** @brief Is this song used for locking/unlocking purposes? */ + enum Locked + { + Locked_Locked, /**< This song is a locked song. */ + Locked_Unlocked, /**< This song is an unlocked song. */ + Locked_DontCare /**< This song can or cannot be locked or unlocked. */ + } m_Locked; + /** @brief Set up some initial song criteria. */ SongCriteria() { m_bUseSongGenreAllowedList = false; @@ -40,9 +55,20 @@ public: m_Locked = Locked_DontCare; } + /** + * @brief Determine if the song matches the current criteria. + * @param p the song to compare against the criteria. + * @return true of the song matches the criteria, false otherwise. + */ bool Matches( const Song *p ) const; + /** + * @brief Determine if two sets of criteria are equivalent. + * @param other the other criteria. + * @return true if the two sets of criteria are equal, false otherwise. + */ bool operator==( const SongCriteria &other ) const { +/** @brief A quick way to match every part of the song criterium. */ #define X(x) (x == other.x) return X(m_sGroupName) && @@ -58,9 +84,15 @@ public: X(m_Locked); #undef X } + /** + * @brief Determine if two sets of criteria are not equivalent. + * @param other the other criteria. + * @return true if the two sets of criteria are not equal, false otherwise. + */ bool operator!=( const SongCriteria &other ) const { return !operator==( other ); } }; +/** @brief A set of song utilities to make working with songs easier. */ namespace SongUtil { void GetSteps( @@ -70,7 +102,8 @@ namespace SongUtil Difficulty dc = Difficulty_Invalid, int iMeterLow = -1, int iMeterHigh = -1, - const RString &sDescription = "", + const RString &sDescription = "", + const RString &sCredit = "", bool bIncludeAutoGen = true, unsigned uHash = 0, int iMaxToGet = -1 @@ -81,15 +114,17 @@ namespace SongUtil Difficulty dc = Difficulty_Invalid, int iMeterLow = -1, int iMeterHigh = -1, - const RString &sDescription = "", + const RString &sDescription = "", + const RString &sCredit = "", unsigned uHash = 0, bool bIncludeAutoGen = true ); Steps* GetStepsByDifficulty( const Song *pSong, StepsType st, Difficulty dc, bool bIncludeAutoGen = true ); Steps* GetStepsByMeter( const Song *pSong, StepsType st, int iMeterLow, int iMeterHigh ); Steps* GetStepsByDescription( const Song *pSong, StepsType st, RString sDescription ); + Steps* GetStepsByCredit( const Song *pSong, StepsType st, RString sCredit ); Steps* GetClosestNotes( const Song *pSong, StepsType st, Difficulty dc, bool bIgnoreLocked=false ); - + void AdjustDuplicateSteps( Song *pSong ); // part of TidyUpData void DeleteDuplicateSteps( Song *pSong, vector &vSteps ); @@ -111,10 +146,19 @@ namespace SongUtil int CompareSongPointersByGroup(const Song *pSong1, const Song *pSong2); + /** + * @brief Determine if the requested description for an edit is unique. + * @param pSong the song the edit is for. + * @param st the steps type for the edit. + * @param sPreferredDescription the requested description. + * @param pExclude the steps that want the description. + * @return true if it is unique, false otherwise. + */ bool IsEditDescriptionUnique( const Song* pSong, StepsType st, const RString &sPreferredDescription, 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 ); void GetAllSongGenres( vector &vsOut ); void FilterSongs( const SongCriteria &sc, const vector &in, vector &out ); @@ -156,8 +200,10 @@ public: #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/StageStats.cpp b/src/StageStats.cpp index ebd0f734f5..b7c5398eb4 100644 --- a/src/StageStats.cpp +++ b/src/StageStats.cpp @@ -202,7 +202,7 @@ void StageStats::FinalizeScores( bool bSummary ) m_multiPlayer[mp].m_HighScore = FillInHighScore( m_multiPlayer[mp], *GAMESTATE->m_pMultiPlayerState[mp], "", sPlayerGuid ); } - // todo: check if player was CPU autoplay here? -aj + // todo: don't save scores in autoplay -aj FOREACH_HumanPlayer( p ) { const HighScore &hs = m_player[p].m_HighScore; diff --git a/src/StdString.h b/src/StdString.h index 71b5acb9b2..f92cd07a65 100644 --- a/src/StdString.h +++ b/src/StdString.h @@ -1,4 +1,4 @@ -/* StdString - std::string convenience wrapper. */ +/** @brief StdString - std::string convenience wrapper. */ // ============================================================================= // FILE: StdString.h @@ -155,7 +155,17 @@ namespace StdString /* Our strings are UTF-8; instead of having to play around with locales, * let's just manually toupper ASCII only. If we really want to play with * Unicode cases, we can do it ourself in RageUtil. */ +/** + * @brief Turn the character into its uppercase equivalent. + * @param ch the character to convert. + * @return the converted character. + */ inline char sstoupper(char ch) { return (ch >= 'a' && ch <= 'z')? char(ch + 'A' - 'a'): ch; } +/** + * @brief Turn the character into its lowercase equivalent. + * @param ch the character to convert. + * @return the converted character. + */ inline char sstolower(char ch) { return (ch >= 'A' && ch <= 'Z')? char(ch + 'a' - 'A'): ch; } // ----------------------------------------------------------------------------- @@ -164,6 +174,11 @@ inline char sstolower(char ch) { return (ch >= 'A' && ch <= 'Z')? char(ch + 'a' typedef std::string::size_type SS_SIZETYPE; // just for shorthand, really typedef std::string::pointer SS_PTRTYPE; +/** + * @brief Assign one string to another. + * @param sDst the destination string. + * @param sSrc the source string. + */ inline void ssasn(std::string& sDst, const std::string& sSrc) { if ( sDst.c_str() != sSrc.c_str() ) @@ -172,6 +187,11 @@ inline void ssasn(std::string& sDst, const std::string& sSrc) sDst.assign(sSrc); } } +/** + * @brief Assign one string to another. + * @param sDst the destination string. + * @param pA the source string. + */ inline void ssasn(std::string& sDst, PCSTR pA) { #if defined(HAVE_ASSIGN_FIX) @@ -196,6 +216,11 @@ inline void ssasn(std::string& sDst, PCSTR pA) sDst.assign(pA); #endif } +/** + * @brief Erase the destination string. + * @param sDst the destination string. + * @param nNull the null value. + */ inline void ssasn(std::string& sDst, const int nNull) { sDst.erase(); @@ -206,10 +231,20 @@ inline void ssasn(std::string& sDst, const int nNull) // ----------------------------------------------------------------------------- // ssadd: string object concatenation -- add second argument to first // ----------------------------------------------------------------------------- +/** + * @brief Concatenate one string with another. + * @param sDst the original string. + * @param sSrc the string being added. + */ inline void ssadd(std::string& sDst, const std::string& sSrc) { sDst += sSrc; } +/** + * @brief Concatenate one string with another. + * @param sDst the original string. + * @param pA the string being added. + */ inline void ssadd(std::string& sDst, PCSTR pA) { // If the string being added is our internal string or a part of our @@ -233,20 +268,26 @@ inline void ssadd(std::string& sDst, PCSTR pA) // ----------------------------------------------------------------------------- // ssicmp: comparison (case insensitive ) // ----------------------------------------------------------------------------- - template - inline int ssicmp(const CT* pA1, const CT* pA2) +/** + * @brief Perform a case insensitive comparison of the two strings. + * @param pA1 the first string. + * @param pA2 the second string. + * @return >0 if pA1 > pA2, <0 if pA1 < pA2, or 0 otherwise. + */ +template +inline int ssicmp(const CT* pA1, const CT* pA2) +{ + CT f; + CT l; + + do { - CT f; - CT l; + f = sstolower(*(pA1++)); + l = sstolower(*(pA2++)); + } while ( (f) && (f == l) ); - do - { - f = sstolower(*(pA1++)); - l = sstolower(*(pA2++)); - } while ( (f) && (f == l) ); - - return (int)(f - l); - } + return (int)(f - l); +} // ----------------------------------------------------------------------------- // ssupr/sslwr: Uppercase/Lowercase conversion functions @@ -266,22 +307,22 @@ inline void ssadd(std::string& sDst, PCSTR pA) } #endif - inline void sslwr(char *pT, size_t nLen) - { - MakeLower( pT, nLen ); - } - inline void ssupr(char *pT, size_t nLen) - { - MakeUpper( pT, nLen ); - } - inline void sslwr(wchar_t *pT, size_t nLen) - { - MakeLower( pT, nLen ); - } - inline void ssupr(wchar_t *pT, size_t nLen) - { - MakeUpper( pT, nLen ); - } +inline void sslwr(char *pT, size_t nLen) +{ + MakeLower( pT, nLen ); +} +inline void ssupr(char *pT, size_t nLen) +{ + MakeUpper( pT, nLen ); +} +inline void sslwr(wchar_t *pT, size_t nLen) +{ + MakeLower( pT, nLen ); +} +inline void ssupr(wchar_t *pT, size_t nLen) +{ + MakeUpper( pT, nLen ); +} #if defined(WIN32) #define vsnprintf _vsnprintf @@ -307,6 +348,12 @@ inline void ssadd(std::string& sDst, PCSTR pA) template class CStdStr; +/** + * @brief Another way to concatenate two strings together. + * @param str1 the original string. + * @param str2 the string to be added. + * @return the longer string. + */ template inline CStdStr operator+(const CStdStr& str1, const CStdStr& str2) @@ -315,7 +362,12 @@ CStdStr operator+(const CStdStr& str1, const CStdStr& str2) strRet.append(str2); return strRet; } - +/** + * @brief Another way to concatenate two strings together. + * @param str the original string. + * @param t the string to be added. + * @return the longer string. + */ template inline CStdStr operator+(const CStdStr& str, CT t) @@ -327,14 +379,24 @@ CStdStr operator+(const CStdStr& str, CT t) strRet.append(1, t); // 2 return strRet; } - +/** + * @brief Another way to concatenate two strings together. + * @param str the original string. + * @param pA the string to be added. + * @return the longer string. + */ template inline CStdStr operator+(const CStdStr& str, PCSTR pA) { return CStdStr(str) + CStdStr(pA); } - +/** + * @brief Another way to concatenate two strings together. + * @param pA the original string. + * @param str the string to be added. + * @return the longer string. + */ template inline CStdStr operator+(PCSTR pA, const CStdStr& str) @@ -345,7 +407,7 @@ CStdStr operator+(PCSTR pA, const CStdStr& str) } - +/** @brief Our wrapper for std::string. */ template class CStdStr : public std::basic_string { @@ -732,7 +794,7 @@ public: // ============================================================================= // Now typedef our class names based upon this humongous template - +/** @brief Typedef the class names based on the template */ typedef CStdStr CStdStringA; // a better std::string #define CStdString CStdStringA @@ -783,7 +845,10 @@ struct StdStringEqualsNoCase #endif // #ifndef STDSTRING_H -/* +/** + * @file + * @author Joseph M. O'Leary (c) 1999 + * @section LICENSE * COPYRIGHT: * 1999 Joseph M. O'Leary. This code is free. Use it anywhere you want. * Rewrite it, restructure it, whatever. Please don't blame me if it makes diff --git a/src/StepMania-net2003.vcproj b/src/StepMania-net2003.vcproj index 74e4579685..2a0cbf18f1 100644 --- a/src/StepMania-net2003.vcproj +++ b/src/StepMania-net2003.vcproj @@ -986,6 +986,12 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ + + + + @@ -998,6 +1004,12 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ + + + + @@ -1346,12 +1358,6 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ - - - - @@ -1382,12 +1388,6 @@ cl /Zl /nologo /c verstub.cpp /Fo"$(IntDir)"\ - - - - diff --git a/src/StepMania-net2005.vcproj b/src/StepMania-net2005.vcproj index 127763f0e9..8e593ab5a9 100644 --- a/src/StepMania-net2005.vcproj +++ b/src/StepMania-net2005.vcproj @@ -1314,6 +1314,14 @@ RelativePath="NotesLoaderSM.h" > + + + + @@ -1330,6 +1338,15 @@ RelativePath="NotesWriterSM.h" > + + + + + @@ -2510,14 +2527,6 @@ RelativePath="GrooveRadar.h" > - - - - @@ -2558,14 +2567,6 @@ RelativePath=".\ModIconRow.h" > - - - - diff --git a/src/StepMania-net2008.vcproj b/src/StepMania-net2008.vcproj index e510383dfb..4393682851 100644 --- a/src/StepMania-net2008.vcproj +++ b/src/StepMania-net2008.vcproj @@ -1456,6 +1456,14 @@ RelativePath="NotesLoaderSM.h" > + + + + @@ -1472,6 +1480,15 @@ RelativePath="NotesWriterSM.h" > + + + + + @@ -2712,14 +2729,6 @@ RelativePath="GrooveRadar.h" > - - - - @@ -2760,14 +2769,6 @@ RelativePath=".\ModIconRow.h" > - - - - diff --git a/src/StepMania.cpp b/src/StepMania.cpp index 51d6cf2035..2e8ee2af5c 100644 --- a/src/StepMania.cpp +++ b/src/StepMania.cpp @@ -1270,13 +1270,10 @@ void StepMania::ClearCredits() /* Returns true if the key has been handled and should be discarded, false if * the key should be sent on to screens. */ static LocalizedString SERVICE_SWITCH_PRESSED ( "StepMania", "Service switch pressed" ); -// xxx: Okay, these probably shouldn't be here, but I wanted them to be -// localized and this was the place to do it since this is where the control -// structure is placed... apologies to those who like properly structured -// language files. I like compatibility. -aj static LocalizedString RELOADED_METRICS( "ThemeManager", "Reloaded metrics" ); static LocalizedString RELOADED_METRICS_AND_TEXTURES( "ThemeManager", "Reloaded metrics and textures" ); static LocalizedString RELOADED_SCRIPTS( "ThemeManager", "Reloaded scripts" ); +static LocalizedString RELOADED_OVERLAY_SCREENS( "ThemeManager", "Reloaded overlay screens" ); bool HandleGlobalInputs( const InputEventPlus &input ) { // None of the globals keys act on types other than FIRST_PRESS @@ -1312,23 +1309,33 @@ bool HandleGlobalInputs( const InputEventPlus &input ) // re-added for StepMania 3.9 veterans, plus it's just plain old faster // than the debug menu. However, this is without the LShift capability // that was in 3.9; if we get enough requests, we'll re-add it, but meh. -aj + bool bIsShiftHeld = INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT), &input.InputList) || + INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT), &input.InputList); + bool bIsCtrlHeld = INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL), &input.InputList) || + INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL), &input.InputList); if( input.DeviceI == DeviceInput(DEVICE_KEYBOARD, KEY_F2) ) { - if( INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT), &input.InputList) || - INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT), &input.InputList)) + if( bIsShiftHeld && !bIsCtrlHeld ) { // Shift+F2: refresh metrics and CodeDetector cache only THEME->ReloadMetrics(); CodeDetector::RefreshCacheItems(); SCREENMAN->SystemMessage( RELOADED_METRICS ); } - else if(INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL), &input.InputList) || - INPUTFILTER->IsBeingPressed( DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL), &input.InputList)) + else if( bIsCtrlHeld && !bIsShiftHeld ) { // Ctrl+F2: reload scripts only THEME->UpdateLuaGlobals(); SCREENMAN->SystemMessage( RELOADED_SCRIPTS ); } + else if( bIsCtrlHeld && bIsShiftHeld ) + { + // Shift+Ctrl+F2: reload overlay screens (and metrics, since themers + // are likely going to do this after changing metrics and be lazy.) + THEME->ReloadMetrics(); + SCREENMAN->ReloadOverlayScreens(); + SCREENMAN->SystemMessage( RELOADED_OVERLAY_SCREENS ); + } else { // F2 alone: refresh metrics, textures, noteskins, codedetector cache diff --git a/src/StepManiaXbox-2003.vcproj b/src/StepManiaXbox-2003.vcproj index a071d84a48..e3cdae7552 100644 --- a/src/StepManiaXbox-2003.vcproj +++ b/src/StepManiaXbox-2003.vcproj @@ -1554,12 +1554,6 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ - - - - @@ -1590,12 +1584,6 @@ cl /Zl /nologo /c verstub.cpp /Fo$(IntDir)\ - - - - diff --git a/src/Steps.cpp b/src/Steps.cpp index e4349e0aea..852c5b0b47 100644 --- a/src/Steps.cpp +++ b/src/Steps.cpp @@ -20,7 +20,7 @@ #include "NoteData.h" #include "GameManager.h" #include "NoteDataUtil.h" -#include "NotesLoaderSM.h" +#include "NotesLoaderSSC.h" #include @@ -231,7 +231,7 @@ void Steps::Decompress() const { /* We have data on disk and not in memory. Load it. */ Song s; - if( !SMLoader::LoadFromSMFile(m_sFilename, s, true) ) + if( !SSCLoader::LoadFromSSCFile(m_sFilename, s, true) ) { LOG->Warn( "Couldn't load \"%s\"", m_sFilename.c_str() ); return; @@ -322,7 +322,7 @@ void Steps::DeAutogen( bool bCopyNoteData ) m_Difficulty = Real()->m_Difficulty; m_iMeter = Real()->m_iMeter; copy( Real()->m_CachedRadarValues, Real()->m_CachedRadarValues + NUM_PLAYERS, m_CachedRadarValues ); - + m_sCredit = Real()->m_sCredit; parent = NULL; if( bCopyNoteData ) @@ -366,6 +366,12 @@ void Steps::SetDifficultyAndDescription( Difficulty dc, RString sDescription ) MakeValidEditDescription( m_sDescription ); } +void Steps::SetCredit( RString sCredit ) +{ + DeAutogen(); + m_sCredit = sCredit; +} + bool Steps::MakeValidEditDescription( RString &sPreferredDescription ) { if( int(sPreferredDescription.size()) > MAX_EDIT_STEPS_DESCRIPTION_LENGTH ) @@ -391,13 +397,14 @@ void Steps::SetCachedRadarValues( const RadarValues v[NUM_PLAYERS] ) // lua start #include "LuaBinding.h" - +/** @brief Allow Lua to have access to the Steps. */ class LunaSteps: public Luna { public: DEFINE_METHOD( GetStepsType, m_StepsType ) DEFINE_METHOD( GetDifficulty, GetDifficulty() ) DEFINE_METHOD( GetDescription, GetDescription() ) + DEFINE_METHOD( GetAuthorCredit, GetCredit() ) DEFINE_METHOD( GetMeter, GetMeter() ) DEFINE_METHOD( GetFilename, GetFilename() ) DEFINE_METHOD( IsAutogen, IsAutogen() ) @@ -428,6 +435,7 @@ public: ADD_METHOD( GetStepsType ); ADD_METHOD( GetDifficulty ); ADD_METHOD( GetDescription ); + ADD_METHOD( GetAuthorCredit ); ADD_METHOD( GetMeter ); ADD_METHOD( GetFilename ); ADD_METHOD( GetRadarValues ); diff --git a/src/Steps.h b/src/Steps.h index 77d0fa3359..532857381a 100644 --- a/src/Steps.h +++ b/src/Steps.h @@ -1,4 +1,4 @@ -/* Steps - Holds note information for a Song. A Song may have one or more Notes. */ +/** @brief Steps - Holds note information for a Song. A Song may have one or more Notes. */ #ifndef STEPS_H #define STEPS_H @@ -14,12 +14,20 @@ class Profile; class NoteData; struct lua_State; +/** + * @brief Allow only 12 characters for the length of edits. + * + * This is a holdover from In The Groove: this may perhaps be not needed in the future. + */ const int MAX_EDIT_STEPS_DESCRIPTION_LENGTH = 12; +/** @brief The collective note pattern and information of the Steps that are played. */ class Steps { public: + /** @brief Set up the Steps with initial values. */ Steps(); + /** @brief Destroy the Steps that are no longer needed. */ ~Steps(); // initializers @@ -29,17 +37,52 @@ public: void Compress() const; void Decompress() const; - bool IsAutogen() const { return parent != NULL; } // Was created by autogen? + /** + * @brief Determine if these steps were created by the autogenerator. + * @return true if they were, false otherwise. + */ + bool IsAutogen() const { return parent != NULL; } - // Use a special value of difficulty + /** + * @brief Determine if this set of Steps is an edit. + * + * Edits have a special value of difficulty to make it easy to determine. + * @return true if this is an edit, false otherwise. + */ bool IsAnEdit() const { return m_Difficulty == Difficulty_Edit; } + /** + * @brief Determine if this set of Steps is a player edit. + * + * Player edits also have to be loaded from a player's profile slot, not the machine. + * @return true if this is a player edit, false otherwise. */ bool IsAPlayerEdit() const { return IsAnEdit() && GetLoadedFromProfileSlot() < ProfileSlot_Machine; } + /** + * @brief Determine if these steps were loaded from a player's profile. + * @return true if they were from a player profile, false otherwise. + */ bool WasLoadedFromProfile() const { return m_LoadedFromProfile != ProfileSlot_Invalid; } ProfileSlot GetLoadedFromProfileSlot() const { return m_LoadedFromProfile; } + /** + * @brief Retrieve the description used for this edit. + * @return the description used for this edit. + */ RString GetDescription() const { return Real()->m_sDescription; } + /** + * @brief Retrieve the difficulty used for this edit. + * @return the difficulty used for this edit. + */ Difficulty GetDifficulty() const { return Real()->m_Difficulty; } + /** + * @brief Retrieve the meter used for this edit. + * @return the meter used for this edit. + */ int GetMeter() const { return Real()->m_iMeter; } const RadarValues& GetRadarValues( PlayerNumber pn ) const { return Real()->m_CachedRadarValues[pn]; } + /** + * @brief Retrieve the author credit used for this edit. + * @return the author credit used for this edit. + */ + RString GetCredit() const { return Real()->m_sCredit; } void SetFilename( RString fn ) { m_sFilename = fn; } RString GetFilename() const { return m_sFilename; } @@ -48,6 +91,7 @@ public: void SetDifficulty( Difficulty dc ) { SetDifficultyAndDescription( dc, GetDescription() ); } void SetDescription( RString sDescription ) { SetDifficultyAndDescription( this->GetDifficulty(), sDescription ); } void SetDifficultyAndDescription( Difficulty dc, RString sDescription ); + void SetCredit( RString sCredit ); static bool MakeValidEditDescription( RString &sPreferredDescription ); // return true if was modified void SetLoadedFromProfile( ProfileSlot slot ) { m_LoadedFromProfile = slot; } @@ -75,7 +119,10 @@ private: inline const Steps *Real() const { return parent ? parent : this; } void DeAutogen( bool bCopyNoteData = true ); /* If this Steps is autogenerated, make it a real Steps. */ - /* If this Steps is autogenerated, this will point to the autogen + /** + * @brief Identify this Steps' parent. + * + * If this Steps is autogenerated, this will point to the autogen * source. If this is true, m_sNoteDataCompressed will always be empty. */ const Steps *parent; @@ -86,22 +133,35 @@ private: mutable bool m_bNoteDataIsFilled; mutable RString m_sNoteDataCompressed; + /** @brief The name of the file where these steps are stored. */ RString m_sFilename; - bool m_bSavedToDisk; // true if this was loaded from disk or has been saved to disk. - ProfileSlot m_LoadedFromProfile; // ProfileSlot_Invalid if wasn't loaded from a profile + /** @brief true if these Steps were loaded from or saved to disk. */ + bool m_bSavedToDisk; + /** @brief What profile was used? This is ProfileSlot_Invalid if not from a profile. */ + ProfileSlot m_LoadedFromProfile; /* These values are pulled from the autogen source first, if there is one. */ - mutable unsigned m_iHash; // only used if m_Difficulty == Difficulty_Edit - RString m_sDescription; // Step author, edit name, or something meaningful - Difficulty m_Difficulty; // difficulty classification - int m_iMeter; // difficulty rating from MIN_METER to MAX_METER + /** @brief The hash of the steps. This is used only for Edit Steps. */ + mutable unsigned m_iHash; + /** @brief The name of the edit, or some other useful description. + This used to also contain the step author's name. */ + RString m_sDescription; + /** @brief The difficulty that these steps are assigned to. */ + Difficulty m_Difficulty; + /** @brief The numeric difficulty of the Steps, ranging from MIN_METER to MAX_METER. */ + int m_iMeter; + /** @brief The radar values used for each player. */ RadarValues m_CachedRadarValues[NUM_PLAYERS]; + /** @brief The name of the person who created the Steps. */ + RString m_sCredit; }; #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/StepsDisplay.cpp b/src/StepsDisplay.cpp index a9ce7c04c3..92c3639d4e 100644 --- a/src/StepsDisplay.cpp +++ b/src/StepsDisplay.cpp @@ -213,6 +213,7 @@ void StepsDisplay::SetInternal( const SetParams ¶ms ) if( m_bShowTicks ) { + // todo: let themers handle the logic of tick text. -aj char on = char('1'); char off = '0'; @@ -233,6 +234,7 @@ void StepsDisplay::SetInternal( const SetParams ¶ms ) } else { + // todo: allow themer to specify a format string? -aj const RString sMeter = ssprintf( "%i", params.iMeter ); m_textMeter.SetText( sMeter ); m_textMeter.HandleMessage( msg ); @@ -260,6 +262,7 @@ void StepsDisplay::SetInternal( const SetParams ¶ms ) RString sStepsType = GAMEMAN->GetStepsTypeInfo(params.st).szName; m_sprStepsType.Load( THEME->GetPathG(m_sMetricsGroup,"StepsType "+sStepsType) ); */ + m_sprStepsType->HandleMessage( msg ); } } diff --git a/src/StepsUtil.cpp b/src/StepsUtil.cpp index 30dee5b56c..f2f4afd9f5 100644 --- a/src/StepsUtil.cpp +++ b/src/StepsUtil.cpp @@ -258,11 +258,11 @@ Steps *StepsID::ToSteps( const Song *p, bool bAllowNull ) const Steps *pRet = NULL; if( dc == Difficulty_Edit ) { - pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, sDescription, uHash, true ); + pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, sDescription, "", uHash, true ); } else { - pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, "", 0, true ); + pRet = SongUtil::GetOneSteps( p, st, dc, -1, -1, "", "", 0, true ); } if( !bAllowNull && pRet == NULL ) diff --git a/src/StreamDisplay.cpp b/src/StreamDisplay.cpp index 2828693944..185028e209 100644 --- a/src/StreamDisplay.cpp +++ b/src/StreamDisplay.cpp @@ -20,7 +20,6 @@ StreamDisplay::StreamDisplay() m_fVelocity = 0; m_fPassingAlpha = 0; m_fHotAlpha = 0; - m_fThreePartWidth = 0; m_bAlwaysBounce = false; } @@ -33,13 +32,8 @@ void StreamDisplay::Load( const RString &_sMetricsGroup ) float fTextureCoordScaleX = THEME->GetMetricF(sMetricsGroup,"TextureCoordScaleX"); int iNumPills = THEME->GetMetricF(sMetricsGroup,"NumPills"); - m_bUsingThreePart = THEME->GetMetricB(sMetricsGroup,"UseThreePartMethod"); m_bAlwaysBounce = THEME->GetMetricB(sMetricsGroup,"AlwaysBounceNormalBar"); - // three part method only uses 3 pills - if(iNumPills != 3) - m_bUsingThreePart = false; - FOREACH_ENUM( StreamType, st ) { ASSERT( m_vpSprPill[st].empty() ); @@ -48,35 +42,15 @@ void StreamDisplay::Load( const RString &_sMetricsGroup ) { Sprite *pSpr = new Sprite; - if( m_bUsingThreePart ) - { - pSpr->Load( THEME->GetPathG( sMetricsGroup, ssprintf("%s part%d",StreamTypeToString(st).c_str(),i) ) ); - - if(pSpr->GetNumStates() > 1) - { - pSpr->SetAllStateDelays( THEME->GetMetricF( sMetricsGroup, ssprintf("%spart%ddelay",StreamTypeToString(st).c_str(),i) ) ); - } - } - else - pSpr->Load( THEME->GetPathG( sMetricsGroup, StreamTypeToString(st) ) ); + pSpr->Load( THEME->GetPathG( sMetricsGroup, StreamTypeToString(st) ) ); m_vpSprPill[st].push_back( pSpr ); - if( !m_bUsingThreePart ) - { - m_transformPill.TransformItemDirect( *pSpr, -1, i, iNumPills ); - float f = 1 / fTextureCoordScaleX; - pSpr->SetCustomTextureRect( RectF(f*i,0,f*(i+1),1) ); - } + m_transformPill.TransformItemDirect( *pSpr, -1, i, iNumPills ); + float f = 1 / fTextureCoordScaleX; + pSpr->SetCustomTextureRect( RectF(f*i,0,f*(i+1),1) ); this->AddChild( pSpr ); } - - if( m_bUsingThreePart ) - { - m_fThreePartWidth = THEME->GetMetricF( sMetricsGroup, "ThreePartWidth" ); - // first element positioned depending on metric width specified - m_vpSprPill[st][0]->AddX( -(m_fThreePartWidth/2 + m_vpSprPill[st][0]->GetZoomedWidth()/2) ); - } } } @@ -131,28 +105,9 @@ void StreamDisplay::Update( float fDeltaSecs ) // XXX scale by current song speed - if( !m_bUsingThreePart ) // usual lifebar - { - pSpr->SetCropRight( 1.0f - fPercentFilledThisPill ); - pSpr->SetTexCoordVelocity( -1, 0 ); - } - else // using the three-part method - { + pSpr->SetCropRight( 1.0f - fPercentFilledThisPill ); + pSpr->SetTexCoordVelocity( -1, 0 ); - if( i==1 ) // middle pill - { - float fMiddleWidth = m_fThreePartWidth * m_fTrailingPercent; - pSpr->ZoomToWidth( fMiddleWidth ); - - float fMiddleX = m_vpSprPill[st][0]->GetX() + ( fMiddleWidth/2 ) + ( m_vpSprPill[st][0]->GetZoomedWidth()/2 ); - pSpr->SetX( fMiddleX ); - } - else if( i!=0 ) // last pill - { - float fEndX = m_vpSprPill[st][1]->GetX() + ( m_vpSprPill[st][1]->GetZoomedWidth()/2 ) + ( pSpr->GetZoomedWidth()/2 ); - pSpr->SetX( fEndX ); - } - } // Optimization: Don't draw pills that are covered up switch( st ) { diff --git a/src/StreamDisplay.h b/src/StreamDisplay.h index a9e124de9b..11c178ece4 100644 --- a/src/StreamDisplay.h +++ b/src/StreamDisplay.h @@ -15,7 +15,6 @@ enum StreamType NUM_StreamType, }; - class StreamDisplay : public ActorFrame { public: @@ -43,9 +42,6 @@ private: float m_fPassingAlpha; float m_fHotAlpha; - bool m_bUsingThreePart; - - float m_fThreePartWidth; bool m_bAlwaysBounce; }; diff --git a/src/Style.cpp b/src/Style.cpp index e034c2e63f..b8a41a8dbd 100644 --- a/src/Style.cpp +++ b/src/Style.cpp @@ -120,12 +120,16 @@ public: static int GetName( T* p, lua_State *L ) { LuaHelpers::Push( L, (RString) p->m_szName ); return 1; } DEFINE_METHOD( GetStyleType, m_StyleType ) DEFINE_METHOD( GetStepsType, m_StepsType ) + DEFINE_METHOD( ColumnsPerPlayer, m_iColsPerPlayer ) + DEFINE_METHOD( NeedsZoomOutWith2Players, m_bNeedsZoomOutWith2Players ) LunaStyle() { ADD_METHOD( GetName ); ADD_METHOD( GetStyleType ); ADD_METHOD( GetStepsType ); + ADD_METHOD( ColumnsPerPlayer ); + ADD_METHOD( NeedsZoomOutWith2Players ); } }; diff --git a/src/Style.h b/src/Style.h index 05e2c3b913..4c91746533 100644 --- a/src/Style.h +++ b/src/Style.h @@ -1,4 +1,4 @@ -/* Style - A data structure that holds the definition for one of a Game's styles. */ +/** @brief Style - A data structure that holds the definition for one of a Game's styles. */ #ifndef STYLE_H #define STYLE_H @@ -8,8 +8,9 @@ #include "PlayerNumber.h" #include "GameConstantsAndTypes.h" - +/** @brief Each style can have a maximum amount of columns to work with. */ const int MAX_COLS_PER_PLAYER = MAX_NOTE_TRACKS; +/** @brief Provide a default value for an invalid column. */ static const int Column_Invalid = -1; class NoteData; @@ -19,41 +20,68 @@ struct lua_State; class Style { public: - bool m_bUsedForGameplay; // Can be used only for gameplay? - bool m_bUsedForEdit; // Can be used for editing? - bool m_bUsedForDemonstration; // Can be used for demonstration? - bool m_bUsedForHowToPlay; // Can be used for HowToPlay? + /** @brief Can this style be used for gameplay purposes? */ + bool m_bUsedForGameplay; + /** @brief Can this style be used for making edits? */ + bool m_bUsedForEdit; + /** @brief Can this style be used in a demonstration? */ + bool m_bUsedForDemonstration; + /** @brief Can this style be used to explain how to play the game? */ + bool m_bUsedForHowToPlay; - /* The name of the style. (This is currently unused.) */ + /** + * @brief The name of the style. + * + * At this time, it is currently unused. */ const char * m_szName; - /* Steps format used for each player. For example, "dance versus" reads - * the Steps with the tag "dance-single". */ + /** + * @brief Steps format used for each player. + * + * For example, "dance versus" reads the Steps with the tag "dance-single". */ StepsType m_StepsType; + /** @brief Style format used for each player. */ StyleType m_StyleType; - int m_iColsPerPlayer; // number of total tracks this style expects (e.g. 4 for versus, but 8 for double) + /** + * @brief The number of total tracks/columns this style expects. + * + * As an example, 4 is expected for ITG style versus, but 8 for ITG style double. */ + int m_iColsPerPlayer; + /** @brief Some general column infromation */ struct ColumnInfo { - int track; // take note data from this track - float fXOffset; // x position of the column relative to player center - const char *pzName; // name of this column, or NULL to use the name of a button mapped to it + int track; /**< Take note data from this track. */ + float fXOffset; /**< This is the x position of the column relative to the player's center. */ + const char *pzName; /**< The name of the column, or NULL to use the button name mapped to it. */ }; - ColumnInfo m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; // maps each players' column to a track in the NoteData + /** @brief Map each players' colun to a track in the NoteData. */ + ColumnInfo m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER]; - /* This maps from game inputs to columns. More than one button may map to a + /* This maps from game inputs to columns. More than one button may map to a * single column. */ enum { NO_MAPPING = -1, END_MAPPING = -2 }; - int m_iInputColumn[NUM_GameController][NUM_GameButton]; // maps each input to a column, or GameButton_Invalid + /** @brief Map each input to a column, or GameButton_Invalid. */ + int m_iInputColumn[NUM_GameController][NUM_GameButton]; int m_iColumnDrawOrder[MAX_COLS_PER_PLAYER]; - bool m_bNeedsZoomOutWith2Players; - bool m_bCanUseBeginnerHelper; - bool m_bLockDifficulties; // used in couple Styles + /** @brief Does this style need to be zoomed out with two players due to too many columns? */ + bool m_bNeedsZoomOutWith2Players; + /** @brief Can this style use the BeginnerHelper for assisting new people to the game? */ + bool m_bCanUseBeginnerHelper; + /** + * @brief Should difficulty selection be locked when using this style? + * + * This is primarily for Couple and Routine styles. */ + bool m_bLockDifficulties; GameInput StyleInputToGameInput( int iCol, PlayerNumber pn ) const; - // Returns Column_Invalid if the input is an invalid column, such as UL corner in 4 pad mode + /** + * @brief Retrieve the column based on the game input. + * @param GameI the game input. + * @return the Column number of the style, or Column_Invalid if it's an invalid column. + * Examples of this include getting the upper left hand corner in a traditional four panel mode. */ int GameInputToColumn( const GameInput &GameI ) const; RString ColToButtonName( int iCol ) const; @@ -68,8 +96,10 @@ public: #endif -/* - * (c) 2001-2002 Chris Danford +/** + * @file + * @author Chris Danford (c) 2001-2002 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/ThemeManager.cpp b/src/ThemeManager.cpp index f0af2ff534..b691d3d7e7 100644 --- a/src/ThemeManager.cpp +++ b/src/ThemeManager.cpp @@ -97,7 +97,7 @@ void ThemeManager::Subscribe( IThemeMetric *p ) { g_Subscribers.Subscribe( p ); - // It's ThemeManager's responsibility to make sure all of it's subscribers + // It's ThemeManager's responsibility to make sure all of its subscribers // are updated with current data. If a metric is created after // a theme is loaded, ThemeManager should update it right away (not just // when the theme changes). @@ -450,11 +450,21 @@ void ThemeManager::RunLuaScripts( const RString &sMask ) { /* Run all script files with the given mask in Lua for all themes. Start * from the deepest fallback theme and work outwards. */ + + /* TODO: verify whether this final check is necessary. */ + const RString sCurThemeName = m_sCurThemeName; + deque::const_iterator iter = g_vThemes.end(); do { --iter; - const RString &sThemeDir = GetThemeDirFromName( iter->sThemeName ); + + /* HACK: pretend to be the theme these are under by setting m_sCurThemeName + * to the name of the theme whose scripts are currently running; if those + * scripts call GetThemeName(), it'll return the theme the script is in. */ + + m_sCurThemeName = iter->sThemeName; + const RString &sThemeDir = GetThemeDirFromName( m_sCurThemeName ); vector asElementPaths; // get files from directories @@ -489,6 +499,13 @@ void ThemeManager::RunLuaScripts( const RString &sMask ) } } while( iter != g_vThemes.begin() ); + + /* TODO: verify whether this final check is necessary. */ + if( sCurThemeName != m_sCurThemeName ) + { + LOG->Warn( "ThemeManager: theme name was not restored after RunLuaScripts" ); + m_sCurThemeName = sCurThemeName; + } } void ThemeManager::UpdateLuaGlobals() diff --git a/src/ThemeManager.h b/src/ThemeManager.h index 474ca5d048..f4e9212a16 100644 --- a/src/ThemeManager.h +++ b/src/ThemeManager.h @@ -99,9 +99,7 @@ public: static RString GetBlankGraphicPath(); - // // For self-registering metrics - // static void Subscribe( IThemeMetric *p ); static void Unsubscribe( IThemeMetric *p ); @@ -113,7 +111,7 @@ protected: void LoadThemeMetrics( const RString &sThemeName, const RString &sLanguage_ ); RString GetMetricRaw( const IniFile &ini, const RString &sMetricsGroup, const RString &sValueName ); bool GetMetricRawRecursive( const IniFile &ini, const RString &sMetricsGroup, const RString &sValueName, RString &sRet ); - + bool GetPathInfoToAndFallback( PathInfo &out, ElementCategory category, const RString &sMetricsGroup, const RString &sFile ); bool GetPathInfoToRaw( PathInfo &out, const RString &sThemeName, ElementCategory category, const RString &sMetricsGroup, const RString &sFile ); static RString GetThemeDirFromName( const RString &sThemeName ); diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 5af204256a..773be72a58 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -47,6 +47,11 @@ void TimingData::AddWarpSegment( const WarpSegment &seg ) m_WarpSegments.insert( upper_bound(m_WarpSegments.begin(), m_WarpSegments.end(), seg), seg ); } +void TimingData::AddTickcountSegment( const TickcountSegment &seg ) +{ + m_TickcountSegments.insert( upper_bound(m_TickcountSegments.begin(), m_TickcountSegments.end(), seg), seg ); +} + /* Change an existing BPM segment, merge identical segments together or insert a new one. */ void TimingData::SetBPMAtRow( int iNoteRow, float fBPM ) { @@ -72,11 +77,6 @@ void TimingData::SetBPMAtRow( int iNoteRow, float fBPM ) } } -void TimingData::SetStopAtRow( int iRow, float fSeconds ) -{ - SetStopAtRow(iRow,fSeconds,false); -} - void TimingData::SetStopAtRow( int iRow, float fSeconds, bool bDelay ) { unsigned i; @@ -84,7 +84,7 @@ void TimingData::SetStopAtRow( int iRow, float fSeconds, bool bDelay ) if( m_StopSegments[i].m_iStartRow == iRow ) break; - if( i == m_StopSegments.size() ) // there is no BPMSegment at the current beat + if( i == m_StopSegments.size() ) // there is no StopSegment at the current beat { // create a new StopSegment if( fSeconds > 0 || PREFSMAN->m_bQuirksMode ) @@ -104,9 +104,46 @@ void TimingData::SetStopAtRow( int iRow, float fSeconds, bool bDelay ) } } -void TimingData::SetDelayAtRow( int iRow, float fSeconds ) +void TimingData::SetTimeSignatureAtRow( int iRow, int iNumerator, int iDenominator ) { - SetStopAtRow(iRow,fSeconds,true); + unsigned i; + for( i = 0; i < m_vTimeSignatureSegments.size(); i++ ) + { + if( m_vTimeSignatureSegments[i].m_iStartRow >= iRow) + break; // We found our segment. + } + TimeSignatureSegment &ts = m_vTimeSignatureSegments[i]; + TimeSignatureSegment &prev = m_vTimeSignatureSegments[i-1]; + if( i == m_vTimeSignatureSegments.size() || ts.m_iStartRow != iRow ) + { + // There is no TimeSignatureSegment at the specified beat. + // If the TimeSignatureSegment being set differs + // from the last TimeSignature, create a new TimeSignatureSegment. + if( i == 0 || ( prev.m_iNumerator != iNumerator || prev.m_iDenominator != iDenominator ) ) + AddTimeSignatureSegment( TimeSignatureSegment(iRow, iNumerator, iDenominator) ); + } + else // TimeSignatureSegment being modified is m_vTimeSignatureSegments[i] + { + if( i > 0 && prev.m_iNumerator == iNumerator + && prev.m_iDenominator == iDenominator ) + m_vTimeSignatureSegments.erase( m_vTimeSignatureSegments.begin()+i, + m_vTimeSignatureSegments.begin()+i+1 ); + else + { + ts.m_iNumerator = iNumerator; + ts.m_iDenominator = iDenominator; + } + } +} + +void TimingData::SetTimeSignatureNumeratorAtRow( int iRow, int iNumerator ) +{ + SetTimeSignatureAtRow( iRow, iNumerator, GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iRow ) ).m_iDenominator ); +} + +void TimingData::SetTimeSignatureDenominatorAtRow( int iRow, int iDenominator ) +{ + SetTimeSignatureAtRow( iRow, GetTimeSignatureSegmentAtBeat( NoteRowToBeat( iRow ) ).m_iNumerator, iDenominator ); } /* @@ -116,21 +153,52 @@ void TimingData::SetWarpAtRow( int iRowAt, float fLengthBeats ) } */ -float TimingData::GetStopAtRow( int iNoteRow, bool &bDelayOut ) const +/* 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 ) + break; + + if( i == m_TickcountSegments.size() || m_TickcountSegments[i].m_iStartRow != iRow ) + { + // No TickcountSegment here. Make a new segment if required. + if( i == 0 || m_TickcountSegments[i-1].m_iTicks != iTicks ) + AddTickcountSegment( TickcountSegment(iRow, iTicks ) ); + } + else // TickcountSegment being modified is m_TickcountSegments[i] + { + if( i > 0 && m_TickcountSegments[i-1].m_iTicks == iTicks ) + m_TickcountSegments.erase( m_TickcountSegments.begin()+i, m_TickcountSegments.begin()+i+1 ); + else + m_TickcountSegments[i].m_iTicks = iTicks; + } +} + +float TimingData::GetStopAtRow( int iNoteRow, bool bDelay ) const { - bDelayOut = false; // not a delay by default for( unsigned i=0; i iIndex ) + if( m_BPMSegments[i+1].m_iStartRow > iNoteRow ) break; return m_BPMSegments[i].GetBPM(); } -int TimingData::GetBPMSegmentIndexAtBeat( float fBeat ) +int TimingData::GetBPMSegmentIndexAtRow( int iNoteRow ) const +{ + unsigned i; + for( i=0; i iNoteRow ) + break; + return (int)i; +} + +int TimingData::GetStopSegmentIndexAtRow( int iNoteRow, bool bDelay ) const +{ + unsigned i; + for( i=0; i iNoteRow && s.m_bDelay == bDelay ) + break; + } + return (int)i; +} + +int TimingData::GetTimeSignatureSegmentIndexAtRow( int iRow ) const { - int iIndex = BeatToNoteRow( fBeat ); int i; - for( i=0; i<(int)(m_BPMSegments.size())-1; i++ ) - if( m_BPMSegments[i+1].m_iStartRow > iIndex ) + for (i=0; i < (int)(m_vTimeSignatureSegments.size()) - 1; i++ ) + if( m_vTimeSignatureSegments[i+1].m_iStartRow > iRow ) break; return i; } -const TimeSignatureSegment& TimingData::GetTimeSignatureSegmentAtBeat( float fBeat ) const +TimeSignatureSegment& TimingData::GetTimeSignatureSegmentAtRow( int iRow ) { - int iIndex = BeatToNoteRow( fBeat ); unsigned i; for( i=0; i iIndex ) + if( m_vTimeSignatureSegments[i+1].m_iStartRow > iRow ) break; return m_vTimeSignatureSegments[i]; } -BPMSegment& TimingData::GetBPMSegmentAtBeat( float fBeat ) +int TimingData::GetTimeSignatureNumeratorAtRow( int iRow ) +{ + return GetTimeSignatureSegmentAtRow( iRow ).m_iNumerator; +} + +int TimingData::GetTimeSignatureDenominatorAtRow( int iRow ) +{ + return GetTimeSignatureSegmentAtRow( iRow ).m_iDenominator; +} + +BPMSegment& TimingData::GetBPMSegmentAtRow( int iNoteRow ) { static BPMSegment empty; if( m_BPMSegments.empty() ) return empty; - int i = GetBPMSegmentIndexAtBeat( fBeat ); + int i = GetBPMSegmentIndexAtRow( iNoteRow ); return m_BPMSegments[i]; } +StopSegment& TimingData::GetStopSegmentAtRow( int iNoteRow, bool bDelay ) +{ + static StopSegment empty; + if( m_StopSegments.empty() ) + return empty; + + int i = GetStopSegmentIndexAtRow( iNoteRow, bDelay ); + return m_StopSegments[i]; +} + +int TimingData::GetTickcountSegmentIndexAtRow( int iRow ) const +{ + int i; + for (i=0; i < (int)(m_TickcountSegments.size()) - 1; i++ ) + if( m_TickcountSegments[i+1].m_iStartRow > iRow ) + break; + return i; +} + +TickcountSegment& TimingData::GetTickcountSegmentAtRow( int iRow ) +{ + static TickcountSegment empty; + if( m_TickcountSegments.empty() ) + return empty; + + int i = GetTickcountSegmentIndexAtBeat( iRow ); + return m_TickcountSegments[i]; +} + +int TimingData::GetTickcountAtRow( int iRow ) const +{ + return m_TickcountSegments[GetTickcountSegmentIndexAtRow( iRow )].m_iTicks; +} + void TimingData::GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &fWarpLengthOut ) const { fElapsedTime += PREFSMAN->m_fGlobalOffsetSeconds; @@ -290,7 +420,6 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float if( !bIsLastBPMSegment && m_WarpSegments[j].m_iStartRow > iStartRowNextSegment ) continue; - // are these wrong? am I second guessing myself? /* const int iRowsBeatsSinceStartOfSegment = m_WarpSegments[j].m_iStartRow - iStartRowThisSegment; const float fBeatsSinceStartOfSegment = NoteRowToBeat(iRowsBeatsSinceStartOfSegment); @@ -307,6 +436,7 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float // this WarpSegment IS the current segment. // don't know how to properly handle beatout -aj //fBeatOut = NoteRowToBeat(m_WarpSegments[j].m_iStartRow); + fBeatOut = fStartBeatThisSegment + fElapsedTime*fBPS; fBPSOut = m_BPMSegments[i+1].m_fBPS; bFreezeOut = false; bDelayOut = false; @@ -340,7 +470,7 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float // this BPMSegment is NOT the current segment. fElapsedTime -= fSecondsInThisSegment; - // xxx: negative testing + // xxx: negative testing [aj] /* //if(fBPS < 0.0f) if( (fStartBeatNextSegment >= 445.490f && fStartBeatNextSegment <= 453.72f) || fBPS < 0.0f ) @@ -355,12 +485,18 @@ void TimingData::GetBeatAndBPSFromElapsedTimeNoOffset( float fElapsedTime, float vector vBPMS = m_BPMSegments; vector vSS = m_StopSegments; vector vWS = m_WarpSegments; + vector vTSS = m_vTimeSignatureSegments; + vector vTS = m_TickcountSegments; sort( vBPMS.begin(), vBPMS.end() ); sort( vSS.begin(), vSS.end() ); sort( vWS.begin(), vWS.end() ); + sort( vTSS.begin(), vTSS.end() ); + sort( vTS.begin(), vTS.end() ); ASSERT_M( vBPMS == m_BPMSegments, "The BPM segments were not sorted!" ); ASSERT_M( vSS == m_StopSegments, "The Stop segments were not sorted!" ); ASSERT_M( vWS == m_WarpSegments, "The Warp segments were not sorted!" ); + ASSERT_M( vTSS == m_vTimeSignatureSegments, "The Time Signature segments were not sorted!" ); + ASSERT_M( vTS == m_TickcountSegments, "The Tickcount segments were not sorted!" ); FAIL_M( ssprintf("Failed to find the appropriate segment for elapsed time %f.", fTime) ); } @@ -467,6 +603,22 @@ void TimingData::InsertRows( int iStartRow, int iRowsToAdd ) continue; stop.m_iStartRow += iRowsToAdd; } + + for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ ) + { + TimeSignatureSegment &time = m_vTimeSignatureSegments[i]; + if( time.m_iStartRow < iStartRow ) + continue; + time.m_iStartRow += iRowsToAdd; + } + + for( unsigned i = 0; i < m_TickcountSegments.size(); i++ ) + { + TickcountSegment &tick = m_TickcountSegments[i]; + if( tick.m_iStartRow < iStartRow ) + continue; + tick.m_iStartRow += iRowsToAdd; + } if( iStartRow == 0 ) { @@ -524,6 +676,50 @@ void TimingData::DeleteRows( int iStartRow, int iRowsToDelete ) // After deleted region: stop.m_iStartRow -= iRowsToDelete; } + + for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ ) + { + TimeSignatureSegment &time = m_vTimeSignatureSegments[i]; + + // Before deleted region: + if( time.m_iStartRow < iStartRow ) + continue; + + // Inside deleted region: + if( time.m_iStartRow < iStartRow+iRowsToDelete ) + { + m_vTimeSignatureSegments.erase( + m_vTimeSignatureSegments.begin()+i, + m_vTimeSignatureSegments.begin()+i+1 ); + --i; + continue; + } + + // After deleted region: + + + time.m_iStartRow -= iRowsToDelete; + } + + for( unsigned i = 0; i < m_TickcountSegments.size(); i++ ) + { + TickcountSegment &tick = m_TickcountSegments[i]; + + // Before deleted region: + if( tick.m_iStartRow < iStartRow ) + continue; + + // Inside deleted region: + if( tick.m_iStartRow < iStartRow+iRowsToDelete ) + { + m_TickcountSegments.erase( m_TickcountSegments.begin()+i, m_TickcountSegments.begin()+i+1 ); + --i; + continue; + } + + // After deleted region: + tick.m_iStartRow -= iRowsToDelete; + } this->SetBPMAtRow( iStartRow, fNewBPM ); } diff --git a/src/TimingData.h b/src/TimingData.h index 86ac600492..9c85d67087 100644 --- a/src/TimingData.h +++ b/src/TimingData.h @@ -1,4 +1,4 @@ -/* TimingData - Holds data for translating beats<->seconds. */ +/** @brief TimingData - Holds data for translating beats<->seconds. */ #ifndef TIMING_DATA_H #define TIMING_DATA_H @@ -7,45 +7,149 @@ #include "PrefsManager.h" struct lua_State; +/** @brief Compare a TimingData segment's properties with one another. */ #define COMPARE(x) if(x!=other.x) return false; +/** + * @brief Identifies when a song changes its BPM. + */ struct BPMSegment { + /** + * @brief Creates a simple BPM Segment with default values. + * + * It is best to override the values as soon as possible. + */ BPMSegment() : m_iStartRow(-1), m_fBPS(-1.0f) { } + /** + * @brief Creates a BPM Segment with the specified starting row and beats per second. + * @param s the starting row of this segment. + * @param b the beats per second to be turned into beats per minute. + */ BPMSegment( int s, float b ) { m_iStartRow = max( 0, s ); SetBPM( b ); } + /** + * @brief The row in which the BPMSegment activates. + */ int m_iStartRow; + /** + * @brief The BPS to use when this row is reached. + */ float m_fBPS; - + + /** + * @brief Converts the BPS to a BPM. + * @param f The BPM. + */ void SetBPM( float f ) { m_fBPS = f / 60.0f; } + /** + * @brief Retrieves the BPM from the BPS. + * @return the BPM. + */ float GetBPM() const { return m_fBPS * 60.0f; } + /** + * @brief Compares two BPMSegments to see if they are equal to each other. + * @param other the other BPMSegment to compare to. + * @return the equality of the two segments. + */ bool operator==( const BPMSegment &other ) const { COMPARE( m_iStartRow ); COMPARE( m_fBPS ); return true; } + /** + * @brief Compares two BPMSegments to see if they are not equal to each other. + * @param other the other BPMSegment to compare to. + * @return the inequality of the two segments. + */ bool operator!=( const BPMSegment &other ) const { return !operator==(other); } - bool operator<( const BPMSegment &other ) const { return m_iStartRow < other.m_iStartRow; } + /** + * @brief Compares two BPMSegments to see if one is less than the other. + * @param other the other BPMSegment to compare to. + * @return the truth/falsehood of if the first is less than the second. + */ + bool operator<( const BPMSegment &other ) const + { + return m_iStartRow < other.m_iStartRow || + ( m_iStartRow == other.m_iStartRow && m_fBPS < other.m_fBPS ); + } + /** + * @brief Compares two BPMSegments to see if one is less than or equal to the other. + * @param other the other BPMSegment to compare to. + * @return the truth/falsehood of if the first is less or equal to than the second. + */ + bool operator<=( const BPMSegment &other ) const + { + return ( operator<(other) || operator==(other) ); + } + /** + * @brief Compares two BPMSegments to see if one is greater than the other. + * @param other the other BPMSegment to compare to. + * @return the truth/falsehood of if the first is greater than the second. + */ + bool operator>( const BPMSegment &other ) const { return !operator<=(other); } + /** + * @brief Compares two BPMSegments to see if one is greater than or equal to the other. + * @param other the other BPMSegment to compare to. + * @return the truth/falsehood of if the first is greater than or equal to the second. + */ + bool operator>=( const BPMSegment &other ) const { return !operator<(other); } }; - +/** + * @brief Identifies when a song has a stop or a delay. + * + * It is hopeful that stops and delays can be made into their own segments at some point. + */ struct StopSegment { + /** + * @brief Creates a simple Stop Segment with default values. + * + * It is best to override the values as soon as possible. + */ StopSegment() : m_iStartRow(-1), m_fStopSeconds(-1.0f), m_bDelay(false) { } + /** + * @brief Creates a Stop Segment at the specified row for the specified length of time. + * + * This will not create a dedicated delay segment. Use the third constructor for + * making delays. + * @param s the starting row of this segment. + * @param f the length of time to pause the note scrolling. + */ StopSegment( int s, float f ) { m_iStartRow = max( 0, s ); m_fStopSeconds = PREFSMAN->m_bQuirksMode ? f : max( 0.0f, f ); - m_bDelay = false; // no delay by default + m_bDelay = false; } + /** + * @brief Creates a Stop (or Delay) Segment at the specified row for the specified length of time. + * @param s the starting row of this segment. + * @param f the length of time to pause the note scrolling. + * @param d the flag that makes this Stop Segment a Delay Segment. + */ StopSegment( int s, float f, bool d ) { m_iStartRow = max( 0, s ); m_fStopSeconds = PREFSMAN->m_bQuirksMode ? f : max( 0.0f, f ); m_bDelay = d; } + /** + * @brief The row in which the StopSegment activates. + */ int m_iStartRow; + /** + * @brief The amount of time to complete the pause at the given row. + */ float m_fStopSeconds; - bool m_bDelay; // if true, treat this stop as a Pump delay instead - + /** + * @brief If true, the Stop Segment is treated as a Delay Segment, similar to the Pump It Up series. + */ + bool m_bDelay; + /** + * @brief Compares two StopSegments to see if they are equal to each other. + * @param other the other StopSegment to compare to. + * @return the equality of the two segments. + */ bool operator==( const StopSegment &other ) const { COMPARE( m_iStartRow ); @@ -53,27 +157,115 @@ struct StopSegment COMPARE( m_bDelay ); return true; } + /** + * @brief Compares two StopSegments to see if they are not equal to each other. + * @param other the other StopSegment to compare to. + * @return the inequality of the two segments. + */ bool operator!=( const StopSegment &other ) const { return !operator==(other); } - bool operator<( const StopSegment &other ) const { return m_iStartRow < other.m_iStartRow; } + /** + * @brief Compares two StopSegments to see if one is less than the other. + * + * It should be observed that Delay Segments have to come before Stop Segments. + * Otherwise, it will act like a Stop Segment with extra time from the Delay at + * the same row. + * @param other the other StopSegment to compare to. + * @return the truth/falsehood of if the first is less than the second. + */ + bool operator<( const StopSegment &other ) const + { + return ( m_iStartRow < other.m_iStartRow ) || + ( m_iStartRow == other.m_iStartRow && + ( m_bDelay && !other.m_bDelay || m_fStopSeconds < other.m_fStopSeconds )); + } + /** + * @brief Compares two StopSegments to see if one is less than or equal to the other. + * @param other the other StopSegment to compare to. + * @return the truth/falsehood of if the first is less or equal to than the second. + */ + bool operator<=( const StopSegment &other ) const + { + return ( operator<(other) || operator==(other) ); + } + /** + * @brief Compares two StopSegments to see if one is greater than the other. + * + * Similar to the less than operator function, stops must come after delays + * to avoid rendering the point of delays pointless. + * @param other the other StopSegment to compare to. + * @return the truth/falsehood of if the first is greater than the second. + */ + bool operator>( const StopSegment &other ) const { return !operator<=(other); } + /** + * @brief Compares two StopSegments to see if one is greater than or equal to the other. + * @param other the other StopSegment to compare to. + * @return the truth/falsehood of if the first is greater than or equal to the second. + */ + bool operator>=( const StopSegment &other ) const { return !operator<(other); } }; -/* This only supports simple time signatures. The upper number (called the numerator here, though this isn't +/** + * @brief Identifies when a song changes its time signature. + * + * This only supports simple time signatures. The upper number (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 { + /** + * @brief Creates a simple Time Signature Segment with default values. + */ TimeSignatureSegment() : m_iStartRow(-1), m_iNumerator(4), m_iDenominator(4) { } + /** + * @brief Creates a Time Signature Segment at the given row with a supplied numerator. + * @param r the starting row of the segment. + * @param n the numerator for the segment. + */ + TimeSignatureSegment( int r, int n ) { + m_iStartRow = max( 0, r ); + m_iNumerator = n; + m_iDenominator = 4; + } + /** + * @brief Creates a Time Signature Segment at the given row with a supplied numerator & denominator. + * @param r the starting row of the segment. + * @param n the numerator for the segment. + * @param d the denonimator for the segment. + */ + TimeSignatureSegment( int r, int n, int d ) { + m_iStartRow = max( 0, r ); + m_iNumerator = n; + m_iDenominator = d; + } + /** + * @brief The row in which the TimeSignatureSegment activates. + */ int m_iStartRow; + /** + * @brief The numerator of the TimeSignatureSegment. + */ int m_iNumerator; + /** + * @brief The denominator of the TimeSignatureSegment. + */ int m_iDenominator; - /* With BeatToNoteRow(1) rows per beat, then we should have BeatToNoteRow(1)*m_iNumerator + /** + * @brief Retrieve the number of note rows per measure within the TimeSignatureSegment. + * + * With BeatToNoteRow(1) rows per beat, then we should have BeatToNoteRow(1)*m_iNumerator * beats per measure. But if we assume that every BeatToNoteRow(1) rows is a quarter note, * and we want the beats to be 1/m_iDenominator notes, then we should have * BeatToNoteRow(1)*4 is rows per whole note and thus BeatToNoteRow(1)*4/m_iDenominator is - * rows per beat. Multiplying by m_iNumerator gives rows per measure. */ + * rows per beat. Multiplying by m_iNumerator gives rows per measure. + * @returns the number of note rows per measure. + */ int GetNoteRowsPerMeasure() const { return BeatToNoteRow(1) * 4 * m_iNumerator / m_iDenominator; } - + /** + * @brief Compares two TimeSignatureSegments to see if they are equal to each other. + * @param other the other TimeSignatureSegment to compare to. + * @return the equality of the two segments. + */ bool operator==( const TimeSignatureSegment &other ) const { COMPARE( m_iStartRow ); @@ -81,55 +273,607 @@ struct TimeSignatureSegment COMPARE( m_iDenominator ); return true; } + /** + * @brief Compares two TimeSignatureSegments to see if they are not equal to each other. + * @param other the other TimeSignatureSegment to compare to. + * @return the inequality of the two segments. + */ bool operator!=( const TimeSignatureSegment &other ) const { return !operator==(other); } - bool operator<( const TimeSignatureSegment &other ) const { return m_iStartRow < other.m_iStartRow; } + /** + * @brief Compares two TimeSignatureSegments to see if one is less than the other. + * @param other the other TimeSignatureSegment to compare to. + * @return the truth/falsehood of if the first is less than the second. + */ + bool operator<( const TimeSignatureSegment &other ) const + { + return m_iStartRow < other.m_iStartRow || + ( m_iStartRow == other.m_iStartRow && + ( m_iNumerator < other.m_iNumerator || + ( m_iNumerator == other.m_iNumerator && m_iDenominator < other.m_iDenominator ))); + } + /** + * @brief Compares two TimeSignatureSegments to see if one is less than or equal to the other. + * @param other the other TimeSignatureSegment to compare to. + * @return the truth/falsehood of if the first is less or equal to than the second. + */ + bool operator<=( const TimeSignatureSegment &other ) const + { + return ( operator<(other) || operator==(other) ); + } + /** + * @brief Compares two TimeSignatureSegments to see if one is greater than the other. + * @param other the other TimeSignatureSegment to compare to. + * @return the truth/falsehood of if the first is greater than the second. + */ + bool operator>( const TimeSignatureSegment &other ) const { return !operator<=(other); } + /** + * @brief Compares two TimeSignatureSegments to see if one is greater than or equal to the other. + * @param other the other TimeSignatureSegment to compare to. + * @return the truth/falsehood of if the first is greater than or equal to the second. + */ + bool operator>= (const TimeSignatureSegment &other ) const { return !operator<(other); } }; -/* A warp segment is used to replicate the effects of Negative BPMs without +/** + * @brief Identifies when a song needs to warp to a new beat. + * + * A warp segment is used to replicate the effects of Negative BPMs without * abusing negative BPMs. Negative BPMs should be converted to warp segments. * WarpAt=WarpTo is the format, where both are in beats. (Technically they're * both rows though.) */ struct WarpSegment { + /** + * @brief Creates a simple Warp Segment with default values. + * + * It is best to override the values as soon as possible. + */ WarpSegment() : m_iStartRow(-1), m_fWarpBeats(-1) { } + /** + * @brief Creates a Warp Segment with the specified starting row and row to warp to. + * @param s the starting row of this segment. + * @param r the row to warp to. + */ + WarpSegment( int s, int r ) + { + m_iStartRow = max( 0, s ); + m_fWarpBeats = max( 0, NoteRowToBeat( r ) ); + } + /** + * @brief Creates a Warp Segment with the specified starting row and beat to warp to. + * @param s the starting row of this segment. + * @param b the beat to warp to. + */ WarpSegment( int s, float b ){ m_iStartRow = max( 0, s ); m_fWarpBeats = max( 0, b ); } + /** + * @brief The row in which the WarpSegment activates. + */ int m_iStartRow; + /** + * @brief The beat to warp to. + */ float m_fWarpBeats; - + /** + * @brief Compares two WarpSegments to see if they are equal to each other. + * @param other the other WarpSegment to compare to. + * @return the equality of the two segments. + */ bool operator==( const WarpSegment &other ) const { COMPARE( m_iStartRow ); COMPARE( m_fWarpBeats ); return true; } + /** + * @brief Compares two WarpSegments to see if they are not equal to each other. + * @param other the other WarpSegment to compare to. + * @return the inequality of the two segments. + */ bool operator!=( const WarpSegment &other ) const { return !operator==(other); } - bool operator<( const WarpSegment &other ) const { return m_iStartRow < other.m_iStartRow; } + /** + * @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 + { + return m_iStartRow < other.m_iStartRow || + ( m_iStartRow == other.m_iStartRow && m_fWarpBeats < other.m_fWarpBeats ); + } + /** + * @brief Compares two WarpSegments to see if one is less than or equal to the other. + * @param other the other WarpSegment to compare to. + * @return the truth/falsehood of if the first is less or equal to than the second. + */ + bool operator<=( const WarpSegment &other ) const + { + return ( operator<(other) || operator==(other) ); + } + /** + * @brief Compares two WarpSegments to see if one is greater than the other. + * @param other the other WarpSegment to compare to. + * @return the truth/falsehood of if the first is greater than the second. + */ + bool operator>( const WarpSegment &other ) const { return !operator<=(other); } + /** + * @brief Compares two WarpSegments to see if one is greater than or equal to the other. + * @param other the other WarpSegment to compare to. + * @return the truth/falsehood of if the first is greater than or equal to the second. + */ + bool operator>=( const WarpSegment &other ) const { return !operator<(other); } }; +/** + * @brief Identifies when a chart is to have a different tickcount value for hold notes. + * + * A tickcount segment is used to better replicate the checkpoint hold + * system used by various based video games. The number is used to + * represent how many ticks can be counted in one beat. + */ +struct TickcountSegment +{ + /** + * @brief Creates a simple Tickcount Segment with default values. + * + * It is best to override the values as soon as possible. + */ + TickcountSegment() : m_iStartRow(-1), m_iTicks(2) { } + /** + * @brief Creates a Tickcount Segment with the specified starting row and beats per second. + * @param s the starting row of this segment. + * @param t the amount of ticks counted per beat. + */ + TickcountSegment( int s, int t ){ m_iStartRow = max( 0, s ); m_iTicks = max( 1, t ); } + /** + * @brief The row in which the TickcountSegment activates. + */ + int m_iStartRow; + /** + * @brief The amount of ticks counted per beat. + */ + int m_iTicks; + + /** + * @brief Compares two TickcountSegments to see if they are equal to each other. + * @param other the other TickcountSegment to compare to. + * @return the equality of the two segments. + */ + bool operator==( const TickcountSegment &other ) const + { + COMPARE( m_iStartRow ); + COMPARE( m_iTicks ); + return true; + } + /** + * @brief Compares two TickcountSegments to see if they are not equal to each other. + * @param other the other TickcountSegment to compare to. + * @return the inequality of the two segments. + */ + bool operator!=( const TickcountSegment &other ) const { return !operator==(other); } + /** + * @brief Compares two TickcountSegments to see if one is less than the other. + * @param other the other TickcountSegment to compare to. + * @return the truth/falsehood of if the first is less than the second. + */ + bool operator<( const TickcountSegment &other ) const { return m_iStartRow < other.m_iStartRow; } + /** + * @brief Compares two TickcountSegments to see if one is less than or equal to the other. + * @param other the other TickcountSegment to compare to. + * @return the truth/falsehood of if the first is less or equal to than the second. + */ + bool operator<=( const TickcountSegment &other ) const + { + return ( operator<(other) || operator==(other) ); + } + /** + * @brief Compares two TickcountSegments to see if one is greater than the other. + * @param other the other TickcountSegment to compare to. + * @return the truth/falsehood of if the first is greater than the second. + */ + bool operator>( const TickcountSegment &other ) const { return !operator<=(other); } + /** + * @brief Compares two TickcountSegments to see if one is greater than or equal to the other. + * @param other the other TickcountSegment to compare to. + * @return the truth/falsehood of if the first is greater than or equal to the second. + */ + bool operator>=( const TickcountSegment &other ) const { return !operator<(other); } +}; +/** + * @brief Houses all of the TimingData functions. + */ class TimingData { public: + /** + * @brief Sets up initial timing data. + */ TimingData(); - + /** + * @brief Gets the actual BPM of the song. + * @param fMinBPMOut the minimium specified BPM. + * @param fMaxBPMOut the maximum specified BPM. + */ void GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut ) const; - float GetBPMAtBeat( float fBeat ) const; + /** + * @brief Retrieve the BPM at the given row. + * @param iNoteRow the row in question. + * @return the BPM. + */ + float GetBPMAtRow( int iNoteRow ) const; + /** + * @brief Retrieve the BPM at the given beat. + * @param fBeat the beat in question. + * @return the BPM. + */ + float GetBPMAtBeat( float fBeat ) const { return GetBPMAtRow( BeatToNoteRow(fBeat)); } + /** + * @brief Set the row to have the new BPM. + * @param iNoteRow the row to have the new BPM. + * @param fBPM the BPM. + */ void SetBPMAtRow( int iNoteRow, float fBPM ); + /** + * @brief Set the beat to have the new BPM. + * @param fBeat the beat to have the new BPM. + * @param fBPM the BPM. + */ void SetBPMAtBeat( float fBeat, float fBPM ) { SetBPMAtRow( BeatToNoteRow(fBeat), fBPM ); } - void SetStopAtRow( int iNoteRow, float fSeconds ); - void SetStopAtRow( int iNoteRow, float fSeconds, bool bDelay ); // (sm-ssc) - void SetStopAtBeat( float fBeat, float fSeconds ) { SetStopAtRow( BeatToNoteRow(fBeat), fSeconds ); } - void SetStopAtBeat( float fBeat, float fSeconds, bool bDelay ) { SetStopAtRow( BeatToNoteRow(fBeat), fSeconds, bDelay ); } // (sm-ssc) - float GetStopAtRow( int iNoteRow, bool &bDelayOut ) const; - int GetWarpToRow( int iWarpBeginRow ) const; - void SetDelayAtRow( int iNoteRow, float fSeconds ); // sm-ssc - void MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor ); + /** + * @brief Retrieve the BPMSegment at the specified row. + * @param iNoteRow the row that has a BPMSegment. + * @return the BPMSegment in question. + */ + 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 ); + + /** + * @brief Retrieve the Stop/Delay at the given row. + * @param iNoteRow the row in question. + * @param bDelayOut A flag to determine if we are getting a delay or not. + * @return the time we stop at this row. + */ + float GetStopAtRow( int iNoteRow, bool bDelayOut ) const; + /** + * @brief Retrieve the Stop/Delay at the given row. + * @param fBeat the beat in question. + * @param bDelayOut A flag to determine if we are getting a delay or not. + * @return the time we stop at this beat. + */ + float GetStopAtBeat( float fBeat, bool bDelayOut ) const { return GetStopAtRow( BeatToNoteRow(fBeat), bDelayOut ); } + /** + * @brief Retrieve the stop time at the given row. + * @param iNoteRow the row in question. + * @return the stop time. + */ + float GetStopAtRow( int iNoteRow ) const; + /** + * @brief Retrieve the stop time at the given beat. + * @param fBeat the beat in question. + * @return the stop time. + */ + float GetStopAtBeat( float fBeat ) const { return GetStopAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Retrieve the delay time at the given row. + * @param iNoteRow the row in question. + * @return the delay time. + */ + float GetDelayAtRow( int iNoteRow ) const; + /** + * @brief Retrieve the delay time at the given beat. + * @param fBeat the beat in question. + * @return the delay time. + */ + float GetDelayAtBeat( float fBeat ) const { return GetDelayAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Set the row to have the new stop time. + * @param iNoteRow the row to have the new stop time. + * @param fSeconds the new stop time. + */ + void SetStopAtRow( int iNoteRow, float fSeconds ) { SetStopAtRow( iNoteRow, fSeconds, false ); } + /** + * @brief Set the row to have the new pause time. + * + * This function was added specifically for sm-ssc. + * @param iNoteRow the row to have the new pause time. + * @param fSeconds the new pause time. + * @param bDelay If true, this is a Delay Segment. Otherwise, it is a StopSegment. + */ + void SetStopAtRow( int iNoteRow, float fSeconds, bool bDelay ); + /** + * @brief Set the row to have the new delay time. + * + * This function was added specifically for sm-ssc. + * @param iNoteRow the row to have the new delay time. + * @param fSeconds the new delay time. + */ + void SetDelayAtRow( int iNoteRow, float fSeconds ) { SetStopAtRow( iNoteRow, fSeconds, true ); } + /** + * @brief Set the beat to have the new stop time. + * @param fBeat to have the new stop time. + * @param fSeconds the new stop time. + */ + void SetStopAtBeat( float fBeat, float fSeconds ) { SetStopAtRow( BeatToNoteRow(fBeat), fSeconds, false ); } + /** + * @brief Set the beat to have the new pause time. + * + * This function was added specifically for sm-ssc. + * @param fBeat the beat to have the new pause time. + * @param fSeconds the new pause time. + * @param bDelay If true, this is a Delay Segment. Otherwise, it is a StopSegment. + */ + void SetStopAtBeat( float fBeat, float fSeconds, bool bDelay ) { SetStopAtRow( BeatToNoteRow(fBeat), fSeconds, bDelay ); } + /** + * @brief Set the beat to have the new delay time. + * + * This function was added specifically for sm-ssc. + * @param fBeat the beat to have the new delay time. + * @param fSeconds the new delay time. + */ + void SetDelayAtBeat( float fBeat, float fSeconds ) { SetStopAtRow( BeatToNoteRow(fBeat), fSeconds, true ); } + /** + * @brief Retrieve the StopSegment at the specified row. + * @param iNoteRow the row that has a StopSegment. + * @return the StopSegment in question. + */ + 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); } + /** + * @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 ); + /** + * @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 ); } + /** + * @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 ); } + /** + * @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 ); + + /** + * @brief Retrieve the Time Signature's numerator at the given row. + * @param iNoteRow the row in question. + * @return the numerator. + */ + int GetTimeSignatureNumeratorAtRow( int iNoteRow ); + /** + * @brief Retrieve the Time Signature's numerator at the given beat. + * @param fBeat the beat in question. + * @return the numerator. + */ + int GetTimeSignatureNumeratorAtBeat( float fBeat ) { return GetTimeSignatureNumeratorAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Retrieve the Time Signature's denominator at the given row. + * @param iNoteRow the row in question. + * @return the denominator. + */ + int GetTimeSignatureDenominatorAtRow( int iNoteRow ); + /** + * @brief Retrieve the Time Signature's denominator at the given beat. + * @param fBeat the beat in question. + * @return the denominator. + */ + int GetTimeSignatureDenominatorAtBeat( float fBeat ) { return GetTimeSignatureDenominatorAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Set the row to have the new Time Signature. + * @param iNoteRow the row to have the new Time Signature. + * @param iNumerator the numerator. + * @param iDenominator the denominator. + */ + void SetTimeSignatureAtRow( int iNoteRow, int iNumerator, int iDenominator ); + /** + * @brief Set the beat to have the new Time Signature. + * @param fBeat the beat to have the new Time Signature. + * @param iNumerator the numerator. + * @param iDenominator the denominator. + */ + void SetTimeSignatureAtBeat( float fBeat, int iNumerator, int iDenominator ) { SetTimeSignatureAtRow( BeatToNoteRow(fBeat), iNumerator, iDenominator ); } + /** + * @brief Set the row to have the new Time Signature numerator. + * @param iNoteRow the row to have the new Time Signature numerator. + * @param iNumerator the numerator. + */ + void SetTimeSignatureNumeratorAtRow( int iNoteRow, int iNumerator ); + /** + * @brief Set the beat to have the new Time Signature numerator. + * @param fBeat the beat to have the new Time Signature numerator. + * @param iNumerator the numerator. + */ + void SetTimeSignatureNumeratorAtBeat( float fBeat, int iNumerator ) { SetTimeSignatureNumeratorAtRow( BeatToNoteRow(fBeat), iNumerator); } + /** + * @brief Set the row to have the new Time Signature denominator. + * @param iNoteRow the row to have the new Time Signature denominator. + * @param iDenominator the denominator. + */ + void SetTimeSignatureDenominatorAtRow( int iNoteRow, int iDenominator ); + /** + * @brief Set the beat to have the new Time Signature denominator. + * @param fBeat the beat to have the new Time Signature denominator. + * @param iDenominator the denominator. + */ + void SetTimeSignatureDenominatorAtBeat( float fBeat, int iDenominator ) { SetTimeSignatureDenominatorAtRow( BeatToNoteRow(fBeat), iDenominator); } + /** + * @brief Retrieve the TimeSignatureSegment at the specified row. + * @param iNoteRow the row that has a TimeSignatureSegment. + * @return the TimeSignatureSegment in question. + */ + 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 ); + + /** + * @brief Determine the row to warp to. + * @param iWarpBeginRow The row you start on. + * @return the row you warp to. + */ + int GetWarpToRow( int iWarpBeginRow ) const; + /** + * @brief Add the WarpSegment to the TimingData. + * @param seg the new WarpSegment. + */ void AddWarpSegment( const WarpSegment &seg ); - int GetBPMSegmentIndexAtBeat( float fBeat ); - const TimeSignatureSegment& GetTimeSignatureSegmentAtBeat( float fBeat ) const; - BPMSegment& GetBPMSegmentAtBeat( float fBeat ); + + /** + * @brief Retrieve the Tickcount at the given row. + * @param iNoteRow the row in question. + * @return the Tickcount. + */ + int GetTickcountAtRow( int iNoteRow ) const; + /** + * @brief Retrieve the Tickcount at the given beat. + * @param fBeat the beat in question. + * @return the Tickcount. + */ + int GetTickcountAtBeat( float fBeat ) const { return GetTickcountAtRow( BeatToNoteRow(fBeat) ); } + /** + * @brief Set the row to have the new tickcount. + * @param iNoteRow the row to have the new tickcount. + * @param iTicks the tickcount. + */ + void SetTickcountAtRow( int iNoteRow, int iTicks ); + /** + * @brief Set the beat to have the new tickcount. + * @param fBeat the beat to have the new tickcount. + * @param iTicks the tickcount. + */ + void SetTickcountAtBeat( float fBeat, int iTicks ) { SetTickcountAtRow( BeatToNoteRow( fBeat ), iTicks ); } + /** + * @brief Retrieve the TickcountSegment at the specified row. + * @param iNoteRow the row that has a TickcountSegment. + * @return the TickcountSegment in question. + */ + 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 ); + + void MultiplyBPMInBeatRange( int iStartIndex, int iEndIndex, float fFactor ); + void NoteRowToMeasureAndBeat( int iNoteRow, int &iMeasureIndexOut, int &iBeatIndexOut, int &iRowsRemainder ) const; void GetBeatAndBPSFromElapsedTime( float fElapsedTime, float &fBeatOut, float &fBPSOut, bool &bFreezeOut, bool &bDelayOut, int &iWarpBeginOut, float &fWarpLengthOut ) const; @@ -153,11 +897,28 @@ public: return fBeat; } float GetElapsedTimeFromBeatNoOffset( float fBeat ) const; - + /** + * @brief View the TimingData to see if a song changes its BPM at any point. + * @return true if there is at least one change, false otherwise. + */ bool HasBpmChanges() const; + /** + * @brief View the TimingData to see if there is at least one stop at any point. + * + * For the purposes of this function, Stops and Delays are considered the same. + * @return true if there is at least one stop, false otherwise. + */ bool HasStops() const; + /** + * @brief View the TimingData to see if there is at least one warp at any point. + * @return true if there is at least one warp, false otherwise. + */ bool HasWarps() const; - + /** + * @brief Compare two sets of timing data to see if they are equal. + * @param other the other TimingData. + * @return the equality or lack thereof of the two TimingData. + */ bool operator==( const TimingData &other ) { COMPARE( m_BPMSegments.size() ); @@ -169,9 +930,20 @@ public: COMPARE( m_WarpSegments.size() ); for( unsigned i=0; i m_BPMSegments; // this must be sorted before gameplay - vector m_StopSegments; // this must be sorted before gameplay - vector m_vTimeSignatureSegments; // this must be sorted before gameplay - vector m_WarpSegments; // this must be sorted before gameplay + /** + * @brief The file of the song/steps that use this TimingData. + * + * This is for informational purposes only. + */ + RString m_sFile; + // All of the following vectors must be sorted before gameplay. + /** + * @brief The collection of BPMSegments. + */ + vector 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 initial offset of a song. + */ float m_fBeat0OffsetInSeconds; - bool m_bHasNegativeBpms; // only used for Lua bindings in Song (to be moved to TimingData later) + /** + * @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; }; #undef COMPARE #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2004 + * + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/WheelNotifyIcon.cpp b/src/WheelNotifyIcon.cpp index 73b8cde395..ee1c0047f4 100644 --- a/src/WheelNotifyIcon.cpp +++ b/src/WheelNotifyIcon.cpp @@ -13,6 +13,7 @@ */ static ThemeMetric SHOW_TRAINING ("WheelNotifyIcon","ShowTraining"); +static ThemeMetric BLINK_BEST_ICON ("WheelNotifyIcon","BlinkPlayersBest"); WheelNotifyIcon::WheelNotifyIcon() { @@ -49,15 +50,16 @@ void WheelNotifyIcon::SetFlags( Flags flags ) m_vIconsToShow.push_back( training ); - // HACK: Make players best blink if it's the only icon - // TODO: metric this. use m_bPlayersBestHack as variable name, lol -aj - if( m_vIconsToShow.size() == 1 ) + // If BLINK_BEST_ICON, make player's best icon blink if it's the only icon. + if( m_vIconsToShow.size() == 1 && BLINK_BEST_ICON ) { if( m_vIconsToShow[0] >= best1 && m_vIconsToShow[0] <= best3 ) m_vIconsToShow.push_back( empty ); } - m_vIconsToShow.resize( min(m_vIconsToShow.size(),2u) ); // crop to most important 2 + // crop to most important 2 + // todo: Let themer handle this? -aj + m_vIconsToShow.resize( min(m_vIconsToShow.size(),2u) ); // Broadcast Set message so items can react. (futures) -aj //Message msg("Set"); diff --git a/src/XmlFileUtil.cpp b/src/XmlFileUtil.cpp index aa5df58738..0fb328f9d5 100644 --- a/src/XmlFileUtil.cpp +++ b/src/XmlFileUtil.cpp @@ -25,7 +25,6 @@ bool XmlFileUtil::LoadFromFileShowErrors( XNode &xml, RageFileBasic &f ) return false; } - bool XmlFileUtil::LoadFromFileShowErrors( XNode &xml, const RString &sFile ) { RageFile f; @@ -48,7 +47,7 @@ bool XmlFileUtil::LoadFromFileShowErrors( XNode &xml, const RString &sFile ) static const char chXMLTagOpen = '<'; static const char chXMLTagClose = '>'; static const char chXMLQuestion = '?'; // used in checking for meta tags: "" -static const char chXMLTagPre = '/'; +static const char chXMLTagPre = '/'; static const char chXMLExclamation = '!'; static const char chXMLDash = '-'; @@ -82,7 +81,6 @@ static void InitEntities() } } - // skip spaces static void tcsskip( const RString &s, RString::size_type &i ) { @@ -107,7 +105,6 @@ static void SetString( const RString &s, int iStart, int iEnd, RString* ps, bool ps->assign( s, iStart, len ); } - // attr1="value1" attr2='value2' attr3=value3 /> // ^- return pointer // Desc : loading attribute plain xml text @@ -138,16 +135,16 @@ RString::size_type LoadAttributes( XNode *pNode, const RString &xml, RString &sE sErrorOut = ssprintf( "<%s> attribute has error ", pNode->GetName().c_str() ); return string::npos; } - + // XML Attr Name RString sName; SetString( xml, iOffset, iEnd, &sName ); - + // add new attribute DEBUG_ASSERT( sName.size() ); XNodeValue *pAttr = pNode->AppendAttr( sName ); iOffset = iEnd; - + // XML Attr Value tcsskip( xml, iOffset ); @@ -170,7 +167,7 @@ RString::size_type LoadAttributes( XNode *pNode, const RString &xml, RString &sE else { // XXX: This is invalid XML, should we be accepting it? -- Steve - //attr= value> + //attr= value> // none quote mode iEnd = xml.find_first_of( " >", iOffset ); } @@ -220,12 +217,12 @@ RString::size_type LoadInternal( XNode *pNode, const RString &xml, RString &sErr if( xml[iOffset+1] == chXMLTagPre ) return iOffset; - /* ", iOffset ); if( iEnd == string::npos ) { @@ -301,7 +298,7 @@ RString::size_type LoadInternal( XNode *pNode, const RString &xml, RString &sErr // error cos not exist CloseTag return string::npos; } - + RString sValue; SetString( xml, iOffset, iEnd, &sValue, true ); @@ -315,7 +312,7 @@ RString::size_type LoadInternal( XNode *pNode, const RString &xml, RString &sErr while( iOffset < xml.size() ) { XNode *node = new XNode; - + iOffset = LoadInternal( node, xml, sErrorOut, iOffset ); if( iOffset == string::npos ) { @@ -340,7 +337,7 @@ RString::size_type LoadInternal( XNode *pNode, const RString &xml, RString &sErr { // iOffset += 2; // C - + tcsskip( xml, iOffset ); if( iOffset >= xml.size() ) continue; @@ -384,7 +381,7 @@ RString::size_type LoadInternal( XNode *pNode, const RString &xml, RString &sErr sErrorOut = ssprintf( "it must be closed with ", pNode->GetName().c_str() ); return string::npos; } - + RString sValue; SetString( xml, iOffset, iEnd, &sValue, true ); @@ -434,14 +431,14 @@ bool GetXMLInternal( const XNode *pNode, RageFileBasic &f, bool bWriteTabs, int { // and get child WRITE( ">" ); - + if( !pNode->m_childs.empty() ) iTabBase++; FOREACH_CONST_Child( pNode, p ) if( !GetXMLInternal( p, f, bWriteTabs, iTabBase ) ) return false; - + // Text Value const XNodeValue *pText = pNode->GetAttr( XNode::TEXT_ATTRIBUTE ); if( pText != NULL ) @@ -587,7 +584,7 @@ namespace } else if( sExpression.size() > 0 && sExpression[0] == '@' ) { - /* This is a raw string. */ + // This is a raw string. sExpression.erase( 0, 1 ); LuaHelpers::Push( L, sExpression ); } @@ -632,7 +629,7 @@ namespace { XNode *pNode = new XNode( sName ); - /* Set the value of the node to the table. */ + // Set the value of the node to the table. { XNodeLuaValue *pValue = new XNodeLuaValue; lua_pushvalue( L, -1 ); @@ -640,12 +637,12 @@ namespace pNode->AppendAttrFrom( XNode::TEXT_ATTRIBUTE, pValue ); } - /* Iterate over the table, pulling out attributes and tables to process. */ + // Iterate over the table, pulling out attributes and tables to process. vector NodeNamesToAdd; vector NodesToAdd; - /* Add array elements first, in array order, so iterating over the XNode keeps the - * array in order. */ + /* Add array elements first, in array order, so iterating over the XNode + * keeps the array in order. */ FOREACH_LUATABLEI( L, -1, i ) { if( !lua_istable(L, -1) ) @@ -658,13 +655,13 @@ namespace int iLen = NodeNamesToAdd.size(); FOREACH_LUATABLE( L, -1 ) { - /* If this entry is a table, add it recursively. */ + // If this entry is a table, add it recursively. if( lua_istable(L, -2) ) { if( lua_isnumber(L, -1) ) { - /* If this number is an integer, and between [1,iLen], then we added - * this one already above. */ + /* If this number is an integer, and between [1,iLen], then + * we added this one already above. */ lua_Number f = lua_tonumber( L, -1 ); int i; lua_number2int(i, f); @@ -683,20 +680,20 @@ namespace RString sName; LuaHelpers::Pop( L, sName ); - /* Otherwise, add an attribute. */ + // Otherwise, add an attribute. XNodeLuaValue *pValue = new XNodeLuaValue; pValue->SetValueFromStack( L ); pNode->AppendAttrFrom( sName, pValue ); } lua_pop( L, 1 ); - /* Recursively process tables. */ + // Recursively process tables. for( size_t i = 0; i < NodesToAdd.size(); ++i ) { const RString &sNodeName = NodeNamesToAdd[i]; LuaReference &NodeToAdd = NodesToAdd[i]; - /* Check if the table is on the stack. */ + // Check if the table is on the stack. ProcessedTables.PushSelf( L ); NodeToAdd.PushSelf( L ); // push table lua_gettable( L, -2 ); @@ -706,7 +703,7 @@ namespace if( bSawThisTableAlready ) continue; - /* Add the table to the stack. */ + // Add the table to the stack. ProcessedTables.PushSelf( L ); NodeToAdd.PushSelf( L ); lua_pushboolean( L, true ); @@ -718,7 +715,7 @@ namespace if( pNewNode ) pNode->AppendChild( pNewNode ); - /* Remove the table from the stack. */ + // Remove the table from the stack. ProcessedTables.PushSelf( L ); NodeToAdd.PushSelf( L ); lua_pushnil( L ); @@ -731,19 +728,18 @@ namespace } -/* - * Pop a table off of the stack, and return an XNode tree referring recursively +/* Pop a table off of the stack, and return an XNode tree referring recursively * to entries in the table. * * The table may not contain table cycles; if a cycle is detected, only the first * table seen will have a corresponding XNode. * - * Users of the resulting XNode may access the original table via PushValue. - */ + * Users of the resulting XNode may access the original table via PushValue. */ XNode *XmlFileUtil::XNodeFromTable( lua_State *L ) { - /* Maintain a set of references that we've created. Tables may loop; XNode trees may - * not. If we encounter a cycle, skip creating an XNode for that node. */ + /* Maintain a set of references that we've created. Tables may loop; XNode + * trees may not. If we encounter a cycle, skip creating an XNode for + * that node. */ LuaReference ProcessedTables; lua_newtable( L ); ProcessedTables.SetFromStack( L ); @@ -751,7 +747,7 @@ XNode *XmlFileUtil::XNodeFromTable( lua_State *L ) return XNodeFromTableRecursive( L, "Layer", ProcessedTables ); } -/* Move nodes from pFrom into pTo which don't already exist in pTo. For +/* Move nodes from pFrom into pTo which don't already exist in pTo. For * efficiency, nodes will be moved, not copied, so pFrom will be modified. * On return, the contents of pFrom will be undefined and should be deleted. */ void XmlFileUtil::MergeIniUnder( XNode *pFrom, XNode *pTo ) @@ -760,14 +756,14 @@ void XmlFileUtil::MergeIniUnder( XNode *pFrom, XNode *pTo ) * with the possibility of duplicate child names. */ vector aToMove; - /* Iterate over each section in pFrom. */ + // Iterate over each section in pFrom. XNodes::iterator it = pFrom->m_childs.begin(); while( it != pFrom->m_childs.end() ) { XNodes::iterator next = it; ++next; - /* If this node doesn't exist in pTo, just move the whole node. */ + // If this node doesn't exist in pTo, just move the whole node. XNode *pSectionNode = *it; XNode *pChildNode = pTo->GetChild( pSectionNode->GetName() ); if( pChildNode == NULL ) @@ -778,7 +774,7 @@ void XmlFileUtil::MergeIniUnder( XNode *pFrom, XNode *pTo ) { FOREACH_Attr( pSectionNode, it2 ) { - /* Don't overwrite existing nodes. */ + // Don't overwrite existing nodes. pChildNode->AppendAttrFrom( it2->first, it2->second->Copy(), false ); } } diff --git a/src/arch/ArchHooks/ArchHooks_Win32.cpp b/src/arch/ArchHooks/ArchHooks_Win32.cpp index a036ef764d..05d67feacf 100644 --- a/src/arch/ArchHooks/ArchHooks_Win32.cpp +++ b/src/arch/ArchHooks/ArchHooks_Win32.cpp @@ -19,7 +19,7 @@ static bool g_bIsMultipleInstance = false; void InvalidParameterHandler( const wchar_t *szExpression, const wchar_t *szFunction, const wchar_t *szFile, unsigned int iLine, uintptr_t pReserved ) { - FAIL_M( "Invalid parameter" ); + FAIL_M( "Invalid parameter" ); //TODO: Make this more informative } #endif diff --git a/src/arch/Dialog/Dialog.cpp b/src/arch/Dialog/Dialog.cpp index 59c77c6184..66f6acfe11 100644 --- a/src/arch/Dialog/Dialog.cpp +++ b/src/arch/Dialog/Dialog.cpp @@ -30,7 +30,7 @@ DialogDriver *MakeDialogDriver() sDriver = asDriversToTry[i]; #ifdef USE_DIALOG_DRIVER_COCOA - if( !asDriversToTry[i].CompareNoCase("Cocoa") ) pRet = new DialogDriver_Cocoa; + if( !asDriversToTry[i].CompareNoCase("Cocoa") ) pRet = new DialogDriver_MacOSX; #endif #ifdef USE_DIALOG_DRIVER_WIN32 if( !asDriversToTry[i].CompareNoCase("Win32") ) pRet = new DialogDriver_Win32; diff --git a/src/arch/Dialog/Selector_Dialog.h b/src/arch/Dialog/Selector_Dialog.h index baf647a9b5..f9b0b4086f 100644 --- a/src/arch/Dialog/Selector_Dialog.h +++ b/src/arch/Dialog/Selector_Dialog.h @@ -8,7 +8,7 @@ #include "DialogDriver_Win32.h" #elif defined(MACOSX) -#include "DialogDriver_Cocoa.h" +#include "DialogDriver_MacOSX.h" #endif #include "DialogDriver.h" // DialogDriver_Null is in here diff --git a/src/arch/InputHandler/InputHandler.cpp b/src/arch/InputHandler/InputHandler.cpp index f481e641b4..684f66b749 100644 --- a/src/arch/InputHandler/InputHandler.cpp +++ b/src/arch/InputHandler/InputHandler.cpp @@ -69,6 +69,8 @@ wchar_t InputHandler::DeviceButtonToChar( DeviceButton button, bool bUseCurrentK INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL)) || INPUTFILTER->IsBeingPressed(DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL)); + // todo: handle Caps Lock -freem + if( bHoldingShift && !bHoldingCtrl ) { MakeUpper( &c, 1 ); diff --git a/src/arch/InputHandler/InputHandler_DirectInput.cpp b/src/arch/InputHandler/InputHandler_DirectInput.cpp index 696351ed14..180191f123 100644 --- a/src/arch/InputHandler/InputHandler_DirectInput.cpp +++ b/src/arch/InputHandler/InputHandler_DirectInput.cpp @@ -18,7 +18,7 @@ REGISTER_INPUT_HANDLER_CLASS2( DirectInput, DInput ); static vector Devices; -/* Number of joysticks found: */ +// Number of joysticks found: static int g_iNumJoysticks; static BOOL CALLBACK EnumDevicesCallback( const DIDEVICEINSTANCE *pdidInstance, void *pContext ) @@ -37,12 +37,6 @@ static BOOL CALLBACK EnumDevicesCallback( const DIDEVICEINSTANCE *pdidInstance, switch( device.type ) { - /* - case device.MOUSE: - device.dev = DEVICE_MOUSE; - break; - */ - case device.JOYSTICK: if( g_iNumJoysticks == NUM_JOYSTICKS ) return DIENUM_CONTINUE; @@ -54,6 +48,12 @@ static BOOL CALLBACK EnumDevicesCallback( const DIDEVICEINSTANCE *pdidInstance, case device.KEYBOARD: device.dev = DEVICE_KEYBOARD; break; + + /* + case device.MOUSE: + device.dev = DEVICE_MOUSE; + break; + */ } Devices.push_back(device); @@ -120,8 +120,8 @@ InputHandler_DInput::InputHandler_DInput() if( hr != DI_OK ) RageException::Throw( hr_ssprintf(hr, "InputHandler_DInput: IDirectInput::EnumDevices") ); + // mouse /* - mouse LOG->Trace( "InputHandler_DInput: IDirectInput::EnumDevices(DIDEVTYPE_MOUSE)" ); hr = g_dinput->EnumDevices( DIDEVTYPE_MOUSE, EnumDevicesCallback, NULL, DIEDFL_ATTACHEDONLY ); if( hr != DI_OK ) @@ -237,14 +237,14 @@ static int TranslatePOV(DWORD value) if( LOWORD(value) == 0xFFFF ) return 0; - /* Round the value up: */ + // Round the value up: value += 4500 / 2; value %= 36000; value /= 4500; if( value >= 8 ) - return 0; /* shouldn't happen */ - + return 0; // shouldn't happen + return HAT_VALS[value]; } @@ -303,7 +303,7 @@ void InputHandler_DInput::UpdatePolled( DIDevice &device, const RageTimer &tm ) if( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) return; - /* Set each known axis, button and POV. */ + // Set each known axis, button and POV. for( unsigned i = 0; i < device.Inputs.size(); ++i ) { const input_t &in = device.Inputs[i]; @@ -382,6 +382,27 @@ void InputHandler_DInput::UpdatePolled( DIDevice &device, const RageTimer &tm ) break; /* case device.MOUSE: + DIMOUSESTATE state; + + HRESULT hr = GetDeviceState(device.Device, sizeof(state), &state); + if( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) + return; + + // do button checks here + for( unsigned i = 0; i < device.Inputs.size(); ++i ) + { + const input_t &in = device.Inputs[i]; + const InputDevice dev = device.dev; + + switch(in.type) + { + case in.BUTTON: + DeviceInput di( dev, enum_add2(MOUSE_LEFT, in.num), !!state.rgbButtons[in.ofs - DIMOFS_BUTTON0], tm ); + ButtonPressed( di ); + break; + } + } + break; */ } @@ -413,6 +434,7 @@ void InputHandler_DInput::UpdateBuffered( DIDevice &device, const RageTimer &tm return; } + // todo: update for mouse? -aj for( int i = 0; i < (int) numevents; ++i ) { for(unsigned j = 0; j < device.Inputs.size(); ++j) @@ -426,38 +448,33 @@ void InputHandler_DInput::UpdateBuffered( DIDevice &device, const RageTimer &tm switch( in.type ) { case in.KEY: - /* - switch( in.num ) - { - // "Joystick with Keyboard" hack - case 115: //s - ButtonPressed( DeviceInput(DEVICE_JOY1, JOY_UP, !!(evtbuf[i].dwData & 0x80), tm) ); - break; - case 120: //x - ButtonPressed( DeviceInput(DEVICE_JOY1, JOY_DOWN, !!(evtbuf[i].dwData & 0x80), tm) ); - break; - case 122: //z - ButtonPressed( DeviceInput(DEVICE_JOY1, JOY_LEFT, !!(evtbuf[i].dwData & 0x80), tm) ); - break; - case 99: //c - ButtonPressed( DeviceInput(DEVICE_JOY1, JOY_RIGHT, !!(evtbuf[i].dwData & 0x80), tm) ); - break; - case 100: //d - ButtonPressed( DeviceInput(DEVICE_JOY1, JOY_BUTTON_1, !!(evtbuf[i].dwData & 0x80), tm) ); - break; - case 101: //e - ButtonPressed( DeviceInput(DEVICE_JOY1, JOY_BUTTON_2, !!(evtbuf[i].dwData & 0x80), tm) ); - break; - default: - */ - ButtonPressed( DeviceInput(dev, (DeviceButton) in.num, !!(evtbuf[i].dwData & 0x80), tm) ); - /* - break; - } - */ + ButtonPressed( DeviceInput(dev, (DeviceButton) in.num, !!(evtbuf[i].dwData & 0x80), tm) ); break; case in.BUTTON: + /* + if(dev == DEVICE_MOUSE) + { + DeviceButton mouseInput = DeviceButton_Invalid; + switch(in.ofs) + { + case DIMOFS_BUTTON0: mouseInput = MOUSE_LEFT; break; + case DIMOFS_BUTTON1: mouseInput = MOUSE_RIGHT; break; + case DIMOFS_BUTTON2: mouseInput = MOUSE_MIDDLE; break; + case DIMOFS_BUTTON3: break; + // todo: handle directions + case DIMOFS_X: break; + case DIMOFS_Y: break; + case DIMOFS_Z: break; + default: LOG->MapLog( "unknown input", + "Mouse '%s' is returning an unknown mouse offset, %i", + device.m_sName.c_str(), in.ofs ); + continue; + } + ButtonPressed( DeviceInput(dev, mouseInput, !!evtbuf[i].dwData, tm) ); + } + else + */ ButtonPressed( DeviceInput(dev, enum_add2(JOY_BUTTON_1, in.num), !!evtbuf[i].dwData, tm) ); break; @@ -524,7 +541,7 @@ void InputHandler_DInput::PollAndAcquireDevices( bool bBuffered ) void InputHandler_DInput::Update() { - /* Handle polled devices. Handle buffered, too, if there's no input thread to do it. */ + // Handle polled devices. Handle buffered, too, if there's no input thread to do it. PollAndAcquireDevices( false ); if( !m_InputThread.IsCreated() ) PollAndAcquireDevices( true ); @@ -683,7 +700,6 @@ static wchar_t ScancodeAndKeysToChar( DWORD scancode, unsigned char keys[256] ) pToUnicodeEx = (TOUNICODEEX *) GetProcAddress( hModule, "ToUnicodeEx" ); } - unsigned short result[2]; // ToAscii writes a max of 2 chars ZERO( result ); @@ -733,6 +749,7 @@ wchar_t InputHandler_DInput::DeviceButtonToChar( DeviceButton button, bool bUseC ZERO( keys ); if( bUseCurrentKeyModifiers ) GetKeyboardState(keys); + // todo: handle Caps Lock -freem wchar_t c = ScancodeAndKeysToChar( i->ofs, keys ); if( c ) return c; diff --git a/src/arch/InputHandler/InputHandler_DirectInputHelper.cpp b/src/arch/InputHandler/InputHandler_DirectInputHelper.cpp index b11733a6fc..939ad6cc24 100644 --- a/src/arch/InputHandler/InputHandler_DirectInputHelper.cpp +++ b/src/arch/InputHandler/InputHandler_DirectInputHelper.cpp @@ -16,6 +16,7 @@ LPDIRECTINPUT g_dinput = NULL; static int ConvertScancodeToKey( int scancode ); static BOOL CALLBACK DIJoystick_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data); +static BOOL CALLBACK DIMouse_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data); DIDevice::DIDevice() { @@ -23,6 +24,7 @@ DIDevice::DIDevice() dev = InputDevice_Invalid; buffered = true; memset(&JoystickInst, 0, sizeof(JoystickInst)); + //memset(&MouseInst, 0, sizeof(MouseInst)); Device = NULL; } @@ -34,13 +36,14 @@ bool DIDevice::Open() buffered = true; LPDIRECTINPUTDEVICE tmpdevice; + + // load joystick HRESULT hr = g_dinput->CreateDevice( JoystickInst.guidInstance, &tmpdevice, NULL ); if ( hr != DI_OK ) { LOG->Info( hr_ssprintf(hr, "OpenDevice: IDirectInput_CreateDevice") ); return false; } - hr = tmpdevice->QueryInterface( IID_IDirectInputDevice2, (LPVOID *) &Device ); tmpdevice->Release(); if ( hr != DI_OK ) @@ -49,6 +52,27 @@ bool DIDevice::Open() return false; } + // load mouse + /* + hr = g_dinput->CreateDevice( MouseInst.guidInstance, &tmpdevice, NULL ); + if ( hr != DI_OK ) + { + LOG->Info( hr_ssprintf(hr, "OpenDevice: IDirectInput_CreateDevice") ); + return false; + } + */ + // is this ok? -aj + //hr = tmpdevice->QueryInterface( IID_IDirectInputDevice2, (LPVOID *) &Device ); + /* + tmpdevice->Release(); + if ( hr != DI_OK ) + { + LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice::QueryInterface", m_sName.c_str()) ); + return false; + } + */ + + // should mouse be foreground? -aj int coop = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; if( type == KEYBOARD ) coop = DISCL_NONEXCLUSIVE | DISCL_FOREGROUND; @@ -60,7 +84,20 @@ bool DIDevice::Open() return false; } - hr = Device->SetDataFormat( type == JOYSTICK? &c_dfDIJoystick: &c_dfDIKeyboard ); + switch(type) + { + case KEYBOARD: + hr = Device->SetDataFormat( &c_dfDIKeyboard ); + break; + case JOYSTICK: + hr = Device->SetDataFormat( &c_dfDIJoystick ); + break; + /* + case MOUSE: + hr = Device->SetDataFormat( &c_dfDIMouse ); + break; + */ + } if ( hr != DI_OK ) { LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2::SetDataFormat", m_sName.c_str()) ); @@ -69,26 +106,27 @@ bool DIDevice::Open() switch( type ) { - case JOYSTICK: - Device->EnumObjects( DIJoystick_EnumDevObjectsProc, this, DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV); - break; - case KEYBOARD: - /* Always 256-button. */ - for( int b = 0; b < 256; ++b ) - { - input_t in; - in.type = in.KEY; + case JOYSTICK: + Device->EnumObjects( DIJoystick_EnumDevObjectsProc, this, DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV); + break; + case KEYBOARD: + // Always 256-button. + for( int b = 0; b < 256; ++b ) + { + input_t in; + in.type = in.KEY; - in.num = ConvertScancodeToKey(b); - in.ofs = b; - buttons++; - Inputs.push_back(in); - } - break; - /* - case MOUSE: - break; - */ + in.num = ConvertScancodeToKey(b); + in.ofs = b; + buttons++; + Inputs.push_back(in); + } + break; + /* + case MOUSE: + Device->EnumObjects( DIMouse_EnumDevObjectsProc, this, DIDFT_BUTTON | DIDFT_PSHBUTTON ); + break; + */ } { @@ -137,7 +175,7 @@ static BOOL CALLBACK DIJoystick_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev input_t in; const int SupportedMask = DIDFT_BUTTON | DIDFT_POV | DIDFT_AXIS; if(!(dev->dwType & SupportedMask)) - return DIENUM_CONTINUE; // unsupported + return DIENUM_CONTINUE; // unsupported in.ofs = dev->dwOfs; @@ -307,8 +345,32 @@ static int ConvertScancodeToKey( int scancode ) }; } +static BOOL CALLBACK DIMouse_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data) +{ + /* + DIDevice *device = (DIDevice *) data; + + input_t in; + // todo: check mask for accuracy -aj + const int SupportedMask = DIDFT_BUTTON | DIDFT_PSHBUTTON; + if(!(dev->dwType & SupportedMask)) + return DIENUM_CONTINUE; // unsupported + + // xxx: does this check for scrollwheels? -aj + if(dev->dwType & (DIDFT_BUTTON | DIDFT_PSHBUTTON) ) { + in.type = in.BUTTON; + in.num = device->buttons; + device->buttons++; + } + + device->Inputs.push_back(in); + */ + + return DIENUM_CONTINUE; +} + /* - * (c) 2003-2004 Glenn Maynard + * (c) 2003-2011 Glenn Maynard, AJ Kelly * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/arch/InputHandler/InputHandler_DirectInputHelper.h b/src/arch/InputHandler/InputHandler_DirectInputHelper.h index f14b3e82b6..8519a2dbf2 100644 --- a/src/arch/InputHandler/InputHandler_DirectInputHelper.h +++ b/src/arch/InputHandler/InputHandler_DirectInputHelper.h @@ -11,10 +11,10 @@ extern LPDIRECTINPUT g_dinput; typedef struct input_t { - /* DirectInput offset for this input type: */ + // DirectInput offset for this input type: DWORD ofs; - /* Button, axis or hat: */ + // Button, axis or hat: enum Type { KEY, BUTTON, AXIS, HAT } type; int num; @@ -23,11 +23,12 @@ typedef struct input_t struct DIDevice { DIDEVICEINSTANCE JoystickInst; + DIDEVICEINSTANCE MouseInst; LPDIRECTINPUTDEVICE2 Device; RString m_sName; - enum { KEYBOARD, JOYSTICK } type; - //enum { KEYBOARD, JOYSTICK, MOUSE } type; + //enum { KEYBOARD, JOYSTICK } type; + enum { KEYBOARD, JOYSTICK, MOUSE } type; bool buffered; int buttons, axes, hats; diff --git a/src/arch/InputHandler/InputHandler_Linux_Joystick.cpp b/src/arch/InputHandler/InputHandler_Linux_Joystick.cpp index 0826f27ffe..2fc7392d0c 100644 --- a/src/arch/InputHandler/InputHandler_Linux_Joystick.cpp +++ b/src/arch/InputHandler/InputHandler_Linux_Joystick.cpp @@ -36,13 +36,13 @@ InputHandler_Linux_Joystick::InputHandler_Linux_Joystick() LOG->Trace( "InputHandler_Linux_Joystick disabled (joystick driver already loaded)" ); return; } - + /* We check both eg. /dev/js0 and /dev/input/js0. If both exist, they're probably * the same device; keep track of device IDs so we don't open the same joystick * twice. */ set< pair > devices; bool bFoundAnyJoysticks = false; - + for(int i = 0; i < NUM_JOYSTICKS; ++i) { struct stat st; @@ -89,7 +89,7 @@ InputHandler_Linux_Joystick::InputHandler_Linux_Joystick() InputHandler_Linux_Event::m_bFoundAnyJoysticks = true; } } - + InputHandler_Linux_Joystick::~InputHandler_Linux_Joystick() { if( m_InputThread.IsCreated() ) @@ -117,7 +117,7 @@ void InputHandler_Linux_Joystick::InputThread() fd_set fdset; FD_ZERO(&fdset); int max_fd = -1; - + for(int i = 0; i < NUM_JOYSTICKS; ++i) { if (fds[i] < 0) @@ -166,7 +166,7 @@ void InputHandler_Linux_Joystick::InputThread() ButtonPressed( DeviceInput(id, enum_add2(JOY_BUTTON_1, iNum), event.value, now) ); break; } - + case JS_EVENT_AXIS: { DeviceButton neg = enum_add2(JOY_LEFT, 2*event.number); DeviceButton pos = enum_add2(JOY_RIGHT, 2*event.number); @@ -175,7 +175,7 @@ void InputHandler_Linux_Joystick::InputThread() ButtonPressed( DeviceInput(id, pos, max(+l,0), now) ); break; } - + default: LOG->Warn("Unexpected packet (type %i) from joystick %i; disabled", event.type, i); close(fds[i]); diff --git a/src/arch/InputHandler/InputHandler_MacOSX_HID.cpp b/src/arch/InputHandler/InputHandler_MacOSX_HID.cpp index 840391fac6..163a688766 100644 --- a/src/arch/InputHandler/InputHandler_MacOSX_HID.cpp +++ b/src/arch/InputHandler/InputHandler_MacOSX_HID.cpp @@ -26,7 +26,7 @@ void InputHandler_MacOSX_HID::QueueCallback( void *target, int result, void *ref AbsoluteTime zeroTime = { 0, 0 }; HIDDevice *dev = This->m_vDevices[int( refcon )]; vector vPresses; - + while( (result = CALL(queue, getNextEvent, &event, zeroTime, 0)) == kIOReturnSuccess ) { if( event.longValueSize != 0 && event.longValue != NULL ) @@ -51,10 +51,10 @@ static void RunLoopStarted( CFRunLoopObserverRef o, CFRunLoopActivity a, void *s int InputHandler_MacOSX_HID::Run( void *data ) { InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)data; - + This->m_LoopRef = CFRunLoopGetCurrent(); CFRetain( This->m_LoopRef ); - + This->StartDevices(); { const RString sError = SetThreadPrecedence( 1.0f ); @@ -70,7 +70,7 @@ int InputHandler_MacOSX_HID::Run( void *data ) false, 0, RunLoopStarted, &context); CFRunLoopAddObserver( This->m_LoopRef, o, kCFRunLoopDefaultMode ); } - + /* Add a source for ending the run loop. This serves two purposes: * 1. it provides a way to terminate the run loop when IH_MacOSX_HID exists, and * 2. it ensures that CFRunLoopRun() doesn't return immediately if there are no other sources. */ @@ -81,10 +81,10 @@ int InputHandler_MacOSX_HID::Run( void *data ) void (*perform)(void *) = (void (*)(void *))CFRunLoopStop; // { version, info, retain, release, copyDescription, equal, hash, schedule, cancel, perform } CFRunLoopSourceContext context = { 0, info, NULL, NULL, NULL, NULL, NULL, NULL, NULL, perform }; - + // Pass 1 so that it is called after all inputs have been handled (they will have order = 0) This->m_SourceRef = CFRunLoopSourceCreate( kCFAllocatorDefault, 1, &context ); - + CFRunLoopAddSource( This->m_LoopRef, This->m_SourceRef, kCFRunLoopDefaultMode ); } CFRunLoopRun(); @@ -95,7 +95,7 @@ int InputHandler_MacOSX_HID::Run( void *data ) void InputHandler_MacOSX_HID::DeviceAdded( void *refCon, io_iterator_t ) { InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)refCon; - + LockMut( This->m_ChangeLock ); This->m_bChanged = true; } @@ -105,7 +105,7 @@ void InputHandler_MacOSX_HID::DeviceChanged( void *refCon, io_service_t service, if( messageType == kIOMessageServiceIsTerminated ) { InputHandler_MacOSX_HID *This = (InputHandler_MacOSX_HID *)refCon; - + LockMut( This->m_ChangeLock ); This->m_bChanged = true; } @@ -115,13 +115,13 @@ void InputHandler_MacOSX_HID::DeviceChanged( void *refCon, io_service_t service, void InputHandler_MacOSX_HID::StartDevices() { int n = 0; - + ASSERT( m_LoopRef ); FOREACH( HIDDevice *, m_vDevices, i ) (*i)->StartQueue( m_LoopRef, InputHandler_MacOSX_HID::QueueCallback, this, n++ ); - + CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource( m_NotifyPort ); - + CFRunLoopAddSource( m_LoopRef, runLoopSource, kCFRunLoopDefaultMode ); } @@ -138,7 +138,7 @@ InputHandler_MacOSX_HID::~InputHandler_MacOSX_HID() CFRelease( m_LoopRef ); LOG->Trace( "Input handler thread shut down." ); } - + FOREACH( io_iterator_t, m_vIters, i ) IOObjectRelease( *i ); IONotificationPortDestroy( m_NotifyPort ); @@ -148,20 +148,20 @@ static CFDictionaryRef GetMatchingDictionary( int usagePage, int usage ) { // Build the matching dictionary. CFMutableDictionaryRef dict; - + if( (dict = IOServiceMatching(kIOHIDDeviceKey)) == NULL ) FAIL_M( "Couldn't create a matching dictionary." ); // Refine the search by only looking for joysticks CFNumberRef usagePageRef = CFInt( usagePage ); CFNumberRef usageRef = CFInt( usage ); - + CFDictionarySetValue( dict, CFSTR(kIOHIDPrimaryUsagePageKey), usagePageRef ); CFDictionarySetValue( dict, CFSTR(kIOHIDPrimaryUsageKey), usageRef ); - + // Cleanup after ourselves CFRelease( usagePageRef ); CFRelease( usageRef ); - + return dict; } @@ -182,28 +182,28 @@ void InputHandler_MacOSX_HID::AddDevices( int usagePage, int usage, InputDevice io_iterator_t iter; CFDictionaryRef dict = GetMatchingDictionary( usagePage, usage ); kern_return_t ret = IOServiceAddMatchingNotification( m_NotifyPort, kIOFirstMatchNotification, dict, - InputHandler_MacOSX_HID::DeviceAdded, this, &iter ); + InputHandler_MacOSX_HID::DeviceAdded, this, &iter ); io_object_t device; if( ret != KERN_SUCCESS ) return; - + m_vIters.push_back( iter ); - + // Iterate over the devices and add them while( (device = IOIteratorNext(iter)) ) { LOG->Trace( "\tFound device %d", id ); HIDDevice *dev = MakeDevice( id ); int num; - + if( !dev ) { LOG->Trace( "\t\tInvalid id, deleting device" ); IOObjectRelease( device ); continue; } - + if( !dev->Open(device) || (num = dev->AssignIDs(id)) == -1 ) { LOG->Trace( "\tFailed top open or assign id, deleting device" ); @@ -212,13 +212,13 @@ void InputHandler_MacOSX_HID::AddDevices( int usagePage, int usage, InputDevice continue; } io_iterator_t i; - + enum_add( id, num ); m_vDevices.push_back( dev ); ret = IOServiceAddInterestNotification( m_NotifyPort, device, kIOGeneralInterest, InputHandler_MacOSX_HID::DeviceChanged, this, &i ); - + if( ret == KERN_SUCCESS ) m_vIters.push_back( i ); else @@ -233,7 +233,7 @@ InputHandler_MacOSX_HID::InputHandler_MacOSX_HID() : m_Sem( "Input thread starte // Set up the notify ports. m_NotifyPort = IONotificationPortCreate( kIOMasterPortDefault ); - + // Add devices. LOG->Trace( "Finding keyboards" ); AddDevices( kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard, id ); @@ -245,7 +245,7 @@ InputHandler_MacOSX_HID::InputHandler_MacOSX_HID() : m_Sem( "Input thread starte id = DEVICE_PUMP1; AddDevices( kHIDPage_VendorDefinedStart, 0x0001, id ); // Pump pads use the first vendor specific usage page. m_bChanged = false; - + if( PREFSMAN->m_bThreadedInput ) { m_InputThread.SetName( "Input thread" ); @@ -353,7 +353,7 @@ RString InputHandler_MacOSX_HID::GetDeviceSpecificInputString( const DeviceInput case JOY_BUTTON_11: return "P2 DR"; } } - + return InputHandler::GetDeviceSpecificInputString( di ); } @@ -383,7 +383,7 @@ wchar_t InputHandler_MacOSX_HID::DeviceButtonToChar( DeviceButton button, bool b case KEY_PGDN: case KEY_NUMLOCK: case KEY_KP_ENTER: - return L'\0'; + return L'\0'; } // Find the USB key code for this DeviceButton @@ -394,12 +394,14 @@ wchar_t InputHandler_MacOSX_HID::DeviceButtonToChar( DeviceButton button, bool b if( bUseCurrentKeyModifiers ) modifiers = GetCurrentKeyModifiers(); + // todo: handle Caps Lock -freem + SInt16 iCurrentKeyScript = GetScriptManagerVariable( smKeyScript ); SInt16 iCurrentKeyLayoutID = GetScriptVariable( iCurrentKeyScript, smScriptKeys ); static SInt16 iLastKeyLayoutID = !iCurrentKeyLayoutID; // Just be different. static UInt32 iDeadKeyState; static UCKeyboardLayout **KeyLayout; - + if( iCurrentKeyLayoutID != iLastKeyLayoutID ) { iDeadKeyState = 0; @@ -415,24 +417,24 @@ wchar_t InputHandler_MacOSX_HID::DeviceButtonToChar( DeviceButton button, bool b OSStatus status = UCKeyTranslate( *KeyLayout, iMacVirtualKey, kUCKeyActionDown, modifiers, keyboardType, 0, &iDeadKeyState, ARRAYLEN(unicodeInputString), &length, unicodeInputString ); - + if( status ) return L'\0'; - + CFStringRef inputString = CFStringCreateWithCharacters( NULL, unicodeInputString, length ); char utf8InputString[7]; // Max size is 6 (although really only 4 are used) + null. - + if( !CFStringGetCString(inputString, utf8InputString, 7, kCFStringEncodingUTF8) ) { CFRelease( inputString ); return L'\0'; } - + wchar_t ch = utf8_get_char( utf8InputString ); CFRelease( inputString ); return ch == INVALID_CHAR ? L'\0' : ch; - + } else { @@ -440,7 +442,7 @@ wchar_t InputHandler_MacOSX_HID::DeviceButtonToChar( DeviceButton button, bool b static unsigned long state = 0; static Ptr keymap = NULL; Ptr new_keymap; - + new_keymap = (Ptr)GetScriptManagerVariable(smKCHRCache); if( new_keymap != keymap ) { @@ -451,7 +453,7 @@ wchar_t InputHandler_MacOSX_HID::DeviceButtonToChar( DeviceButton button, bool b return KeyTranslate( keymap, UInt16(iMacVirtualKey)|modifiers, &state ) & 0xFF; } } - + return InputHandler::DeviceButtonToChar( button, bUseCurrentKeyModifiers ); } diff --git a/src/arch/InputHandler/InputHandler_MacOSX_HID.h b/src/arch/InputHandler/InputHandler_MacOSX_HID.h index 3e9b12a700..2a94027a1c 100644 --- a/src/arch/InputHandler/InputHandler_MacOSX_HID.h +++ b/src/arch/InputHandler/InputHandler_MacOSX_HID.h @@ -21,7 +21,7 @@ private: IONotificationPortRef m_NotifyPort; RageMutex m_ChangeLock; bool m_bChanged; - + static int Run( void *data ); static void DeviceAdded( void *refCon, io_iterator_t iter ); static void DeviceChanged( void *refCon, io_service_t service, natural_t messageType, void *arg ); @@ -37,7 +37,6 @@ public: RString GetDeviceSpecificInputString( const DeviceInput &di ); wchar_t DeviceButtonToChar( DeviceButton button, bool bUseCurrentKeyModifiers ); static void QueueCallback( void *target, int result, void *refcon, void *sender ); - }; #endif diff --git a/src/global.h b/src/global.h index eec5114432..a2bc4c8ce1 100644 --- a/src/global.h +++ b/src/global.h @@ -9,8 +9,10 @@ #pragma once #endif // _MSC_VER >= 1000 -#define __STDC_LIMIT_MACROS // for INT8_MIN, etc -#define __STDC_CONSTANT_MACROS // for INT64_C, etc +/** @brief This macro is for INT8_MIN, etc. */ +#define __STDC_LIMIT_MACROS +/** @brief This macro is for INT64_C, etc. */ +#define __STDC_CONSTANT_MACROS /* Platform-specific fixes. */ #if defined(WIN32) @@ -33,7 +35,9 @@ #elif defined(HAVE_MACHINE_ENDIAN_H) #include #else +/** @brief The macro for little endian order. */ #define LITTLE_ENDIAN 1234 +/** @brief The macro for big endian order. */ #define BIG_ENDIAN 4321 #if defined(ENDIAN_LITTLE) #define BYTE_ORDER LITTLE_ENDIAN @@ -78,7 +82,7 @@ using namespace std; #undef ASSERT #endif -/* RageThreads defines (don't pull in all of RageThreads.h here) */ +/** @brief RageThreads defines (don't pull in all of RageThreads.h here) */ namespace Checkpoints { void SetCheckpoint( const char *file, int line, const char *message ); @@ -87,10 +91,12 @@ namespace Checkpoints #define CHECKPOINT_M(m) (Checkpoints::SetCheckpoint(__FILE__, __LINE__, m)) -/* Define a macro to tell the compiler that a function doesn't return. This just - * improves compiler warnings. This should be placed near the beginning of the - * function prototype (although it looks better near the end, VC only accepts it - * at the beginning). */ +/** + * @brief Define a macro to tell the compiler that a function doesn't return. + * + * This just improves compiler warnings. This should be placed near the + * beginning of the function prototype (although it looks better near the end, + * VC only accepts it at the beginning). */ #if defined(_MSC_VER) #define NORETURN __declspec(noreturn) #elif defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)) @@ -111,7 +117,7 @@ void NORETURN sm_crash( const char *reason = "Internal error" ); #define ASSERT(COND) ASSERT_M((COND), "Assertion '" #COND "' failed") #endif -/* Use this to catch switching on invalid values */ +/** @brief Use this to catch switching on invalid values */ #define DEFAULT_FAIL(i) default: FAIL_M( ssprintf("%s = %i", #i, (i)) ) void ShowWarningOrTrace( const char *file, int line, const char *message, bool bWarning ); // don't pull in LOG here @@ -144,7 +150,7 @@ template struct CompileAssertDecl { }; #define COMPILE_ASSERT(COND) typedef CompileAssertDecl< sizeof(CompileAssert) > CompileAssertInst #if defined(__GNUC__) -/* Define a macro to tell the compiler that a function has printf() semantics, to aid warning output. */ +/** @brief Define a macro to tell the compiler that a function has printf() semantics, to aid warning output. */ #define PRINTF(a,b) __attribute__((format(__printf__,a,b))) #define CONST_FUNCTION __attribute__((const)) #else @@ -159,14 +165,16 @@ template struct CompileAssertDecl { }; #endif -/* Use CStdString: */ +/** @brief Use RStrings throughout the program. */ #include "StdString.h" typedef StdString::CStdString RString; #include "RageException.h" #if !defined(WIN32) +/** @brief Define stricmp to be strcasecmp. */ #define stricmp strcasecmp +/** @brief Define strnicmp to be strncasecmp. */ #define strnicmp strncasecmp #endif @@ -174,6 +182,7 @@ typedef StdString::CStdString RString; #include #ifndef M_PI +/** @brief Define Pi to many digits. */ #define M_PI 3.1415926535897932384626433832795 #endif @@ -225,8 +234,10 @@ inline float strtof( const char *s, char **se ) { return (float) strtod( s, se ) #endif -/* - * (c) 2001-2004 Chris Danford, Glenn Maynard +/** + * @file + * @author Chris Danford, Glenn Maynard (c) 2001-2004 + * @section LICENSE * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/src/smpackage/ZipArchive/_copy_from_Linux-STL.sh b/src/smpackage/ZipArchive/_copy_from_Linux-STL.sh deleted file mode 100644 index 947dbd50db..0000000000 --- a/src/smpackage/ZipArchive/_copy_from_Linux-STL.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -cp -f Linux/* ./ -cp -f stl/* ./ -rm -f __*.zcfg -echo Linux STL > __Linux_STL.zcfg