Merge with default

This commit is contained in:
Henrik Andersson
2011-06-29 21:27:37 +02:00
108 changed files with 11677 additions and 1109 deletions
+13
View File
@@ -91,6 +91,19 @@ bool AttackArray::ContainsTransformOrTurn() const
return false;
}
vector<RString> AttackArray::ToVectorString() const
{
vector<RString> ret;
FOREACH_CONST( Attack, *this, a )
{
ret.push_back(ssprintf("TIME=%f:LEN=%f:MODS=%s",
a->fStartSecond,
a->fSecsRemaining,
a->sModifiers.c_str()));
}
return ret;
}
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
+5
View File
@@ -71,6 +71,11 @@ struct AttackArray : public vector<Attack>
* @brief Determine if the list of attacks contains a transform or turn mod.
* @return true if it does, or false otherwise. */
bool ContainsTransformOrTurn() const;
/**
* @brief Return a string representation used for simfiles.
* @return the string representation. */
vector<RString> ToVectorString() const;
};
#endif
+16
View File
@@ -1045,6 +1045,22 @@ void NoteField::DrawPrimitives()
}
}
}
else
{
AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ?
GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks :
GAMESTATE->m_pCurSong->m_Attacks;
FOREACH_CONST(Attack, attacks, a)
{
float fBeat = timing.GetBeatFromElapsedTime(a->fStartSecond);
if (BeatToNoteRow(fBeat) >= iFirstRowToDraw &&
BeatToNoteRow(fBeat) <= iLastRowToDraw &&
IS_ON_SCREEN(fBeat))
{
this->DrawAttackText(fBeat, *a);
}
}
}
if( !GAMESTATE->m_bIsUsingStepTiming )
{
+17 -1
View File
@@ -334,7 +334,23 @@ static inline float ToBeat(int row) { return NoteRowToBeat(row); }
*/
static inline float ToBeat(float beat) { return beat; }
/**
* @brief Scales the position.
* @param T start - the starting row of the scaling region
* @param T length - the length of the scaling region
* @param T newLength - the new length of the scaling region
* @param T position - the position to scale
* @return T the scaled position
*/
template<typename T>
inline T ScalePosition( T start, T length, T newLength, T position )
{
if( position < start )
return position;
if( position >= start + length )
return position - length + newLength;
return start + (position - start) * newLength / length;
}
#endif
+18 -12
View File
@@ -10,7 +10,6 @@
#include "Song.h"
#include "SongManager.h"
#include "Steps.h"
#include "Attack.h"
#include "PrefsManager.h"
void SMLoader::SetSongTitle(const RString & title)
@@ -143,26 +142,31 @@ void SMLoader::ProcessBGChanges( Song &out, const RString &sValueName, const RSt
}
}
void SMLoader::ProcessAttacks( Song &out, MsdFile::value_t sParams )
void SMLoader::ProcessAttackString( vector<RString> & attacks, MsdFile::value_t params )
{
for( unsigned s=1; s < params.params.size(); ++s )
{
RString tmp = params[s];
Trim(tmp);
attacks.push_back( tmp );
}
}
void SMLoader::ProcessAttacks( AttackArray &attacks, MsdFile::value_t params )
{
// Build the RString vector here so we can write it to file again later
for( unsigned s=1; s < sParams.params.size(); ++s )
out.m_sAttackString.push_back( sParams[s] );
Attack attack;
float end = -9999;
for( unsigned j=1; j < sParams.params.size(); ++j )
for( unsigned j=1; j < params.params.size(); ++j )
{
vector<RString> sBits;
split( sParams[j], "=", sBits, false );
split( params[j], "=", sBits, false );
// Need an identifer and a value for this to work
if( sBits.size() < 2 )
continue;
TrimLeft( sBits[0] );
TrimRight( sBits[0] );
Trim( sBits[0] );
if( !sBits[0].CompareNoCase("TIME") )
attack.fStartSecond = strtof( sBits[1], NULL );
@@ -172,6 +176,7 @@ void SMLoader::ProcessAttacks( Song &out, MsdFile::value_t sParams )
end = strtof( sBits[1], NULL );
else if( !sBits[0].CompareNoCase("MODS") )
{
Trim(sBits[1]);
attack.sModifiers = sBits[1];
if( end != -9999 )
@@ -183,7 +188,7 @@ void SMLoader::ProcessAttacks( Song &out, MsdFile::value_t sParams )
if( attack.fSecsRemaining < 0.0f )
attack.fSecsRemaining = 0.0f;
out.m_Attacks.push_back( attack );
attacks.push_back( attack );
}
}
}
@@ -913,7 +918,8 @@ bool SMLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCache
// Attacks loaded from file
else if( sValueName=="ATTACKS" )
{
ProcessAttacks( out, sParams );
ProcessAttackString(out.m_sAttackString, sParams);
ProcessAttacks(out.m_Attacks, sParams);
}
else if( sValueName=="NOTES" || sValueName=="NOTES2" )
+13 -1
View File
@@ -3,6 +3,7 @@
#include "GameConstantsAndTypes.h"
#include "BackgroundUtil.h"
#include "Attack.h"
#include "MsdFile.h" // we require the struct from here.
class Song;
@@ -133,7 +134,18 @@ struct SMLoader
virtual void ProcessBGChanges( Song &out, const RString &sValueName,
const RString &sPath, const RString &sParam );
void ProcessAttacks( Song &out, MsdFile::value_t sParams );
/**
* @brief Put the attacks in the attacks string.
* @param attacks the attack string.
* @param params the params from the simfile. */
virtual void ProcessAttackString(vector<RString> &attacks, MsdFile::value_t params);
/**
* @brief Put the attacks in the attacks array.
* @param attacks the attacks array.
* @param params the params from the simfile. */
void ProcessAttacks( AttackArray &attacks, MsdFile::value_t params );
void ProcessInstrumentTracks( Song &out, const RString &sParam );
/**
+2 -1
View File
@@ -432,7 +432,8 @@ bool SMALoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach
// Attacks loaded from file
else if( sValueName=="ATTACKS" )
{
SMLoader::ProcessAttacks( out, sParams );
ProcessAttackString(out.m_sAttackString, sParams);
ProcessAttacks(out.m_Attacks, sParams);
}
else if( sValueName=="NOTES" || sValueName=="NOTES2" )
+4 -2
View File
@@ -344,7 +344,8 @@ bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach
// Attacks loaded from file
else if( sValueName=="ATTACKS" )
{
SMLoader::ProcessAttacks( out, sParams );
ProcessAttackString(out.m_sAttackString, sParams);
ProcessAttacks(out.m_Attacks, sParams);
}
else if( sValueName=="OFFSET" )
@@ -559,7 +560,8 @@ bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach
else if( sValueName=="ATTACKS" )
{
// Step Attacks aren't in yet.
ProcessAttackString(pNewNotes->m_sAttackString, sParams);
ProcessAttacks(pNewNotes->m_Attacks, sParams);
}
else if( sValueName=="OFFSET" )
+2
View File
@@ -26,6 +26,8 @@ const float VERSION_RADAR_FAKE = 0.53f;
const float VERSION_WARP_SEGMENT = 0.56f;
/** @brief The version that formally introduced Split Timing. */
const float VERSION_SPLIT_TIMING = 0.7f;
/** @brief The version that moved the step's Offset higher up. */
const float VERSION_OFFSET_BEFORE_ATTACK = 0.72f;
/**
* @brief The SSCLoader handles all of the parsing needed for .ssc files.
+13 -4
View File
@@ -317,12 +317,21 @@ static RString GetSSCNoteData( const Song &song, const Steps &in, bool bSavingCa
lines.push_back( ssprintf( "#RADARVALUES:%s;", join(",",asRadarValues).c_str() ) );
lines.push_back( ssprintf( "#CREDIT:%s;", SmEscape(in.GetCredit()).c_str() ) );
lines.push_back( ssprintf( "#OFFSET:%.6f;", in.m_Timing.m_fBeat0OffsetInSeconds ) );
GetTimingTags( lines, in.m_Timing );
// For now, attacks are NOT in use for the step.
lines.push_back( "#ATTACKS:;" );
lines.push_back( ssprintf( "#OFFSET:%.6f;", in.m_Timing.m_fBeat0OffsetInSeconds ) );
RString attacks = "";
for( unsigned a=0; a < in.m_sAttackString.size(); a++ )
{
RString sData = in.m_sAttackString[a];
attacks += sData;
if( a != (in.m_sAttackString.size() - 1) )
attacks += ":\r\n"; // Not the end, so write a divider ':'
}
Trim(attacks, ":"); // just in case something screwy happens.
lines.push_back( ssprintf( "#ATTACKS:%s;", attacks.c_str()));
RString sNoteData;
in.GetSMNoteData( sNoteData );
+4 -6
View File
@@ -960,8 +960,10 @@ void Player::Update( float fDeltaTime )
UpdateJudgedRows();
// Check for TapNote misses
UpdateTapNotesMissedOlderThan( GetMaxStepDistanceSeconds() );
if (!GAMESTATE->m_bInStepEditor)
{
UpdateTapNotesMissedOlderThan( GetMaxStepDistanceSeconds() );
}
// process transforms that are waiting to be applied
ApplyWaitingTransforms();
}
@@ -2973,10 +2975,6 @@ void Player::RandomizeNotes( int iNoteRow )
const int iSwapWith = RandomInt( iNumOfTracks );
// Make sure we're not swapping with ourselves.
if( t == iSwapWith )
continue;
// Make sure this is empty.
if( m_NoteData.FindTapNote(iSwapWith, iNewNoteRow) != m_NoteData.end(iSwapWith) )
continue;
+25 -6
View File
@@ -37,7 +37,7 @@ void PlayerOptions::Init()
m_fBlind = 0; m_SpeedfBlind = 1.0f;
m_fCover = 0; m_SpeedfCover = 1.0f;
m_fRandAttack = 0; m_SpeedfRandAttack = 1.0f;
m_fSongAttack = 0; m_SpeedfSongAttack = 1.0f;
m_fNoAttack = 0; m_SpeedfNoAttack = 1.0f;
m_fPlayerAutoPlay = 0; m_SpeedfPlayerAutoPlay = 1.0f;
m_bSetTiltOrSkew = false;
m_fPerspectiveTilt = 0; m_SpeedfPerspectiveTilt = 1.0f;
@@ -73,7 +73,7 @@ void PlayerOptions::Approach( const PlayerOptions& other, float fDeltaSeconds )
APPROACH( fBlind );
APPROACH( fCover );
APPROACH( fRandAttack );
APPROACH( fSongAttack );
APPROACH( fNoAttack );
APPROACH( fPlayerAutoPlay );
APPROACH( fPerspectiveTilt );
APPROACH( fSkew );
@@ -180,7 +180,7 @@ void PlayerOptions::GetMods( vector<RString> &AddTo, bool bForceNoteSkin ) const
AddPart( AddTo, m_fCover, "Cover" );
AddPart( AddTo, m_fRandAttack, "RandomAttacks" );
AddPart( AddTo, m_fSongAttack, "SongAttacks" );
AddPart( AddTo, m_fNoAttack, "NoAttacks" );
AddPart( AddTo, m_fPlayerAutoPlay, "PlayerAutoPlay" );
AddPart( AddTo, m_fPassmark, "Passmark" );
@@ -417,7 +417,7 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut
else if( sBit == "blind" ) SET_FLOAT( fBlind )
else if( sBit == "cover" ) SET_FLOAT( fCover )
else if( sBit == "randomattacks" ) SET_FLOAT( fRandAttack )
else if( sBit == "songattacks" ) SET_FLOAT( fSongAttack )
else if( sBit == "noattacks" ) SET_FLOAT( fNoAttack )
else if( sBit == "playerautoplay" ) SET_FLOAT( fPlayerAutoPlay )
else if( sBit == "passmark" ) SET_FLOAT( fPassmark )
else if( sBit == "overhead" ) { m_bSetTiltOrSkew = true; m_fSkew = 0; m_fPerspectiveTilt = 0; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; }
@@ -657,7 +657,7 @@ bool PlayerOptions::operator==( const PlayerOptions &other ) const
COMPARE(m_fBlind);
COMPARE(m_fCover);
COMPARE(m_fRandAttack);
COMPARE(m_fSongAttack);
COMPARE(m_fNoAttack);
COMPARE(m_fPlayerAutoPlay);
COMPARE(m_fPerspectiveTilt);
COMPARE(m_fSkew);
@@ -712,6 +712,10 @@ bool PlayerOptions::IsEasierForSongAndSteps( Song* pSong, Steps* pSteps, PlayerN
// This makes songs with sparse notes easier.
if( m_bTransforms[TRANSFORM_ECHO] ) return true;
// Removing attacks is easier in general.
if (m_fNoAttack || (!m_fRandAttack && pSteps->HasAttacks()))
return true;
if( m_fCover ) return true;
if( m_fPlayerAutoPlay ) return true;
return false;
@@ -957,7 +961,20 @@ public:
DEFINE_METHOD( GetBlind, m_fBlind )
DEFINE_METHOD( GetCover, m_fCover )
DEFINE_METHOD( GetRandomAttacks, m_fRandAttack )
DEFINE_METHOD( GetSongAttacks, m_fSongAttack )
static int GetStepAttacks( T *p, lua_State *L )
{
lua_pushnumber(L,
(p->m_fNoAttack > 0 || p->m_fRandAttack > 0 ? 0 : 1 ));
return 1;
}
// This one is deprecated.
static int GetSongAttacks( T *p, lua_State *L )
{
return GetStepAttacks(p, L);
}
DEFINE_METHOD( GetNoAttacks, m_fNoAttack )
DEFINE_METHOD( GetSkew, m_fSkew )
DEFINE_METHOD( GetPassmark, m_fPassmark )
DEFINE_METHOD( GetRandomSpeed, m_fRandomSpeed )
@@ -984,6 +1001,8 @@ public:
// SetSkew
ADD_METHOD( GetSongAttacks );
// SetSongAttacks
ADD_METHOD( GetStepAttacks );
ADD_METHOD( GetNoAttacks );
ADD_METHOD( GetCMod );
ADD_METHOD( GetXMod );
+2 -2
View File
@@ -27,7 +27,7 @@ public:
m_fBlind(0), m_SpeedfBlind(1.0f),
m_fCover(0), m_SpeedfCover(1.0f),
m_fRandAttack(0), m_SpeedfRandAttack(1.0f),
m_fSongAttack(0), m_SpeedfSongAttack(1.0f),
m_fNoAttack(0), m_SpeedfNoAttack(1.0f),
m_fPlayerAutoPlay(0), m_SpeedfPlayerAutoPlay(1.0f),
m_bSetTiltOrSkew(false),
m_fPerspectiveTilt(0), m_SpeedfPerspectiveTilt(1.0f),
@@ -167,7 +167,7 @@ public:
float m_fBlind, m_SpeedfBlind;
float m_fCover, m_SpeedfCover; // hide the background per-player--can't think of a good name
float m_fRandAttack, m_SpeedfRandAttack;
float m_fSongAttack, m_SpeedfSongAttack;
float m_fNoAttack, m_SpeedfNoAttack;
float m_fPlayerAutoPlay, m_SpeedfPlayerAutoPlay;
bool m_bSetTiltOrSkew; // true if the tilt or skew was set by FromString
float m_fPerspectiveTilt, m_SpeedfPerspectiveTilt; // -1 = near, 0 = overhead, +1 = space
+1 -1
View File
@@ -434,7 +434,7 @@ RString ConvertI64FormatString( const RString &sStr )
RString ConvertI64FormatString( const RString &sStr ) { return sStr; }
#endif
/* ISO-639-1 codes: http://www.loc.gov/standards/iso639-2/langcodes.html
/* ISO-639-1 codes: http://www.loc.gov/standards/iso639-2/php/code_list.php
* native forms: http://people.w3.org/rishida/names/languages.html
* We don't use 3-letter codes, so we don't bother supporting them. */
static const LanguageInfo g_langs[] =
+326 -29
View File
@@ -68,6 +68,8 @@ AutoScreenMessage( SM_BackFromSongInformation );
AutoScreenMessage( SM_BackFromBGChange );
AutoScreenMessage( SM_BackFromInsertTapAttack );
AutoScreenMessage( SM_BackFromInsertTapAttackPlayerOptions );
AutoScreenMessage( SM_BackFromInsertStepAttack );
AutoScreenMessage( SM_BackFromInsertStepAttackPlayerOptions );
AutoScreenMessage( SM_BackFromInsertCourseAttack );
AutoScreenMessage( SM_BackFromInsertCourseAttackPlayerOptions );
AutoScreenMessage( SM_BackFromCourseModeMenu );
@@ -144,13 +146,13 @@ void ScreenEdit::InitEditMappings()
m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PERIOD);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_COMMA);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_LABEL_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PERIOD);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_NEXT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_SEGMENT_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_PERIOD);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SEGMENT_NEXT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SEGMENT_NEXT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_LABEL_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_COMMA);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_LABEL_PREV][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_SEGMENT_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_COMMA);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SEGMENT_PREV][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SEGMENT_PREV][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_SELECT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_SCROLL_SELECT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT);
@@ -244,8 +246,8 @@ void ScreenEdit::InitEditMappings()
m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cb);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LSHIFT);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RSHIFT);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_COURSE_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cc);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cv);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_ADD_STEP_MODS][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cc);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_OPEN_STEP_ATTACK_MENU][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cv);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_INSERT_SHIFT_PAUSES][0] = DeviceInput(DEVICE_KEYBOARD, KEY_INSERT);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_INSERT_SHIFT_PAUSES][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
@@ -275,6 +277,14 @@ void ScreenEdit::InitEditMappings()
m_EditMappingsDeviceInput.button[EDIT_BUTTON_CYCLE_TAP_LEFT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cn);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_CYCLE_TAP_RIGHT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cm);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_CYCLE_SEGMENT_LEFT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cn);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_CYCLE_SEGMENT_LEFT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_CYCLE_SEGMENT_LEFT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
m_EditMappingsDeviceInput.button[EDIT_BUTTON_CYCLE_SEGMENT_RIGHT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_Cm);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_CYCLE_SEGMENT_RIGHT][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_CYCLE_SEGMENT_RIGHT][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
m_EditMappingsDeviceInput.button [EDIT_BUTTON_SCROLL_SPEED_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_UP);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SCROLL_SPEED_UP][0] = DeviceInput(DEVICE_KEYBOARD, KEY_LCTRL);
m_EditMappingsDeviceInput.hold[EDIT_BUTTON_SCROLL_SPEED_UP][1] = DeviceInput(DEVICE_KEYBOARD, KEY_RCTRL);
@@ -569,6 +579,8 @@ static MenuDef g_AreaMenu(
MenuRowDef( ScreenEdit::shift_pauses_backward, "Shift all timing changes up", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::convert_pause_to_beat, "Convert pause to beats", true,
EditMode_Full, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::convert_delay_to_beat, "Convert delay to beats", true,
EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::undo, "Undo", true, EditMode_Practice, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::clear_clipboard, "Clear clipboard", true,
EditMode_Practice, true, true, 0, NULL )
@@ -631,6 +643,8 @@ static MenuDef g_TimingDataInformation(
MenuRowDef( ScreenEdit::speed_mode, "Edit speed (mode)", true, EditMode_Full, true, true, 0, "Beats", "Seconds" ),
MenuRowDef( ScreenEdit::scroll, "Edit scrolling factor", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::fake, "Edit fake", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::copy_timing, "Copy timing data", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::paste_timing, "Paste timing data", true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef( ScreenEdit::erase_step_timing, "Erase step timing", true, EditMode_Full, true, true, 0, NULL )
);
@@ -768,6 +782,8 @@ void ScreenEdit::Init()
ScreenWithMenuElements::Init();
InitEditMappings();
currentCycleSegment = "label";
// save the originals for reverting later
CopyToLastSave();
@@ -859,6 +875,8 @@ void ScreenEdit::Init()
m_bRemoveNoteButtonDown = false;
m_Clipboard.SetNumTracks( m_NoteDataEdit.GetNumTracks() );
clipboardTiming = GAMESTATE->m_pCurSong->m_SongTiming; // always have a backup.
m_bHasUndo = false;
m_Undo.SetNumTracks( m_NoteDataEdit.GetNumTracks() );
@@ -1096,9 +1114,11 @@ static LocalizedString DIFFICULTY("ScreenEdit", "Difficulty");
static LocalizedString ROUTINE_PLAYER("ScreenEdit", "Routine Player");
static LocalizedString DESCRIPTION("ScreenEdit", "Description");
static LocalizedString CHART_STYLE("ScreenEdit", "Chart Style");
static LocalizedString STEP_AUTHOR("ScreenEdit", "Step Author");
static LocalizedString MAIN_TITLE("ScreenEdit", "Main title");
static LocalizedString SUBTITLE("ScreenEdit", "Subtitle");
static LocalizedString TAP_NOTE_TYPE("ScreenEdit", "Tap Note");
static LocalizedString SEGMENT_TYPE("ScreenEdit", "Segment");
static LocalizedString TAP_STEPS("ScreenEdit", "Tap Steps");
static LocalizedString JUMPS("ScreenEdit", "Jumps");
static LocalizedString HANDS("ScreenEdit", "Hands");
@@ -1124,9 +1144,11 @@ static ThemeMetric<RString> DIFFICULTY_FORMAT("ScreenEdit", "DifficultyFormat");
static ThemeMetric<RString> ROUTINE_PLAYER_FORMAT("ScreenEdit", "RoutinePlayerFormat");
static ThemeMetric<RString> DESCRIPTION_FORMAT("ScreenEdit", "DescriptionFormat");
static ThemeMetric<RString> CHART_STYLE_FORMAT("ScreenEdit", "ChartStyleFormat");
static ThemeMetric<RString> STEP_AUTHOR_FORMAT("ScreenEdit", "StepAuthorFormat");
static ThemeMetric<RString> MAIN_TITLE_FORMAT("ScreenEdit", "MainTitleFormat");
static ThemeMetric<RString> SUBTITLE_FORMAT("ScreenEdit", "SubtitleFormat");
static ThemeMetric<RString> TAP_NOTE_TYPE_FORMAT("ScreenEdit", "TapNoteTypeFormat");
static ThemeMetric<RString> SEGMENT_TYPE_FORMAT("ScreenEdit", "SegmentTypeFormat");
static ThemeMetric<RString> NUM_STEPS_FORMAT("ScreenEdit", "NumStepsFormat");
static ThemeMetric<RString> NUM_JUMPS_FORMAT("ScreenEdit", "NumJumpsFormat");
static ThemeMetric<RString> NUM_HOLDS_FORMAT("ScreenEdit", "NumHoldsFormat");
@@ -1192,12 +1214,14 @@ void ScreenEdit::UpdateTextInfo()
if ( m_InputPlayerNumber != PLAYER_INVALID )
sText += ssprintf( ROUTINE_PLAYER_FORMAT.GetValue(), ROUTINE_PLAYER.GetValue().c_str(), m_InputPlayerNumber + 1 );
sText += ssprintf( DESCRIPTION_FORMAT.GetValue(), DESCRIPTION.GetValue().c_str(), m_pSteps->GetDescription().c_str() );
sText += ssprintf( CHART_STYLE_FORMAT.GetValue(), CHART_STYLE.GetValue().c_str(), m_pSteps->GetChartStyle().c_str() );
sText += ssprintf( STEP_AUTHOR_FORMAT.GetValue(), STEP_AUTHOR.GetValue().c_str(), m_pSteps->GetCredit().c_str() );
//sText += ssprintf( CHART_STYLE_FORMAT.GetValue(), CHART_STYLE.GetValue().c_str(), m_pSteps->GetChartStyle().c_str() );
sText += ssprintf( MAIN_TITLE_FORMAT.GetValue(), MAIN_TITLE.GetValue().c_str(), m_pSong->m_sMainTitle.c_str() );
if( m_pSong->m_sSubTitle.size() )
sText += ssprintf( SUBTITLE_FORMAT.GetValue(), SUBTITLE.GetValue().c_str(), m_pSong->m_sSubTitle.c_str() );
sText += ssprintf( SEGMENT_TYPE_FORMAT.GetValue(), SEGMENT_TYPE.GetValue().c_str(), currentCycleSegment.c_str() );
sText += ssprintf( TAP_NOTE_TYPE_FORMAT.GetValue(), TAP_NOTE_TYPE.GetValue().c_str(), TapNoteTypeToString( m_selectedTap.type ).c_str() );
break;
break;
}
GAMESTATE->SetProcessedTimingData(&m_pSteps->m_Timing);
@@ -1453,6 +1477,62 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
}
break;
}
case EDIT_BUTTON_CYCLE_SEGMENT_LEFT:
{
if (this->currentCycleSegment == "label")
this->currentCycleSegment = "fake";
else if (this->currentCycleSegment == "fake")
this->currentCycleSegment = "scroll";
else if (this->currentCycleSegment == "scroll")
this->currentCycleSegment = "speed";
else if (this->currentCycleSegment == "speed")
this->currentCycleSegment = "combo";
else if (this->currentCycleSegment == "combo")
this->currentCycleSegment = "tickcount";
else if (this->currentCycleSegment == "tickcount")
this->currentCycleSegment = "timeSig";
else if (this->currentCycleSegment == "timeSig")
this->currentCycleSegment = "warp";
else if (this->currentCycleSegment == "warp")
this->currentCycleSegment = "delay";
else if (this->currentCycleSegment == "delay")
this->currentCycleSegment = "stop";
else if (this->currentCycleSegment == "stop")
this->currentCycleSegment = "bpm";
else if (this->currentCycleSegment == "bpm")
this->currentCycleSegment = "label";
// fallback gracefully instead of assert.
else this->currentCycleSegment = "label";
break;
}
case EDIT_BUTTON_CYCLE_SEGMENT_RIGHT:
{
if (this->currentCycleSegment == "label")
this->currentCycleSegment = "bpm";
else if (this->currentCycleSegment == "bpm")
this->currentCycleSegment = "stop";
else if (this->currentCycleSegment == "stop")
this->currentCycleSegment = "delay";
else if (this->currentCycleSegment == "delay")
this->currentCycleSegment = "warp";
else if (this->currentCycleSegment == "warp")
this->currentCycleSegment = "timeSig";
else if (this->currentCycleSegment == "timeSig")
this->currentCycleSegment = "tickcount";
else if (this->currentCycleSegment == "tickcount")
this->currentCycleSegment = "combo";
else if (this->currentCycleSegment == "combo")
this->currentCycleSegment = "speed";
else if (this->currentCycleSegment == "speed")
this->currentCycleSegment = "scroll";
else if (this->currentCycleSegment == "scroll")
this->currentCycleSegment = "fake";
else if (this->currentCycleSegment == "fake")
this->currentCycleSegment = "label";
// fallback gracefully instead of assert.
else this->currentCycleSegment = "label";
break;
}
case EDIT_BUTTON_SCROLL_SPEED_UP:
case EDIT_BUTTON_SCROLL_SPEED_DOWN:
{
@@ -1567,16 +1647,60 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
ScrollTo( NoteRowToBeat(iRow) );
}
break;
case EDIT_BUTTON_LABEL_NEXT:
{
ScrollTo( GetAppropriateTiming().GetNextLabelSegmentBeatAtBeat( GetBeat() ) );
}
break;
case EDIT_BUTTON_LABEL_PREV:
{
ScrollTo( GetAppropriateTiming().GetPreviousLabelSegmentBeatAtBeat( GetBeat() ) );
}
break;
case EDIT_BUTTON_SEGMENT_NEXT:
{
TimingData &timing = GetAppropriateTiming();
if (this->currentCycleSegment == "label")
ScrollTo(timing.GetNextLabelSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "bpm")
ScrollTo(timing.GetNextBPMSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "stop")
ScrollTo(timing.GetNextStopSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "delay")
ScrollTo(timing.GetNextDelaySegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "warp")
ScrollTo(timing.GetNextWarpSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "timeSig")
ScrollTo(timing.GetNextTimeSignatureSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "tickcount")
ScrollTo(timing.GetNextTickcountSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "combo")
ScrollTo(timing.GetNextComboSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "speed")
ScrollTo(timing.GetNextSpeedSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "scroll")
ScrollTo(timing.GetNextScrollSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "fake")
ScrollTo(timing.GetNextFakeSegmentBeatAtBeat(GetBeat()));
}
break;
case EDIT_BUTTON_SEGMENT_PREV:
{
TimingData &timing = GetAppropriateTiming();
if (this->currentCycleSegment == "label")
ScrollTo(timing.GetPreviousLabelSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "bpm")
ScrollTo(timing.GetPreviousBPMSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "stop")
ScrollTo(timing.GetPreviousStopSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "delay")
ScrollTo(timing.GetPreviousDelaySegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "warp")
ScrollTo(timing.GetPreviousWarpSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "timeSig")
ScrollTo(timing.GetPreviousTimeSignatureSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "tickcount")
ScrollTo(timing.GetPreviousTickcountSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "combo")
ScrollTo(timing.GetPreviousComboSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "speed")
ScrollTo(timing.GetPreviousSpeedSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "scroll")
ScrollTo(timing.GetPreviousScrollSegmentBeatAtBeat(GetBeat()));
else if (this->currentCycleSegment == "fake")
ScrollTo(timing.GetPreviousFakeSegmentBeatAtBeat(GetBeat()));
}
break;
case EDIT_BUTTON_SNAP_NEXT:
if( m_SnapDisplay.PrevSnapMode() )
OnSnapModeChange();
@@ -1654,6 +1778,9 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
// don't keep undo when changing Steps
ClearUndo();
// get the second of the current step.
float curSecond = GetAppropriateTiming().GetElapsedTimeFromBeat(GetBeat());
// save current steps
Steps* pSteps = GAMESTATE->m_pCurSteps[PLAYER_1];
ASSERT( pSteps );
@@ -1706,6 +1833,8 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
int(vSteps.size()) );
SCREENMAN->SystemMessage( s );
m_soundSwitchSteps.Play();
ScrollTo( GetAppropriateTiming().GetBeatFromElapsedTime(curSecond) );
}
break;
case EDIT_BUTTON_BPM_UP:
@@ -1988,6 +2117,35 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
EditMiniMenu( &g_CourseMode, SM_BackFromCourseModeMenu );
}
break;
case EDIT_BUTTON_OPEN_STEP_ATTACK_MENU:
{
TimingData &timing = GetAppropriateTiming();
float startTime = timing.GetElapsedTimeFromBeat(GetBeat());
AttackArray &attacks =
(GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks);
int index = FindAttackAtTime(attacks, startTime);
if (index >= 0)
{
const RString sDuration = ssprintf( "%.5f", attacks[index].fSecsRemaining );
g_InsertCourseAttack.rows[remove].bEnabled = true;
if( g_InsertCourseAttack.rows[duration].choices.size() == 9 )
g_InsertCourseAttack.rows[duration].choices.push_back( sDuration );
else
g_InsertCourseAttack.rows[duration].choices.back() = sDuration;
g_InsertCourseAttack.rows[duration].iDefaultChoice = 9;
}
else
{
if( g_InsertCourseAttack.rows[duration].choices.size() == 10 )
g_InsertCourseAttack.rows[duration].choices.pop_back();
g_InsertCourseAttack.rows[duration].iDefaultChoice = 3;
}
EditMiniMenu( &g_InsertCourseAttack, SM_BackFromInsertStepAttack );
break;
}
case EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU:
{
// TODO: Give Song/Step Timing switches/functions here?
@@ -2019,6 +2177,44 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB )
EditMiniMenu( &g_InsertCourseAttack, SM_BackFromInsertCourseAttack );
}
break;
case EDIT_BUTTON_ADD_STEP_MODS:
{
float start = -1;
float end = -1;
PlayerOptions po;
if (m_NoteFieldEdit.m_iBeginMarker == -1) // not highlighted
{
po.FromString("");
}
else
{
TimingData &timing = GetAppropriateTiming();
start = timing.GetElapsedTimeFromBeat(NoteRowToBeat(m_NoteFieldEdit.m_iBeginMarker));
AttackArray &attacks =
(GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks);
int index = FindAttackAtTime(attacks, start);
if (index >= 0)
{
po.FromString("");
}
if (m_NoteFieldEdit.m_iEndMarker == -1)
{
end = m_pSong->m_fMusicLengthSeconds;
}
else
{
end = timing.GetElapsedTimeFromBeat(NoteRowToBeat(m_NoteFieldEdit.m_iEndMarker));
}
}
g_fLastInsertAttackPositionSeconds = start;
g_fLastInsertAttackDurationSeconds = end - start;
GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.Assign( ModsLevel_Stage, po );
SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptions", SM_BackFromInsertStepAttackPlayerOptions );
break;
}
case EDIT_BUTTON_ADD_COURSE_MODS:
{
float fStart, fEnd;
@@ -2910,6 +3106,30 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
m_NoteDataEdit.SetTapNote( g_iLastInsertTapAttackTrack, row, tn );
CheckNumberOfNotesAndUndo();
}
else if (SM == SM_BackFromInsertStepAttack)
{
int iDurationChoice = ScreenMiniMenu::s_viLastAnswers[0];
TimingData &timing = GetAppropriateTiming();
g_fLastInsertAttackPositionSeconds = timing.GetElapsedTimeFromBeat( GetBeat() );
g_fLastInsertAttackDurationSeconds = StringToFloat( g_InsertCourseAttack.rows[0].choices[iDurationChoice] );
AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks;
int iAttack = FindAttackAtTime(attacks, g_fLastInsertAttackPositionSeconds);
if (ScreenMiniMenu::s_iLastRowCode == ScreenEdit::remove )
{
ASSERT(iAttack >= 0);
attacks.erase(attacks.begin() + iAttack);
}
else
{
PlayerOptions po;
if (iAttack >= 0)
po.FromString(attacks[iAttack].sModifiers);
GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.Assign( ModsLevel_Preferred, po );
SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptions", SM_BackFromInsertStepAttackPlayerOptions );
}
}
else if( SM == SM_BackFromInsertCourseAttack )
{
int iDurationChoice = ScreenMiniMenu::s_viLastAnswers[0];
@@ -2939,6 +3159,27 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
SCREENMAN->AddNewScreenToTop( "ScreenPlayerOptions", SM_BackFromInsertCourseAttackPlayerOptions );
}
}
else if (SM == SM_BackFromInsertStepAttackPlayerOptions)
{
PlayerOptions poChosen = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.GetPreferred();
RString mods = poChosen.GetString();
if (g_fLastInsertAttackPositionSeconds >= 0)
{
Attack a(ATTACK_LEVEL_1,
g_fLastInsertAttackPositionSeconds,
g_fLastInsertAttackDurationSeconds,
mods,
false,
false);
AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ? m_pSteps->m_Attacks : m_pSong->m_Attacks;
int index = FindAttackAtTime(attacks, g_fLastInsertAttackPositionSeconds);
if (index >= 0)
attacks[index] = a;
else
attacks.push_back(a);
}
}
else if( SM == SM_BackFromInsertCourseAttackPlayerOptions )
{
PlayerOptions poChosen = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.GetPreferred();
@@ -3409,6 +3650,12 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector<int> &iAns
// copy edit into current Steps
m_pSteps->SetNoteData( m_NoteDataEdit );
// don't forget the attacks.
m_pSong->m_Attacks = GAMESTATE->m_pCurSong->m_Attacks;
m_pSong->m_sAttackString = GAMESTATE->m_pCurSong->m_Attacks.ToVectorString();
m_pSteps->m_Attacks = GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks;
m_pSteps->m_sAttackString = GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks.ToVectorString();
switch( EDIT_MODE.GetValue() )
{
@@ -3856,18 +4103,29 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAns
break;
case convert_pause_to_beat:
{
// TODO: Convert both Delays and Stops at once.
float fStopSeconds = GetAppropriateTiming().GetStopAtRow( BeatToNoteRow( GetBeat() ) );
GetAppropriateTiming().SetStopAtBeat( GetBeat() , 0 );
{
float fStopSeconds = GetAppropriateTiming().GetStopAtRow(GetRow());
GetAppropriateTiming().SetStopAtBeat( GetBeat() , 0 );
float fStopBeats = fStopSeconds * GetAppropriateTiming().GetBPMAtBeat( GetBeat() ) / 60;
float fStopBeats = fStopSeconds * GetAppropriateTiming().GetBPMAtBeat( GetBeat() ) / 60;
// don't move the step from where it is, just move everything later
NoteDataUtil::InsertRows( m_NoteDataEdit, BeatToNoteRow( GetBeat() ) + 1, BeatToNoteRow(fStopBeats) );
GetAppropriateTiming().InsertRows( BeatToNoteRow( GetBeat() ) + 1, BeatToNoteRow(fStopBeats) );
}
// don't move the step from where it is, just move everything later
NoteDataUtil::InsertRows( m_NoteDataEdit, GetRow() + 1, BeatToNoteRow(fStopBeats) );
GetAppropriateTiming().InsertRows( GetRow() + 1, BeatToNoteRow(fStopBeats) );
}
break;
case convert_delay_to_beat:
{
TimingData &timing = GetAppropriateTiming();
float pause = timing.GetDelayAtRow(GetRow());
timing.SetDelayAtRow(GetRow(), 0);
float pauseBeats = pause * timing.GetBPMAtBeat(GetBeat()) / 60;
NoteDataUtil::InsertRows(m_NoteDataEdit, GetRow(), BeatToNoteRow(pauseBeats));
timing.InsertRows(GetRow(), BeatToNoteRow(pauseBeats));
break;
}
case undo:
Undo();
break;
@@ -4150,6 +4408,24 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
);
break;
}
case copy_timing:
{
clipboardTiming = GetAppropriateTiming();
break;
}
case paste_timing:
{
if (GAMESTATE->m_bIsUsingStepTiming)
{
GAMESTATE->m_pCurSteps[PLAYER_1]->m_Timing = clipboardTiming;
}
else
{
GAMESTATE->m_pCurSong->m_SongTiming = clipboardTiming;
}
SetDirty(true);
break;
}
case erase_step_timing:
ScreenPrompt::Prompt( SM_DoEraseStepTiming, CONFIRM_TIMING_ERASE , PROMPT_YES_NO, ANSWER_NO );
break;
@@ -4265,6 +4541,27 @@ void ScreenEdit::SetupCourseAttacks()
FOREACH( Attack, Attacks, attack )
GAMESTATE->m_pPlayerState[PLAYER_1]->LaunchAttack( *attack );
}
else
{
const PlayerOptions &p = GAMESTATE->m_pPlayerState[PLAYER_1]->m_PlayerOptions.GetCurrent();
if (GAMESTATE->m_pCurSong && p.m_fNoAttack == 0 && p.m_fRandAttack == 0 )
{
AttackArray &attacks = GAMESTATE->m_bIsUsingStepTiming ?
GAMESTATE->m_pCurSteps[PLAYER_1]->m_Attacks :
GAMESTATE->m_pCurSong->m_Attacks;
if (attacks.size() > 0)
{
FOREACH(Attack, attacks, attack)
{
float fBeat = GetAppropriateTiming().GetBeatFromElapsedTime(attack->fStartSecond);
if (fBeat >= GetBeat())
GAMESTATE->m_pPlayerState[PLAYER_1]->LaunchAttack( *attack );
}
}
}
}
GAMESTATE->m_pPlayerState[PLAYER_1]->RebuildPlayerOptionsFromActiveAttacks();
}
+22 -3
View File
@@ -60,6 +60,9 @@ enum EditButton
EDIT_BUTTON_CYCLE_TAP_LEFT, /**< Rotate the available tap notes once to the "left". */
EDIT_BUTTON_CYCLE_TAP_RIGHT, /**< Rotate the available tap notes once to the "right". */
EDIT_BUTTON_CYCLE_SEGMENT_LEFT, /**< Select one segment to the left for jumping. */
EDIT_BUTTON_CYCLE_SEGMENT_RIGHT, /**< Select one segment to the right for jumping. */
EDIT_BUTTON_SCROLL_UP_LINE,
EDIT_BUTTON_SCROLL_UP_PAGE,
EDIT_BUTTON_SCROLL_UP_TS,
@@ -73,8 +76,8 @@ enum EditButton
EDIT_BUTTON_SCROLL_NEXT,
EDIT_BUTTON_SCROLL_PREV,
EDIT_BUTTON_LABEL_NEXT, /**< Jump to the start of the next label downward. */
EDIT_BUTTON_LABEL_PREV, /**< Jump to the start of the previous label upward. */
EDIT_BUTTON_SEGMENT_NEXT, /**< Jump to the start of the next segment downward. */
EDIT_BUTTON_SEGMENT_PREV, /**< Jump to the start of the previous segment upward. */
// These are modifiers to EDIT_BUTTON_SCROLL_*.
EDIT_BUTTON_SCROLL_SELECT,
@@ -95,8 +98,12 @@ enum EditButton
EDIT_BUTTON_OPEN_BGCHANGE_LAYER2_MENU,
EDIT_BUTTON_OPEN_COURSE_MENU,
EDIT_BUTTON_OPEN_COURSE_ATTACK_MENU,
EDIT_BUTTON_OPEN_STEP_ATTACK_MENU, /**< Open up the Step Attacks menu. */
EDIT_BUTTON_ADD_STEP_MODS, /**< Add a mod attack to the row. */
EDIT_BUTTON_OPEN_INPUT_HELP,
EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP,
EDIT_BUTTON_BAKE_RANDOM_FROM_SONG_GROUP_AND_GENRE,
@@ -266,9 +273,18 @@ protected:
* This is mainly to allow playing a chart with Song Timing. */
TimingData backupStepTiming;
/**
* @brief Have a backup of the TimingData of the player's choice.
*
* This will be used for copying and pasting as required. */
TimingData clipboardTiming;
/** @brief The current TapNote that would be inserted. */
TapNote m_selectedTap;
/** @brief The type of segment users will jump back and forth between. */
RString currentCycleSegment;
void UpdateTextInfo();
BitmapText m_textInfo; // status information that changes
bool m_bTextInfoNeedsUpdate;
@@ -404,6 +420,7 @@ public:
shift_pauses_forward,
shift_pauses_backward,
convert_pause_to_beat,
convert_delay_to_beat,
undo,
clear_clipboard,
NUM_AREA_MENU_CHOICES
@@ -539,6 +556,8 @@ public:
speed_mode,
scroll,
fake,
copy_timing,
paste_timing,
erase_step_timing,
NUM_TIMING_DATA_INFORMATION_CHOICES
};
+5 -4
View File
@@ -820,11 +820,12 @@ void ScreenGameplay::InitSongQueues()
{
Steps *pSteps = GAMESTATE->m_pCurSteps[ pi->GetStepsAndTrailIndex() ];
pi->m_vpStepsQueue.push_back( pSteps );
if( pi->GetPlayerState()->m_PlayerOptions.GetCurrent().m_fSongAttack != 0 &&
GAMESTATE->m_pCurSong->m_Attacks.size() > 0 )
const PlayerOptions &p = pi->GetPlayerState()->m_PlayerOptions.GetCurrent();
if (p.m_fNoAttack == 0 && p.m_fRandAttack == 0 &&
pSteps->m_Attacks.size() > 0 )
{
pi->m_asModifiersQueue.push_back( GAMESTATE->m_pCurSong->m_Attacks );
pi->m_asModifiersQueue.push_back( pSteps->m_Attacks );
}
else
{
-2
View File
@@ -53,7 +53,6 @@ protected:
Page GetPage( int iChoiceIndex ) const;
Page GetCurrentPage() const;
ThemeMetric<bool> USE_TWO_SCROLLERS;
ThemeMetric<bool> DO_SWITCH_ANYWAYS;
ThemeMetric<bool> DOUBLE_PRESS_TO_SELECT;
ThemeMetric<bool> SHOW_ICON;
@@ -68,7 +67,6 @@ protected:
ThemeMetric<float> PRE_SWITCH_PAGE_SECONDS;
ThemeMetric<float> POST_SWITCH_PAGE_SECONDS;
ThemeMetric1D<RString> OPTION_ORDER;
ThemeMetric1D<RString> OPTION_ORDER2;
ThemeMetric<bool> WRAP_CURSOR;
ThemeMetric<bool> WRAP_SCROLLER;
ThemeMetric<bool> LOOP_SCROLLER;
+4 -2
View File
@@ -41,7 +41,7 @@
* @brief The internal version of the cache for StepMania.
*
* Increment this value to invalidate the current cache. */
const int FILE_CACHE_VERSION = 182;
const int FILE_CACHE_VERSION = 185;
/** @brief How long does a song sample last by default? */
const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f;
@@ -154,7 +154,9 @@ Steps *Song::CreateSteps()
void Song::InitSteps(Steps *pSteps)
{
pSteps->m_Timing = m_SongTiming;
pSteps->m_Timing = this->m_SongTiming;
pSteps->m_sAttackString = this->m_sAttackString;
pSteps->m_Attacks = this->m_Attacks;
}
void Song::GetDisplayBpms( DisplayBpms &AddTo ) const
+1 -1
View File
@@ -20,7 +20,7 @@ void FixupPath( RString &path, const RString &sSongPath );
RString GetSongAssetPath( RString sPath, const RString &sSongPath );
/** @brief The version of the .ssc file format. */
const static float STEPFILE_VERSION_NUMBER = 0.7f;
const static float STEPFILE_VERSION_NUMBER = 0.72f;
/** @brief How many edits for this song can each profile have? */
const int MAX_EDITS_PER_SONG_PER_PROFILE = 15;
+20 -1
View File
@@ -40,6 +40,11 @@ Steps::~Steps()
{
}
bool Steps::HasAttacks() const
{
return !this->m_Attacks.empty();
}
unsigned Steps::GetHash() const
{
if( parent )
@@ -364,6 +369,8 @@ void Steps::CopyFrom( Steps* pSource, StepsType ntTo, float fMusicLengthSeconds
noteData.SetNumTracks( GAMEMAN->GetStepsTypeInfo(ntTo).iNumTracks );
parent = NULL;
m_Timing = pSource->m_Timing;
this->m_Attacks = pSource->m_Attacks;
this->m_sAttackString = pSource->m_sAttackString;
this->SetNoteData( noteData );
this->SetDescription( pSource->GetDescription() );
this->SetDifficulty( pSource->GetDifficulty() );
@@ -463,7 +470,18 @@ public:
DEFINE_METHOD( IsAPlayerEdit, IsAPlayerEdit() )
DEFINE_METHOD( UsesSplitTiming, UsesSplitTiming() )
static int HasSignificantTimingChanges( T* p, lua_State *L ) { lua_pushboolean(L, p->HasSignificantTimingChanges()); return 1; }
static int HasSignificantTimingChanges( T* p, lua_State *L )
{
lua_pushboolean(L, p->HasSignificantTimingChanges());
return 1;
}
static int HasAttacks( T* p, lua_State *L )
{
lua_pushboolean(L, p->HasAttacks());
return 1;
}
static int GetRadarValues( T* p, lua_State *L )
{
@@ -500,6 +518,7 @@ public:
ADD_METHOD( GetHash );
ADD_METHOD( GetMeter );
ADD_METHOD( HasSignificantTimingChanges );
ADD_METHOD( HasAttacks );
ADD_METHOD( GetRadarValues );
ADD_METHOD( GetTimingData );
//ADD_METHOD( GetSMNoteData );
+11
View File
@@ -1,6 +1,7 @@
#ifndef STEPS_H
#define STEPS_H
#include "Attack.h"
#include "GameConstantsAndTypes.h"
#include "PlayerNumber.h"
#include "Grade.h"
@@ -92,6 +93,11 @@ public:
*/
RString GetCredit() const { return Real()->m_sCredit; }
/** @brief The list of attacks. */
AttackArray m_Attacks;
/** @brief The stringified list of attacks. */
vector<RString> m_sAttackString;
void SetFilename( RString fn ) { m_sFilename = fn; }
RString GetFilename() const { return m_sFilename; }
void SetSavedToDisk( bool b ) { DeAutogen(); m_bSavedToDisk = b; }
@@ -128,6 +134,11 @@ public:
* @brief Determine if the Steps have any major timing changes during gameplay.
* @return true if it does, or false otherwise. */
bool HasSignificantTimingChanges() const;
/**
* @brief Determine if the Steps have any attacks.
* @return true if it does, or false otherwise. */
bool HasAttacks() const;
// Lua
void PushSelf( lua_State *L );
+297 -118
View File
@@ -753,6 +753,287 @@ int TimingData::GetTickcountAtRow( int iRow ) const
return m_TickcountSegments[GetTickcountSegmentIndexAtRow( iRow )].GetTicks();
}
float TimingData::GetPreviousBPMSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_BPMSegments.size(); i++ )
{
if( m_BPMSegments[i].GetRow() >= iRow )
{
break;
}
backup = m_BPMSegments[i].GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextBPMSegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_BPMSegments.size(); i++ )
{
if( m_BPMSegments[i].GetRow() <= iRow )
{
continue;
}
return m_BPMSegments[i].GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousStopSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_StopSegments.size(); i++ )
{
const StopSegment &s = m_StopSegments[i];
if( s.GetRow() >= iRow )
{
break;
}
if (!s.GetDelay())
backup = s.GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextStopSegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_StopSegments.size(); i++ )
{
const StopSegment &s = m_StopSegments[i];
if( s.GetRow() <= iRow )
{
continue;
}
if (!s.GetDelay())
return s.GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousDelaySegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_StopSegments.size(); i++ )
{
const StopSegment &s = m_StopSegments[i];
if( s.GetRow() >= iRow )
{
break;
}
if (s.GetDelay())
backup = s.GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextDelaySegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_StopSegments.size(); i++ )
{
const StopSegment &s = m_StopSegments[i];
if( s.GetRow() <= iRow )
{
continue;
}
if (s.GetDelay())
return s.GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousTimeSignatureSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ )
{
if( m_vTimeSignatureSegments[i].GetRow() >= iRow )
{
break;
}
backup = m_vTimeSignatureSegments[i].GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextTimeSignatureSegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ )
{
if( m_vTimeSignatureSegments[i].GetRow() <= iRow )
{
continue;
}
return m_vTimeSignatureSegments[i].GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousTickcountSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_TickcountSegments.size(); i++ )
{
if( m_TickcountSegments[i].GetRow() >= iRow )
{
break;
}
backup = m_TickcountSegments[i].GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextTickcountSegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_TickcountSegments.size(); i++ )
{
if( m_TickcountSegments[i].GetRow() <= iRow )
{
continue;
}
return m_TickcountSegments[i].GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousComboSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_ComboSegments.size(); i++ )
{
if( m_ComboSegments[i].GetRow() >= iRow )
{
break;
}
backup = m_ComboSegments[i].GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextComboSegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_ComboSegments.size(); i++ )
{
if( m_ComboSegments[i].GetRow() <= iRow )
{
continue;
}
return m_ComboSegments[i].GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousWarpSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_WarpSegments.size(); i++ )
{
if( m_WarpSegments[i].GetRow() >= iRow )
{
break;
}
backup = m_WarpSegments[i].GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextWarpSegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_WarpSegments.size(); i++ )
{
if( m_WarpSegments[i].GetRow() <= iRow )
{
continue;
}
return m_WarpSegments[i].GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousFakeSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_FakeSegments.size(); i++ )
{
if( m_FakeSegments[i].GetRow() >= iRow )
{
break;
}
backup = m_FakeSegments[i].GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextFakeSegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_FakeSegments.size(); i++ )
{
if( m_FakeSegments[i].GetRow() <= iRow )
{
continue;
}
return m_FakeSegments[i].GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousSpeedSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_SpeedSegments.size(); i++ )
{
if( m_SpeedSegments[i].GetRow() >= iRow )
{
break;
}
backup = m_SpeedSegments[i].GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextSpeedSegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_SpeedSegments.size(); i++ )
{
if( m_SpeedSegments[i].GetRow() <= iRow )
{
continue;
}
return m_SpeedSegments[i].GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousScrollSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
for (unsigned i = 0; i < m_ScrollSegments.size(); i++ )
{
if( m_ScrollSegments[i].GetRow() >= iRow )
{
break;
}
backup = m_ScrollSegments[i].GetBeat();
}
return (backup > -1) ? backup : NoteRowToBeat(iRow);
}
float TimingData::GetNextScrollSegmentBeatAtRow( int iRow ) const
{
for (unsigned i = 0; i < m_ScrollSegments.size(); i++ )
{
if( m_ScrollSegments[i].GetRow() <= iRow )
{
continue;
}
return m_ScrollSegments[i].GetBeat();
}
return NoteRowToBeat(iRow);
}
float TimingData::GetPreviousLabelSegmentBeatAtRow( int iRow ) const
{
float backup = -1;
@@ -1026,149 +1307,48 @@ void TimingData::ScaleRegion( float fScale, int iStartIndex, int iEndIndex, bool
ASSERT( iStartIndex >= 0 );
ASSERT( iStartIndex < iEndIndex );
int length = iEndIndex - iStartIndex;
int newLength = lrintf( fScale * length );
for ( unsigned i = 0; i < m_BPMSegments.size(); i++ )
{
BPMSegment &b = m_BPMSegments[i];
const int iSegStart = b.GetRow();
if( iSegStart < iStartIndex )
continue;
else if( iSegStart > iEndIndex )
b.SetRow( b.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) ) );
else
b.SetRow( lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex );
}
m_BPMSegments[i].Scale( iStartIndex, length, newLength );
for( unsigned i = 0; i < m_StopSegments.size(); i++ )
{
StopSegment &s = m_StopSegments[i];
const int iSegStartRow = s.GetRow();
if( iSegStartRow < iStartIndex )
continue;
else if( iSegStartRow > iEndIndex )
s.SetRow(s.GetRow() + lrintf((iEndIndex - iStartIndex) * (fScale - 1)));
else
s.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex);
}
m_StopSegments[i].Scale( iStartIndex, length, newLength );
for( unsigned i = 0; i < m_vTimeSignatureSegments.size(); i++ )
{
TimeSignatureSegment &t = m_vTimeSignatureSegments[i];
const int iSegStartRow = t.GetRow();
if( iSegStartRow < iStartIndex )
continue;
else if( iSegStartRow > iEndIndex )
t.SetRow(t.GetRow() + lrintf((iEndIndex - iStartIndex) * (fScale - 1)));
else
t.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex);
}
m_vTimeSignatureSegments[i].Scale( iStartIndex, length, newLength );
for( unsigned i = 0; i < m_WarpSegments.size(); i++ )
{
WarpSegment &w = m_WarpSegments[i];
const int iSegStartRow = w.GetRow();
const int iSegEndRow = iSegStartRow + BeatToNoteRow( w.GetLength() );
if( iSegEndRow >= iStartIndex )
{
if( iSegEndRow > iEndIndex )
w.SetLength(w.GetLength() +
NoteRowToBeat(lrintf((iEndIndex - iStartIndex) * (fScale - 1))));
else
w.SetLength(NoteRowToBeat(lrintf((iSegEndRow - iStartIndex) * fScale)));
}
if( iSegStartRow < iStartIndex )
continue;
else if( iSegStartRow > iEndIndex )
w.SetRow(w.GetRow() + lrintf((iEndIndex - iStartIndex) * (fScale - 1)));
else
w.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex);
}
m_WarpSegments[i].Scale( iStartIndex, length, newLength );
for ( unsigned i = 0; i < m_TickcountSegments.size(); i++ )
{
TickcountSegment &t = m_TickcountSegments[i];
const int iSegStart = t.GetRow();
if( iSegStart < iStartIndex )
continue;
else if( iSegStart > iEndIndex )
t.SetRow(t.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) ));
else
t.SetRow(lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex);
}
m_TickcountSegments[i].Scale( iStartIndex, length, newLength );
for ( unsigned i = 0; i < m_ComboSegments.size(); i++ )
{
ComboSegment &c = m_ComboSegments[i];
const int iSegStart = c.GetRow();
if( iSegStart < iStartIndex )
continue;
else if( iSegStart > iEndIndex )
c.SetRow(c.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) ));
else
c.SetRow(lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex);
}
m_ComboSegments[i].Scale( iStartIndex, length, newLength );
for ( unsigned i = 0; i < m_LabelSegments.size(); i++ )
{
LabelSegment &l = m_LabelSegments[i];
const int iSegStart = l.GetRow();
if( iSegStart < iStartIndex )
continue;
else if( iSegStart > iEndIndex )
l.SetRow(l.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) ));
else
l.SetRow(lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex);
}
m_LabelSegments[i].Scale( iStartIndex, length, newLength );
for ( unsigned i = 0; i < m_SpeedSegments.size(); i++ )
{
SpeedSegment &s = m_SpeedSegments[i];
const int iSegStart = s.GetRow();
if( iSegStart < iStartIndex )
continue;
else if( iSegStart > iEndIndex )
s.SetRow(s.GetRow() + lrintf( (iEndIndex - iStartIndex) * (fScale - 1) ));
else
s.SetRow(lrintf( (iSegStart - iStartIndex) * fScale ) + iStartIndex);
s.Scale( iStartIndex, length, newLength );
if (s.GetUnit() == 0) // beats
s.SetLength(s.GetLength() * fScale);
}
for( unsigned i = 0; i < m_FakeSegments.size(); i++ )
{
FakeSegment &f = m_FakeSegments[i];
const int iSegStartRow = f.GetRow();
const int iSegEndRow = iSegStartRow + BeatToNoteRow( f.GetLength() );
if( iSegEndRow >= iStartIndex )
{
if( iSegEndRow > iEndIndex )
f.SetLength(f.GetLength()
+ NoteRowToBeat(lrintf((iEndIndex - iStartIndex) * (fScale - 1))));
else
f.SetLength(NoteRowToBeat(lrintf((iSegEndRow - iStartIndex) * fScale)));
}
if( iSegStartRow < iStartIndex )
continue;
else if( iSegStartRow > iEndIndex )
f.SetRow(f.GetRow()
+ lrintf((iEndIndex - iStartIndex) * (fScale - 1)));
else
f.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex);
}
m_FakeSegments[i].Scale( iStartIndex, length, newLength );
for( unsigned i = 0; i < m_ScrollSegments.size(); i++ )
{
ScrollSegment &s = m_ScrollSegments[i];
const int iSegStartRow = s.GetRow();
if( iSegStartRow < iStartIndex )
continue;
else if( iSegStartRow > iEndIndex )
s.SetRow(s.GetRow() + lrintf((iEndIndex - iStartIndex) * (fScale - 1)));
else
s.SetRow(lrintf((iSegStartRow - iStartIndex) * fScale) + iStartIndex);
}
m_ScrollSegments[i].Scale( iStartIndex, length, newLength );
// adjust BPM changes to preserve timing
if( bAdjustBPM )
{
int iNewEndIndex = lrintf( (iEndIndex - iStartIndex) * fScale ) + iStartIndex;
int iNewEndIndex = iStartIndex + newLength;
float fEndBPMBeforeScaling = GetBPMAtRow(iNewEndIndex);
// adjust BPM changes "between" iStartIndex and iNewEndIndex
@@ -1186,7 +1366,6 @@ void TimingData::ScaleRegion( float fScale, int iStartIndex, int iEndIndex, bool
// set BPM at iStartIndex and iNewEndIndex.
SetBPMAtRow( iStartIndex, GetBPMAtRow(iStartIndex) * fScale );
SetBPMAtRow( iNewEndIndex, fEndBPMBeforeScaling );
}
}
+327 -2
View File
@@ -83,6 +83,38 @@ public:
*/
void AddBPMSegment( const BPMSegment &seg );
/**
* @brief Retrieve the next beat that contains a BPMSegment.
* @param iRow the present row.
* @return the next beat with a BPMSegment, or fBeat if there is none ahead.
*/
float GetNextBPMSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a BPMSegment.
* @param fBeat the present beat.
* @return the next beat with a BPMSegment, or fBeat if there is none ahead.
*/
float GetNextBPMSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextBPMSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a BPMSegment.
* @param iRow the present row.
* @return the previous beat with a BPMSegment, or fBeat if there is none prior.
*/
float GetPreviousBPMSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a BPMSegment.
* @param fBeat the present beat.
* @return the previous beat with a BPMSegment, or fBeat if there is none prior.
*/
float GetPreviousBPMSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousBPMSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the Stop/Delay at the given row.
* @param iNoteRow the row in question.
@@ -249,6 +281,68 @@ public:
*/
void AddStopSegment( const StopSegment &seg );
/**
* @brief Retrieve the next beat that contains a StopSegment.
* @param iRow the present row.
* @return the next beat with a StopSegment, or fBeat if there is none ahead.
*/
float GetNextStopSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a StopSegment.
* @param fBeat the present beat.
* @return the next beat with a StopSegment, or fBeat if there is none ahead.
*/
float GetNextStopSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextStopSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a StopSegment.
* @param iRow the present row.
* @return the previous beat with a StopSegment, or fBeat if there is none prior.
*/
float GetPreviousStopSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a StopSegment.
* @param fBeat the present beat.
* @return the previous beat with a StopSegment, or fBeat if there is none prior.
*/
float GetPreviousStopSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousStopSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the next beat that contains a DelaySegment.
* @param iRow the present row.
* @return the next beat with a DelaySegment, or fBeat if there is none ahead.
*/
float GetNextDelaySegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a DelaySegment.
* @param fBeat the present beat.
* @return the next beat with a DelaySegment, or fBeat if there is none ahead.
*/
float GetNextDelaySegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextDelaySegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a DelaySegment.
* @param iRow the present row.
* @return the previous beat with a DelaySegment, or fBeat if there is none prior.
*/
float GetPreviousDelaySegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a DelaySegment.
* @param fBeat the present beat.
* @return the previous beat with a DelaySegment, or fBeat if there is none prior.
*/
float GetPreviousDelaySegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousDelaySegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the Time Signature's numerator at the given row.
* @param iNoteRow the row in question.
@@ -345,6 +439,39 @@ public:
* @param iRow The row you start on.
* @return the beat you warp to.
*/
/**
* @brief Retrieve the next beat that contains a TimeSignatureSegment.
* @param iRow the present row.
* @return the next beat with a TimeSignatureSegment, or fBeat if there is none ahead.
*/
float GetNextTimeSignatureSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a TimeSignatureSegment.
* @param fBeat the present beat.
* @return the next beat with a TimeSignatureSegment, or fBeat if there is none ahead.
*/
float GetNextTimeSignatureSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextTimeSignatureSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a TimeSignatureSegment.
* @param iRow the present row.
* @return the previous beat with a TimeSignatureSegment, or fBeat if there is none prior.
*/
float GetPreviousTimeSignatureSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a TimeSignatureSegment.
* @param fBeat the present beat.
* @return the previous beat with a TimeSignatureSegment, or fBeat if there is none prior.
*/
float GetPreviousTimeSignatureSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousTimeSignatureSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
float GetWarpAtRow( int iRow ) const;
/**
* @brief Determine the beat to warp to.
@@ -405,6 +532,39 @@ public:
* @param seg the new WarpSegment.
*/
void AddWarpSegment( const WarpSegment &seg );
/**
* @brief Retrieve the next beat that contains a WarpSegment.
* @param iRow the present row.
* @return the next beat with a WarpSegment, or fBeat if there is none ahead.
*/
float GetNextWarpSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a WarpSegment.
* @param fBeat the present beat.
* @return the next beat with a WarpSegment, or fBeat if there is none ahead.
*/
float GetNextWarpSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextWarpSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a WarpSegment.
* @param iRow the present row.
* @return the previous beat with a WarpSegment, or fBeat if there is none prior.
*/
float GetPreviousWarpSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a WarpSegment.
* @param fBeat the present beat.
* @return the previous beat with a WarpSegment, or fBeat if there is none prior.
*/
float GetPreviousWarpSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousWarpSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the Tickcount at the given row.
* @param iNoteRow the row in question.
@@ -459,6 +619,38 @@ public:
*/
void AddTickcountSegment( const TickcountSegment &seg );
/**
* @brief Retrieve the next beat that contains a TickcountSegment.
* @param iRow the present row.
* @return the next beat with a TickcountSegment, or fBeat if there is none ahead.
*/
float GetNextTickcountSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a TickcountSegment.
* @param fBeat the present beat.
* @return the next beat with a TickcountSegment, or fBeat if there is none ahead.
*/
float GetNextTickcountSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextTickcountSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a TickcountSegment.
* @param iRow the present row.
* @return the previous beat with a TickcountSegment, or fBeat if there is none prior.
*/
float GetPreviousTickcountSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a TickcountSegment.
* @param fBeat the present beat.
* @return the previous beat with a TickcountSegment, or fBeat if there is none prior.
*/
float GetPreviousTickcountSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousTickcountSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the Combo at the given row.
* @param iNoteRow the row in question.
@@ -513,6 +705,38 @@ public:
*/
void AddComboSegment( const ComboSegment &seg );
/**
* @brief Retrieve the next beat that contains a ComboSegment.
* @param iRow the present row.
* @return the next beat with a ComboSegment, or fBeat if there is none ahead.
*/
float GetNextComboSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a ComboSegment.
* @param fBeat the present beat.
* @return the next beat with a ComboSegment, or fBeat if there is none ahead.
*/
float GetNextComboSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextComboSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a ComboSegment.
* @param iRow the present row.
* @return the previous beat with a ComboSegment, or fBeat if there is none prior.
*/
float GetPreviousComboSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a ComboSegment.
* @param fBeat the present beat.
* @return the previous beat with a ComboSegment, or fBeat if there is none prior.
*/
float GetPreviousComboSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousComboSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the Label at the given row.
* @param iNoteRow the row in question.
@@ -578,7 +802,10 @@ public:
* @param fBeat the present beat.
* @return the previous beat with a LabelSegment, or fBeat if there is none prior.
*/
float GetPreviousLabelSegmentBeatAtBeat( float fBeat ) const { return GetPreviousLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) ); }
float GetPreviousLabelSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Determine if the requisite label already exists.
@@ -597,7 +824,10 @@ public:
* @param fBeat the present beat.
* @return the next beat with a LabelSegment, or fBeat if there is none ahead.
*/
float GetNextLabelSegmentBeatAtBeat( float fBeat ) const { return GetNextLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) ); }
float GetNextLabelSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextLabelSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
@@ -720,6 +950,38 @@ public:
float GetDisplayedSpeedPercent( float fBeat, float fMusicSeconds ) const;
/**
* @brief Retrieve the next beat that contains a SpeedSegment.
* @param iRow the present row.
* @return the next beat with a SpeedSegment, or fBeat if there is none ahead.
*/
float GetNextSpeedSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a SpeedSegment.
* @param fBeat the present beat.
* @return the next beat with a SpeedSegment, or fBeat if there is none ahead.
*/
float GetNextSpeedSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextSpeedSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a SpeedSegment.
* @param iRow the present row.
* @return the previous beat with a SpeedSegment, or fBeat if there is none prior.
*/
float GetPreviousSpeedSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a SpeedSegment.
* @param fBeat the present beat.
* @return the previous beat with a SpeedSegment, or fBeat if there is none prior.
*/
float GetPreviousSpeedSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousSpeedSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the scrolling factor at the given row.
* @param iNoteRow the row in question.
@@ -778,6 +1040,37 @@ public:
*/
void AddScrollSegment( const ScrollSegment &seg );
/**
* @brief Retrieve the next beat that contains a ScrollSegment.
* @param iRow the present row.
* @return the next beat with a ScrollSegment, or fBeat if there is none ahead.
*/
float GetNextScrollSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a ScrollSegment.
* @param fBeat the present beat.
* @return the next beat with a ScrollSegment, or fBeat if there is none ahead.
*/
float GetNextScrollSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextScrollSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a ScrollSegment.
* @param iRow the present row.
* @return the previous beat with a ScrollSegment, or fBeat if there is none prior.
*/
float GetPreviousScrollSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a ScrollSegment.
* @param fBeat the present beat.
* @return the previous beat with a ScrollSegment, or fBeat if there is none prior.
*/
float GetPreviousScrollSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousScrollSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Determine when the fakes end.
@@ -845,6 +1138,38 @@ public:
*/
void AddFakeSegment( const FakeSegment &seg );
/**
* @brief Retrieve the next beat that contains a FakeSegment.
* @param iRow the present row.
* @return the next beat with a FakeSegment, or fBeat if there is none ahead.
*/
float GetNextFakeSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a FakeSegment.
* @param fBeat the present beat.
* @return the next beat with a FakeSegment, or fBeat if there is none ahead.
*/
float GetNextFakeSegmentBeatAtBeat( float fBeat ) const
{
return this->GetNextFakeSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Retrieve the previous beat that contains a FakeSegment.
* @param iRow the present row.
* @return the previous beat with a FakeSegment, or fBeat if there is none prior.
*/
float GetPreviousFakeSegmentBeatAtRow( int iRow ) const;
/**
* @brief Retrieve the previous beat that contains a FakeSegment.
* @param fBeat the present beat.
* @return the previous beat with a FakeSegment, or fBeat if there is none prior.
*/
float GetPreviousFakeSegmentBeatAtBeat( float fBeat ) const
{
return this->GetPreviousFakeSegmentBeatAtRow( BeatToNoteRow(fBeat) );
}
/**
* @brief Determine if this notes on this row can be judged.
* @param row the row to focus on.
+27 -2
View File
@@ -5,7 +5,6 @@
BaseTimingSegment::~BaseTimingSegment() {}
void BaseTimingSegment::SetRow(const int s)
{
this->startingRow = s;
@@ -26,6 +25,11 @@ float BaseTimingSegment::GetBeat() const
return NoteRowToBeat(GetRow());
}
void BaseTimingSegment::Scale( int start, int length, int newLength )
{
SetRow( ScalePosition( start, length, newLength, GetRow() ) );
}
/* ======================================================
Here comes the actual timing segments implementation!! */
@@ -40,6 +44,16 @@ void FakeSegment::SetLength(const float b)
this->lengthBeats = b;
}
void FakeSegment::Scale( int start, int length, int newLength )
{
float startBeat = GetBeat();
float endBeat = startBeat + GetLength();
float newStartBeat = ScalePosition( NoteRowToBeat(start), NoteRowToBeat(length), NoteRowToBeat(newLength), startBeat );
float newEndBeat = ScalePosition( NoteRowToBeat(start), NoteRowToBeat(length), NoteRowToBeat(newLength), endBeat );
SetLength( newEndBeat - newStartBeat );
TimingSegment<FakeSegment>::Scale( start, length, newLength );
}
bool FakeSegment::operator<( const FakeSegment &other ) const
{
LTCOMPARE(GetRow());
@@ -60,8 +74,19 @@ void WarpSegment::SetLength(const float b)
this->lengthBeats = b;
}
void WarpSegment::Scale( int start, int length, int newLength )
{
// XXX: this function is duplicated, there should be a better way
float startBeat = GetBeat();
float endBeat = startBeat + GetLength();
float newStartBeat = ScalePosition( NoteRowToBeat(start), NoteRowToBeat(length), NoteRowToBeat(newLength), startBeat );
float newEndBeat = ScalePosition( NoteRowToBeat(start), NoteRowToBeat(length), NoteRowToBeat(newLength), endBeat );
SetLength( newEndBeat - newStartBeat );
TimingSegment<WarpSegment>::Scale( start, length, newLength );
}
bool WarpSegment::operator<( const WarpSegment &other ) const
{
{
LTCOMPARE(GetRow());
LTCOMPARE(GetLength());
return false;
+12
View File
@@ -27,6 +27,14 @@ struct BaseTimingSegment
virtual ~BaseTimingSegment();
/**
* @brief Scales itself.
* @param start Starting row
* @param length Length in rows
* @param newLength The new length in rows
*/
virtual void Scale( int start, int length, int newLength );
/**
* @brief Set the starting row of the BaseTimingSegment.
*
@@ -177,6 +185,8 @@ struct FakeSegment : public TimingSegment<FakeSegment>
* @param b the length in beats. */
void SetLength(const float b);
void Scale( int start, int length, int newLength );
/**
* @brief Compares two FakeSegments to see if one is less than the other.
* @param other the other FakeSegment to compare to.
@@ -236,6 +246,8 @@ struct WarpSegment : public TimingSegment<WarpSegment>
* @param b the length in beats. */
void SetLength(const float b);
void Scale( int start, int length, int newLength );
/*
* @brief Compares two WarpSegments to see if one is less than the other.
* @param other the other WarpSegment to compare to.
+126 -6
View File
@@ -7,6 +7,7 @@
#include "RageUtil.h"
#include "SongManager.h"
#include "GameState.h"
#include "GameConstantsAndTypes.h" // StepsTypeToString
#include "ProfileManager.h"
#include "Profile.h"
#include "ThemeManager.h"
@@ -24,6 +25,8 @@ UnlockManager* UNLOCKMAN = NULL; // global and accessable from anywhere in our p
#define UNLOCK(x) THEME->GetMetricR("UnlockManager", ssprintf("Unlock%sCommand",x.c_str()));
static ThemeMetric<bool> AUTO_LOCK_CHALLENGE_STEPS( "UnlockManager", "AutoLockChallengeSteps" );
static ThemeMetric<bool> AUTO_LOCK_EDIT_STEPS( "UnlockManager", "AutoLockEditSteps" );
static ThemeMetric<bool> SONGS_NOT_ADDITIONAL( "UnlockManager", "SongsNotAdditional" );
static const char *UnlockRequirementNames[] =
{
@@ -44,6 +47,7 @@ static const char *UnlockRewardTypeNames[] =
{
"Song",
"Steps",
"StepsType",
"Course",
"Modifier",
};
@@ -171,6 +175,18 @@ bool UnlockManager::StepsIsLocked( const Song *pSong, const Steps *pSteps ) cons
return p->IsLocked();
}
bool UnlockManager::StepsTypeIsLocked(const Song *pSong, const Steps *pSteps, const StepsType *pSType) const
{
if( !PREFSMAN->m_bUseUnlockSystem )
return false;
const UnlockEntry *p = FindStepsType( pSong, pSteps, pSType );
if( p == NULL )
return false;
return p->IsLocked();
}
bool UnlockManager::ModifierIsLocked( const RString &sOneMod ) const
{
if( !PREFSMAN->m_bUseUnlockSystem )
@@ -200,6 +216,19 @@ const UnlockEntry *UnlockManager::FindSteps( const Song *pSong, const Steps *pSt
return NULL;
}
const UnlockEntry *UnlockManager::FindStepsType(const Song *pSong,
const Steps *pSteps,
const StepsType *pSType ) const
{
ASSERT( pSong && pSteps && pSType );
FOREACH_CONST( UnlockEntry, m_UnlockEntries, e )
if(e->m_Song.ToSong() == pSong &&
e->m_dc == pSteps->GetDifficulty() &&
e->m_StepsType == pSteps->m_StepsType)
return &(*e);
return NULL;
}
const UnlockEntry *UnlockManager::FindCourse( const Course *pCourse ) const
{
FOREACH_CONST( UnlockEntry, m_UnlockEntries, e )
@@ -309,6 +338,11 @@ bool UnlockEntry::IsValid() const
case UnlockRewardType_Steps:
return m_Song.IsValid() && m_dc != Difficulty_Invalid;
case UnlockRewardType_Steps_Type:
{
return m_Song.IsValid() && m_dc != Difficulty_Invalid && m_StepsType != StepsType_Invalid;
}
case UnlockRewardType_Course:
return m_Course.IsValid();
@@ -323,7 +357,9 @@ bool UnlockEntry::IsValid() const
UnlockEntryStatus UnlockEntry::GetUnlockEntryStatus() const
{
if( !m_sEntryID.empty() && PROFILEMAN->GetMachineProfile()->m_UnlockedEntryIDs.find(m_sEntryID) != PROFILEMAN->GetMachineProfile()->m_UnlockedEntryIDs.end() )
set<RString> &ids = PROFILEMAN->GetMachineProfile()->m_UnlockedEntryIDs;
if(!m_sEntryID.empty() &&
ids.find(m_sEntryID) != ids.end() )
return UnlockEntryStatus_Unlocked;
float fScores[NUM_UnlockRequirement];
@@ -352,6 +388,21 @@ UnlockEntryStatus UnlockEntry::GetUnlockEntryStatus() const
if( PROFILEMAN->GetMachineProfile()->HasPassedSteps(pSong, *s) )
return UnlockEntryStatus_RequirementsMet;
}
if (m_bRequirePassChallengeSteps && m_Song.IsValid())
{
Song *pSong = m_Song.ToSong();
vector<Steps*> vp;
SongUtil::GetSteps(pSong,
vp,
StepsType_Invalid,
Difficulty_Challenge);
FOREACH_CONST(Steps*, vp, s)
{
if (PROFILEMAN->GetMachineProfile()->HasPassedSteps(pSong, *s))
return UnlockEntryStatus_RequirementsMet;
}
}
return UnlockEntryStatus_RequrementsNotMet;
}
@@ -367,10 +418,16 @@ RString UnlockEntry::GetDescription() const
case UnlockRewardType_Song:
return pSong ? pSong->GetDisplayFullTitle() : "";
case UnlockRewardType_Steps:
{
StepsType st = GAMEMAN->GetHowToPlayStyleForGame( GAMESTATE->m_pCurGame )->m_StepsType; // TODO: Is this the best thing we can do here?
return (pSong ? pSong->GetDisplayFullTitle() : "") + ", " + CustomDifficultyToLocalizedString( GetCustomDifficulty(st, m_dc, CourseType_Invalid) );
}
{
StepsType st = GAMEMAN->GetHowToPlayStyleForGame( GAMESTATE->m_pCurGame )->m_StepsType; // TODO: Is this the best thing we can do here?
return (pSong ? pSong->GetDisplayFullTitle() : "") + ", " + CustomDifficultyToLocalizedString( GetCustomDifficulty(st, m_dc, CourseType_Invalid) );
}
case UnlockRewardType_Steps_Type:
{
RString ret = (pSong ? pSong->GetDisplayFullTitle() : "");
ret += "," + CustomDifficultyToLocalizedString( GetCustomDifficulty(m_StepsType, m_dc, CourseType_Invalid) );
return ret + "," + StringConversion::ToString(m_StepsType); // yeah, bit strange.
}
case UnlockRewardType_Course:
return m_Course.IsValid() ? m_Course.ToCourse()->GetDisplayFullTitle() : "";
case UnlockRewardType_Modifier:
@@ -388,6 +445,7 @@ RString UnlockEntry::GetBannerFile() const
return "";
case UnlockRewardType_Song:
case UnlockRewardType_Steps:
case UnlockRewardType_Steps_Type:
return pSong ? pSong->GetBannerPath() : "";
case UnlockRewardType_Course:
return m_Course.ToCourse() ? m_Course.ToCourse()->GetBannerPath() : "";
@@ -406,6 +464,7 @@ RString UnlockEntry::GetBackgroundFile() const
return "";
case UnlockRewardType_Song:
case UnlockRewardType_Steps:
case UnlockRewardType_Steps_Type:
return pSong ? pSong->GetBackgroundPath() : "";
case UnlockRewardType_Course:
return "";
@@ -462,7 +521,7 @@ void UnlockManager::Load()
if( SongUtil::GetOneSteps(*s, StepsType_Invalid, Difficulty_Challenge) == NULL )
continue;
if( SONGMAN->WasLoadedFromAdditionalSongs(*s) )
if( SONGS_NOT_ADDITIONAL && SONGMAN->WasLoadedFromAdditionalSongs(*s) )
continue;
UnlockEntry ue;
@@ -474,6 +533,33 @@ void UnlockManager::Load()
m_UnlockEntries.push_back( ue );
}
}
if (AUTO_LOCK_EDIT_STEPS)
{
FOREACH_CONST( Song*, SONGMAN->GetAllSongs(), s )
{
// no challenge steps to play: skip.
if (SongUtil::GetOneSteps(*s, StepsType_Invalid, Difficulty_Challenge) == NULL)
continue;
// no edit steps to unlock: skip.
if (SongUtil::GetOneSteps(*s, StepsType_Invalid, Difficulty_Edit) == NULL)
continue;
// don't add additional songs.
if (SONGS_NOT_ADDITIONAL && SONGMAN->WasLoadedFromAdditionalSongs(*s))
continue;
UnlockEntry ue;
ue.m_sEntryID = "_edit_" + (*s)->GetSongDir();
ue.m_Type = UnlockRewardType_Steps;
ue.m_cmd.Load( (*s)->m_sGroupName+"/"+(*s)->GetTranslitFullTitle()+",edit" );
ue.m_bRequirePassChallengeSteps = true;
m_UnlockEntries.push_back(ue);
}
}
// Make sure that we don't have duplicate unlock IDs. This can cause problems
// with UnlockCelebrate and with codes.
@@ -507,6 +593,30 @@ void UnlockManager::Load()
}
break;
case UnlockRewardType_Steps_Type:
{
e->m_Song.FromSong( SONGMAN->FindSong( e->m_cmd.GetArg(0).s ) );
if( !e->m_Song.IsValid() )
{
LOG->Warn( "Unlock: Cannot find song matching \"%s\"", e->m_cmd.GetArg(0).s.c_str() );
break;
}
e->m_dc = StringToDifficulty( e->m_cmd.GetArg(1).s );
if( e->m_dc == Difficulty_Invalid )
{
LOG->Warn( "Unlock: Invalid difficulty \"%s\"", e->m_cmd.GetArg(1).s.c_str() );
break;
}
e->m_StepsType = GAMEMAN->StringToStepsType(e->m_cmd.GetArg(2).s);
if (e->m_StepsType == StepsType_Invalid)
{
LOG->Warn( "Unlock: Invalid steps type \"%s\"", e->m_cmd.GetArg(2).s.c_str() );
break;
}
break;
}
case UnlockRewardType_Course:
e->m_Course.FromCourse( SONGMAN->FindCourse(e->m_cmd.GetArg(0).s) );
if( !e->m_Course.IsValid() )
@@ -529,6 +639,8 @@ void UnlockManager::Load()
str += ssprintf( "%s = %f; ", UnlockRequirementToString(j).c_str(), e->m_fRequirement[j] );
if( e->m_bRequirePassHardSteps )
str += "RequirePassHardSteps; ";
if (e->m_bRequirePassChallengeSteps)
str += "RequirePassChallengeSteps; ";
str += ssprintf( "entryID = %s ", e->m_sEntryID.c_str() );
str += e->IsLocked()? "locked":"unlocked";
@@ -671,6 +783,11 @@ public:
static int GetUnlockRewardType( T* p, lua_State *L ) { lua_pushnumber(L, p->m_Type ); return 1; }
static int GetRequirement( T* p, lua_State *L ) { UnlockRequirement i = Enum::Check<UnlockRequirement>( L, 1 ); lua_pushnumber(L, p->m_fRequirement[i] ); return 1; }
static int GetRequirePassHardSteps( T* p, lua_State *L ){ lua_pushboolean(L, p->m_bRequirePassHardSteps); return 1; }
static int GetRequirePassChallengeSteps( T* p, lua_State *L )
{
lua_pushboolean(L, p->m_bRequirePassChallengeSteps);
return 1;
}
static int GetSong( T* p, lua_State *L )
{
Song *pSong = p->m_Song.ToSong();
@@ -701,6 +818,7 @@ public:
static int song( T* p, lua_State *L ) { GetArgs( p, L ); p->m_Type = UnlockRewardType_Song; return 0; }
static int steps( T* p, lua_State *L ) { GetArgs( p, L ); p->m_Type = UnlockRewardType_Steps; return 0; }
static int steps_type(T* p, lua_State *L) { GetArgs(p, L); p->m_Type = UnlockRewardType_Steps_Type; return 0; }
static int course( T* p, lua_State *L ) { GetArgs( p, L ); p->m_Type = UnlockRewardType_Course; return 0; }
static int mod( T* p, lua_State *L ) { GetArgs( p, L ); p->m_Type = UnlockRewardType_Modifier; return 0; }
static int code( T* p, lua_State *L ) { p->m_sEntryID = SArg(1); return 0; }
@@ -722,10 +840,12 @@ public:
ADD_METHOD( GetUnlockRewardType );
ADD_METHOD( GetRequirement );
ADD_METHOD( GetRequirePassHardSteps );
ADD_METHOD( GetRequirePassChallengeSteps );
ADD_METHOD( GetSong );
ADD_METHOD( GetCourse );
ADD_METHOD( song );
ADD_METHOD( steps );
ADD_METHOD( steps_type );
ADD_METHOD( course );
ADD_METHOD( mod );
ADD_METHOD( code );
+22 -13
View File
@@ -16,16 +16,17 @@ class Steps;
class Profile;
struct lua_State;
/** @brief What is needed to unlock an item? */
enum UnlockRequirement
{
UnlockRequirement_ArcadePoints,
UnlockRequirement_DancePoints,
UnlockRequirement_SongPoints,
UnlockRequirement_ExtraCleared,
UnlockRequirement_ExtraFailed,
UnlockRequirement_Toasties,
UnlockRequirement_StagesCleared,
UnlockRequirement_NumUnlocked,
UnlockRequirement_ArcadePoints, /**< Get a certain number of arcade points. */
UnlockRequirement_DancePoints, /**< Get a certain number of dance points. */
UnlockRequirement_SongPoints, /**< Get a certain number of song points. */
UnlockRequirement_ExtraCleared, /**< Pass the extra stage. */
UnlockRequirement_ExtraFailed, /**< Fail the extra stage. */
UnlockRequirement_Toasties, /**< Get a number of toasties. */
UnlockRequirement_StagesCleared, /**< Clear a number of stages. */
UnlockRequirement_NumUnlocked, /**< Have a number of locked items already unlocked. */
NUM_UnlockRequirement,
UnlockRequirement_Invalid,
};
@@ -33,10 +34,11 @@ LuaDeclareType( UnlockRequirement );
enum UnlockRewardType {
UnlockRewardType_Song,
UnlockRewardType_Steps,
UnlockRewardType_Course,
UnlockRewardType_Modifier,
UnlockRewardType_Song, /**< A song is unlocked. */
UnlockRewardType_Steps, /**< A step pattern for all styles is unlocked. */
UnlockRewardType_Steps_Type, /**< A step pattern for a specific style is unlocked. */
UnlockRewardType_Course, /**< A course is unlocked. */
UnlockRewardType_Modifier, /**< A modifier is unlocked. */
NUM_UnlockRewardType,
UnlockRewardType_Invalid
};
@@ -60,7 +62,8 @@ public:
* if not specified. */
UnlockEntry(): m_Type(UnlockRewardType_Invalid), m_cmd(),
m_Song(), m_dc(Difficulty_Invalid), m_Course(),
m_bRequirePassHardSteps(false), m_bRoulette(false),
m_StepsType(StepsType_Invalid), m_bRequirePassHardSteps(false),
m_bRequirePassChallengeSteps(false), m_bRoulette(false),
m_sEntryID(RString(""))
{
ZERO( m_fRequirement );
@@ -74,9 +77,13 @@ public:
SongID m_Song;
Difficulty m_dc;
CourseID m_Course;
StepsType m_StepsType;
float m_fRequirement[NUM_UnlockRequirement]; // unlocked if any of of these are met
/** @brief Must the hard steps be passed to unlock a higher level? */
bool m_bRequirePassHardSteps;
/** @brief Must the challenge steps be passed to unlock a higher level? */
bool m_bRequirePassChallengeSteps;
bool m_bRoulette;
RString m_sEntryID;
@@ -117,6 +124,7 @@ public:
float PointsUntilNextUnlock( UnlockRequirement t ) const;
int SongIsLocked( const Song *pSong ) const;
bool StepsIsLocked( const Song *pSong, const Steps *pSteps ) const;
bool StepsTypeIsLocked( const Song *pSong, const Steps *pSteps, const StepsType *pSType ) const;
int CourseIsLocked( const Course *course ) const;
bool ModifierIsLocked( const RString &sOneMod ) const;
@@ -153,6 +161,7 @@ public:
const UnlockEntry *FindSong( const Song *pSong ) const;
const UnlockEntry *FindSteps( const Song *pSong, const Steps *pSteps ) const;
const UnlockEntry *FindStepsType( const Song *pSong, const Steps *pSteps, const StepsType *pSType ) const;
const UnlockEntry *FindCourse( const Course *pCourse ) const;
const UnlockEntry *FindModifier( const RString &sOneMod ) const;
+1 -1
View File
@@ -278,7 +278,7 @@ void ArchHooks::MountInitialFilesystems( const RString &sDirOfExecutable )
const char *szHome = getenv( "HOME" );
RString sProductId = PRODUCT_ID;
sProductId.MakeLower();
RString sUserDataPath = ssprintf( "%s/.%s", szHome? szHome:".", sProductId.c_str() );
RString sUserDataPath = ssprintf( "%s/.%s", szHome? szHome:".", "stepmania5" );
FILEMAN->Mount( "dir", sUserDataPath + "/Cache", "/Cache" );
FILEMAN->Mount( "dir", sUserDataPath + "/Logs", "/Logs" );
FILEMAN->Mount( "dir", sUserDataPath + "/Save", "/Save" );
+4 -4
View File
@@ -206,7 +206,7 @@ void RunChild()
WriteToChild( hToStdin, &g_CrashInfo, sizeof(g_CrashInfo) );
// 2. Write info.
const char *p = RageLog::GetInfo();
const TCHAR *p = RageLog::GetInfo();
int iSize = strlen( p );
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
WriteToChild( hToStdin, p, iSize );
@@ -219,7 +219,7 @@ void RunChild()
// 4. Write RecentLogs.
int cnt = 0;
const char *ps[1024];
const TCHAR *ps[1024];
while( cnt < 1024 && (ps[cnt] = RageLog::GetRecentLog( cnt )) != NULL )
++cnt;
@@ -232,7 +232,7 @@ void RunChild()
}
// 5. Write CHECKPOINTs.
static char buf[1024*32];
static TCHAR buf[1024*32];
Checkpoints::GetLogs( buf, sizeof(buf), "$$" );
iSize = strlen( buf )+1;
WriteToChild( hToStdin, &iSize, sizeof(iSize) );
@@ -255,7 +255,7 @@ void RunChild()
if( !ReadFile( hFromStdout, &hMod, sizeof(hMod), &iActual, NULL) )
break;
char szName[MAX_PATH];
TCHAR szName[MAX_PATH];
if( !CrashGetModuleBaseName(hMod, szName) )
strcpy( szName, "???" );
iSize = strlen( szName );