diff --git a/parser/src/header.rs b/parser/src/header.rs index 031697d..620c000 100644 --- a/parser/src/header.rs +++ b/parser/src/header.rs @@ -23,6 +23,8 @@ impl Default for Player { /// `#RANK [0-3]`. Defines the judge difficulty. /// /// We follow LR2 convention here, so Rank is 0,1,2,3 +#[derive(FromRepr, Debug, PartialEq, Clone)] +#[repr(u8)] pub enum Rank { VeryHard, // RANK 0, +-8ms Hard, // RANK 1, +- 15ms @@ -54,6 +56,10 @@ pub enum JudgeRankType { /// Exrank is also weird. It allows the timing window of the chart to be changed /// during play. /// + /// The string represents the identifier (In the example "cc" or "aa") + /// and the f32 represents the rank as a percentage of rank 2. + /// + /// # Example /// To steal from hitkey as an example. /// ``` /// #RANK 2 @@ -63,9 +69,6 @@ pub enum JudgeRankType { /// ``` /// Would result in the timing window for measure 114 changing to DEFEXRANK 48, /// and then going back to DEFEXRANK 100 at the end of the measure. - /// - /// The string represents the identifier (In the example "cc" or "aa") - /// and the f32 represents the rank as a percentage of rank 2. Exrank(String, f32), } @@ -246,8 +249,14 @@ impl Default for ConstantBPM { /// This operates on Channel #xxx08. /// /// This command allows the chart designer to describe BPM changes. -/// For example, /// +/// Negative BPMs are allowed, and in general are expected to make the chart scroll _backwards_. +/// +/// For more info, see https://hitkey.nekokan.dyndns.info/exbpm-object.htm +/// +/// In parsing, we expect to parse the identifier to the string, and the bpm to the float. +/// +/// # Example /// ``` /// #BPMAA 256 /// #BPMBB 155.5 @@ -256,12 +265,6 @@ impl Default for ConstantBPM { /// /// This defines the BPM AA to be 256, the BPM BB to be 155.5 and says where to use it /// in the chart itself. -/// -/// Negative BPMs are allowed, and in general are expected to make the chart scroll _backwards_. -/// -/// For more info, see https://hitkey.nekokan.dyndns.info/exbpm-object.htm -/// -/// In parsing, we expect to parse the identifier to the string, and the bpm to the float. pub struct ExBPM(String, f32); /// Represent the multiple types of BPM as enum variants. @@ -270,5 +273,123 @@ pub enum BPM { Extended(ExBPM), } -/// `#STOP[01-ZZ] n` +/// `#STOP[01-ZZ] n`, DDR Style stops! +/// +/// Operates on Channel #xxx09 +/// +/// A STOP sequence is an object which stops scrolling of the chart for a defined +/// period of time. +/// Once the time is elapsed, the chart will resume normal scrolling. +/// +/// We should treat a `#STOPxx 1` as defining a STOP for 1/192nd of a note in 4/4. +/// It's also important to note that we use the BPM _at time of stop_. +/// +/// Implementing this in game is a bit tricky, due to the #xxx02 command which adjusts +/// how long a measure is. +/// +/// Decimal stops have their fractional part dropped. +/// +/// A negative STOP duration is weirdly defined. For LR2 it applies "-1" and causes it +/// to skip some amount of notes. +/// Generally, it's ignored. +/// +/// # Example +/// +/// ``` +/// #STOP11 96 +/// #STOP22 96 +/// #00109:0011 +/// #00202:0.5 +/// #00209:0022 +/// ``` +/// +/// Reading BMS is awkward, so think about each line here being split like so +/// [AAA][BB]:[CC] +/// Where AAA is the measure, BB is the command we're executing on that measure +/// and CC is the "operand" to that command. +/// +/// Defines STOP 11 as having a length of 192nd note * 96, and so does STOP 22. +/// #00109:0011 says to do STOP 11 on measure 1 +/// #00209:0022 says to do STOP 22 on measure 2 +/// +/// An example of a 1 second stop +/// ``` +/// #BPM 60 // Set BPM to 60 +/// #STOP33 48 // 48 * 1/192 stop length +/// #00109:33 +/// ``` +/// +/// If a STOP and a note are on the same time, the note plays first then timing changes. +/// If a STOP and a BPM change are on the same time, then BPM changes then STOP is applied. +/// +/// For some more examples, please refer to +/// https://hitkey.bms.ms/cmds.htm#STOP pub struct Stop(String, u32); + +/// `#LNTYPE[0-3]`. Long Note type +/// +/// LNType is a field kept for backwards compatibility, as it's no longer needed +/// with the advent of LNOBJ. +/// +/// LnType 1 is what we hope we see. We should probably just parse error and +/// tell the user we're ignoring their chart if it's LNType 2 or 3. +/// +/// This is omissble. +pub struct LNType(u8); + +/// `#LNOBJ xx` +/// +/// This is RDM type LNs. They have sounds on keyup and they're annoying. +/// +/// TODO: Explain how this works better rather than handwaving it. +pub struct LNObj(u32); + +/// `#WAV[00-ZZ] filename` +/// +/// One of the most common commands! This defines the sound files that we actually +/// play! +/// +/// A single file is assignable to two or more indexes. This is used for polyphony. +/// +/// "Alternate search" is expected now. If we cant find example.wav we should search +/// for example.ogg, example.mp3 etc +/// +/// Certain channels are assigned, to certain things. +/// +/// - `#xxx01` is assigned to the BGM. +/// - `#xxx11-19` is assigned to P1 notes +/// - `#xxx21-29` is assigned to P2 notes +/// - `#xxx31-39` is assigned to P1 _invisible_ notes +/// - `#xxx41-49` is assigned to P2 _invisible_ notes +/// - `#xxx51-59` are assigned to P1 LNs. +/// - `#xxx61-69` are assigned to P2 LNs. +/// - `#xxxD1-D9` are assigned to P1 landmines. +/// - `#xxxE1-E9` are assigned to P2 landmines. +/// +/// For more info see https://hitkey.bms.ms/cmds.htm#WAVXX +/// as this is one of the most complex commands we encounter +pub struct Wav(u32, String); + +/// `#BMP[00-ZZ] filename` +/// +/// Image resources. And Also video! +/// +/// Interesringly, certain channels are assigned to certain images. +/// +/// - `#xxx04` is the base bga +/// - `#xxx06` is the POOR image +/// - `#xxx07` is the "BGA Layer" +/// - `#xxx0A` is the "BGA Layer 2" +/// +/// Videos can be used in any of these indexs. In general, we should expect video playback +/// to only be possible on #xxx04. +/// +/// When a video is being played, we should apply layers/miss animation etc overtop. +/// +/// If nothing is found in channel `#xxx04/06/07` we should display just a black image. +/// +/// We should support as many image formats as is reasonable. +/// PNG, JPG, GIF, TGA, DDS are all common. +/// +/// Like with #WAV we should support alternate search. So try PNG then JPEG then GIF etc. +pub struct Bmp(u32, String);