00001 #ifndef NOTE_TYPES_H 00002 #define NOTE_TYPES_H 00003 00004 #include "GameConstantsAndTypes.h" 00005 00006 struct TapNoteResult 00007 { 00008 TapNoteResult() 00009 { 00010 tns = TNS_NONE; 00011 fTapNoteOffset = 0; 00012 } 00013 TapNoteScore tns; 00014 00015 /* Offset, in seconds, for a tap grade. Negative numbers mean the note 00016 * was hit early; positive numbers mean it was hit late. These values are 00017 * only meaningful for graded taps (tns >= TNS_BOO). */ 00018 float fTapNoteOffset; 00019 00020 /* If the whole row has been judged, all taps on the row will be set to hidden. */ 00021 bool bHidden; 00022 }; 00023 00024 struct HoldNoteResult 00025 { 00026 HoldNoteScore hns; 00027 00028 /* 1.0 means this HoldNote has full life. 00029 * 0.0 means this HoldNote is dead 00030 * When this value hits 0.0 for the first time, m_HoldScore becomes HSS_NG. 00031 * If the life is > 0.0 when the HoldNote ends, then m_HoldScore becomes HSS_OK. */ 00032 float fLife; 00033 00034 /* Last index where fLife was greater than 0. If the tap was missed, this will 00035 * be the first index of the hold. */ 00036 int iLastHeldRow; 00037 00038 HoldNoteResult() 00039 { 00040 hns = HNS_NONE; 00041 fLife = 1.0f; 00042 iLastHeldRow = 0; 00043 bHeld = bActive = false; 00044 } 00045 00046 float GetLastHeldBeat() const; 00047 00048 bool bHeld; 00049 bool bActive; 00050 }; 00051 00052 00053 struct TapNote 00054 { 00055 enum Type { 00056 empty, // no note here 00057 tap, 00058 hold_head, // graded like a TAP_TAP 00059 hold_tail, /* In 2sand3s mode, holds are deleted and TAP_HOLD_END is added: */ 00060 mine, // don't step! 00061 attack, 00062 autoKeysound, 00063 } type; 00064 enum Source { 00065 original, // part of the original NoteData 00066 addition, // additional note added by a transform 00067 removed, // Removed taps, e.g. in Little - play keysounds here as if 00068 // judged Perfect, but don't bother rendering or judging this 00069 // step. Also used for when we implement auto-scratch in BM, 00070 // and for if/when we do a "reduce" modifier that cancels out 00071 // all but N keys on a line [useful for BM->DDR autogen, too]. 00072 // Removed hold body (...why?) - acts as follows: 00073 // 1 - if we're using a sustained-sound gametype [Keyboardmania], and 00074 // we've already hit the start of the sound (?? we put Holds Off on?) 00075 // then this is triggered automatically to keep the sound going 00076 // 2 - if we're NOT [anything else], we ignore this. 00077 // Equivalent to all 4s aside from the first one. 00078 } source; 00079 00080 // Only valid if type == attack. 00081 CString sAttackModifiers; 00082 float fAttackDurationSeconds; 00083 00084 bool bKeysound; // true if this note plays a keysound when hit 00085 00086 int iKeysoundIndex; // index into Song's vector of keysound files. 00087 // Only valid if bKeysound. 00088 00089 TapNote() {} 00090 TapNote( 00091 Type type_, 00092 Source source_, 00093 CString sAttackModifiers_, 00094 float fAttackDurationSeconds_, 00095 bool bKeysound_, 00096 int iKeysoundIndex_ ) 00097 { 00098 type = type_; 00099 source = source_; 00100 sAttackModifiers = sAttackModifiers_; 00101 fAttackDurationSeconds = fAttackDurationSeconds_; 00102 bKeysound = bKeysound_; 00103 iKeysoundIndex = iKeysoundIndex_; 00104 } 00105 bool operator==( const TapNote &other ) const 00106 { 00107 #define COMPARE(x) if(x!=other.x) return false; 00108 COMPARE(type); 00109 COMPARE(source); 00110 COMPARE(sAttackModifiers); 00111 COMPARE(fAttackDurationSeconds); 00112 COMPARE(bKeysound); 00113 COMPARE(iKeysoundIndex); 00114 COMPARE(iDuration); 00115 #undef COMPARE 00116 return true; 00117 } 00118 00119 /* hold_head only: */ 00120 int iDuration; 00121 00122 TapNoteResult result; 00123 00124 /* hold_head only: */ 00125 HoldNoteResult HoldResult; 00126 }; 00127 00128 extern TapNote TAP_EMPTY; // '0' 00129 extern TapNote TAP_ORIGINAL_TAP; // '1' 00130 extern TapNote TAP_ORIGINAL_HOLD_HEAD; // '2' 00131 extern TapNote TAP_ORIGINAL_HOLD_TAIL; // '3' 00132 extern TapNote TAP_ORIGINAL_MINE; // 'M' 00133 extern TapNote TAP_ORIGINAL_ATTACK; // 'A' 00134 extern TapNote TAP_ORIGINAL_AUTO_KEYSOUND; // 'K' 00135 extern TapNote TAP_ADDITION_TAP; 00136 extern TapNote TAP_ADDITION_MINE; 00137 00138 // TODO: Don't have a hard-coded track limit. 00139 const int MAX_NOTE_TRACKS = 16; 00140 00141 /* This is a divisor for our "fixed-point" time/beat representation. It must be evenly divisible 00142 * by 2, 3, and 4, to exactly represent 8th, 12th and 16th notes. It must be divisible by 1000, to 00143 * exactly represent 0.001. It must leave enough precision before the decimal place to store 00144 * numbers into the tens of thousands, so we don't have any attainable maximum tap note row. */ 00145 const int ROWS_PER_BEAT = 48*1000; 00146 00147 const int BEATS_PER_MEASURE = 4; 00148 const int ROWS_PER_MEASURE = ROWS_PER_BEAT * BEATS_PER_MEASURE; 00149 const int MAX_NOTE_ROW = (1<<30); 00150 00151 enum NoteType 00152 { 00153 NOTE_TYPE_4TH, // quarter note 00154 NOTE_TYPE_8TH, // eighth note 00155 NOTE_TYPE_12TH, // triplet 00156 NOTE_TYPE_16TH, // sixteenth note 00157 NOTE_TYPE_24TH, // twenty-fourth note 00158 NOTE_TYPE_32ND, // thirty-second note 00159 00160 // Why is this high of resolution needed? It's breaking NoteSkins 00161 // with note-coloring, and the extra resolution will take up more 00162 // memory. Does any game actually use this? -Chris 00163 00164 // MD 11/02/03 - added finer divisions 00165 NOTE_TYPE_48TH, // forty-eighth note 00166 NOTE_TYPE_64TH, // sixty-fourth note 00167 // Not having this triggers asserts all over the place. Go figure. 00168 NOTE_TYPE_192ND, 00169 NUM_NOTE_TYPES, 00170 NOTE_TYPE_INVALID 00171 }; 00172 00173 float NoteTypeToBeat( NoteType nt ); 00174 NoteType GetNoteType( int row ); 00175 NoteType BeatToNoteType( float fBeat ); 00176 bool IsNoteOfType( int row, NoteType t ); 00177 CString NoteTypeToString( NoteType nt ); 00178 00179 inline int BeatToNoteRow( float fBeatNum ) { return lrintf( fBeatNum * ROWS_PER_BEAT ); } // round 00180 inline int BeatToNoteRowNotRounded( float fBeatNum ) { return (int)( fBeatNum * ROWS_PER_BEAT ); } 00181 inline float NoteRowToBeat( int iRow ) { return iRow / (float)ROWS_PER_BEAT; } 00182 00183 #endif 00184 00185 /* 00186 * (c) 2001-2004 Chris Danford, Glenn Maynard 00187 * All rights reserved. 00188 * 00189 * Permission is hereby granted, free of charge, to any person obtaining a 00190 * copy of this software and associated documentation files (the 00191 * "Software"), to deal in the Software without restriction, including 00192 * without limitation the rights to use, copy, modify, merge, publish, 00193 * distribute, and/or sell copies of the Software, and to permit persons to 00194 * whom the Software is furnished to do so, provided that the above 00195 * copyright notice(s) and this permission notice appear in all copies of 00196 * the Software and that both the above copyright notice(s) and this 00197 * permission notice appear in supporting documentation. 00198 * 00199 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00200 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00201 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF 00202 * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS 00203 * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT 00204 * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 00205 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 00206 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00207 * PERFORMANCE OF THIS SOFTWARE. 00208 */