float Profile::GetSongsActual( StepsType st, Difficulty dc ) const { float fTotalPercents = 0; // add steps high scores for( std::map<SongID,HighScoresForASong>::const_iterator i = m_SongHighScores.begin(); i != m_SongHighScores.end(); ++i ) { const SongID &id = i->first; Song* pSong = id.ToSong(); // If the Song isn't loaded on the current machine, then we can't // get radar values to compute dance points. if( pSong == NULL ) continue; if( pSong->m_SelectionDisplay == Song::SHOW_NEVER ) continue; // skip const HighScoresForASong &hsfas = i->second; for( std::map<StepsID,HighScoresForASteps>::const_iterator j = hsfas.m_StepsHighScores.begin(); j != hsfas.m_StepsHighScores.end(); ++j ) { const StepsID &id = j->first; Steps* pSteps = id.ToSteps( pSong, true ); // If the Steps isn't loaded on the current machine, then we can't // get radar values to compute dance points. if( pSteps == NULL ) continue; if( pSteps->m_StepsType != st ) continue; if( pSteps->GetDifficulty() != dc ) continue; // skip const HighScoresForASteps& h = j->second; const HighScoreList& hs = h.hs; fTotalPercents += hs.GetTopScore().fPercentDP; } } return fTotalPercents; }
Steps* SongUtil::GetStepsByDifficulty( const Song *pSong, StepsType st, Difficulty dc, bool bIncludeAutoGen ) { const vector<Steps*>& vpSteps = (st == StepsType_Invalid)? pSong->GetAllSteps() : pSong->GetStepsByStepsType(st); for( unsigned i=0; i<vpSteps.size(); i++ ) // for each of the Song's Steps { Steps* pSteps = vpSteps[i]; if( dc != Difficulty_Invalid && dc != pSteps->GetDifficulty() ) continue; if( !bIncludeAutoGen && pSteps->IsAutogen() ) continue; return pSteps; } return NULL; }
void SongUtil::GetSteps( const Song *pSong, vector<Steps*>& arrayAddTo, StepsType st, Difficulty dc, int iMeterLow, int iMeterHigh, const RString &sDescription, bool bIncludeAutoGen, unsigned uHash, int iMaxToGet ) { if( !iMaxToGet ) return; const vector<Steps*> &vpSteps = st == StepsType_Invalid ? pSong->GetAllSteps() : pSong->GetStepsByStepsType(st); for( unsigned i=0; i<vpSteps.size(); i++ ) // for each of the Song's Steps { Steps* pSteps = vpSteps[i]; if( dc != Difficulty_Invalid && dc != pSteps->GetDifficulty() ) continue; if( iMeterLow != -1 && iMeterLow > pSteps->GetMeter() ) continue; if( iMeterHigh != -1 && iMeterHigh < pSteps->GetMeter() ) continue; if( sDescription.size() && sDescription != pSteps->GetDescription() ) continue; if( uHash != 0 && uHash != pSteps->GetHash() ) continue; if( !bIncludeAutoGen && pSteps->IsAutogen() ) continue; arrayAddTo.push_back( pSteps ); if( iMaxToGet != -1 ) { --iMaxToGet; if( !iMaxToGet ) break; } } }
SongCreditDisplay::SongCreditDisplay() { if( GAMESTATE->IsCourseMode() ) return; this->LoadFromFont( THEME->GetPathF("SongCreditDisplay","text") ); Song* pSong = GAMESTATE->m_pCurSong; ASSERT( pSong ); CString s = pSong->GetFullDisplayTitle() + "\n" + pSong->GetDisplayArtist() + "\n"; if( !pSong->m_sCredit.empty() ) s += pSong->m_sCredit + "\n"; // use a vector and not a set so that ordering is maintained vector<Steps*> vpStepsToShow; FOREACH_PlayerNumber( p ) { if( !GAMESTATE->IsHumanPlayer(p) ) continue; // skip Steps* pSteps = GAMESTATE->m_pCurSteps[p]; bool bAlreadyAdded = find( vpStepsToShow.begin(), vpStepsToShow.end(), pSteps ) != vpStepsToShow.end(); if( !bAlreadyAdded ) vpStepsToShow.push_back( pSteps ); } for( unsigned i=0; i<vpStepsToShow.size(); i++ ) { Steps* pSteps = vpStepsToShow[i]; CString sDifficulty = DifficultyToThemedString( pSteps->GetDifficulty() ); // HACK: reset capitalization sDifficulty.MakeLower(); sDifficulty = Capitalize( sDifficulty ); s += sDifficulty + " steps: " + pSteps->GetDescription() + "\n"; } // erase the last newline s.erase( s.end()-1 ); this->SetText( s ); }
void NotesWriterSM::WriteSMNotesTag( const Steps &in, RageFile &f, bool bSavingCache ) { f.PutLine( "" ); f.PutLine( ssprintf( "//---------------%s - %s----------------", GameManager::StepsTypeToString(in.m_StepsType).c_str(), in.GetDescription().c_str() ) ); f.PutLine( "#NOTES:" ); f.PutLine( ssprintf( " %s:", GameManager::StepsTypeToString(in.m_StepsType).c_str() ) ); f.PutLine( ssprintf( " %s:", in.GetDescription().c_str() ) ); f.PutLine( ssprintf( " %s:", DifficultyToString(in.GetDifficulty()).c_str() ) ); f.PutLine( ssprintf( " %d:", in.GetMeter() ) ); int MaxRadar = bSavingCache? NUM_RADAR_CATEGORIES:5; CStringArray asRadarValues; for( int r=0; r < MaxRadar; r++ ) asRadarValues.push_back( ssprintf("%.3f", in.GetRadarValues()[r]) ); /* Don't append a newline here; it's added in NoteDataUtil::GetSMNoteDataString. * If we add it here, then every time we write unmodified data we'll add an extra * newline and they'll accumulate. */ f.Write( ssprintf( " %s:", join(",",asRadarValues).c_str() ) ); CString sNoteData; CString sAttackData; in.GetSMNoteData( sNoteData, sAttackData ); vector<CString> lines; split( sNoteData, "\n", lines, false ); WriteLineList( f, lines, true, true ); if( sAttackData.empty() ) f.PutLine( ";" ); else { f.PutLine( ":" ); lines.clear(); split( sAttackData, "\n", lines, false ); WriteLineList( f, lines, true, true ); f.PutLine( ";" ); } }
/* This data is added to each player profile, and to the machine profile per-player. */ void AddPlayerStatsToProfile( Profile *pProfile, const StageStats &ss, PlayerNumber pn ) { ss.AssertValid( pn ); CHECKPOINT; StyleID sID; sID.FromStyle( ss.m_pStyle ); ASSERT( (int) ss.m_vpPlayedSongs.size() == ss.m_player[pn].m_iStepsPlayed ); for( int i=0; i<ss.m_player[pn].m_iStepsPlayed; i++ ) { Steps *pSteps = ss.m_player[pn].m_vpPossibleSteps[i]; pProfile->m_iNumSongsPlayedByPlayMode[ss.m_playMode]++; pProfile->m_iNumSongsPlayedByStyle[sID] ++; pProfile->m_iNumSongsPlayedByDifficulty[pSteps->GetDifficulty()] ++; int iMeter = clamp( pSteps->GetMeter(), 0, MAX_METER ); pProfile->m_iNumSongsPlayedByMeter[iMeter] ++; } pProfile->m_iTotalDancePoints += ss.m_player[pn].m_iActualDancePoints; if( ss.m_Stage == Stage_Extra1 || ss.m_Stage == Stage_Extra2 ) { if( ss.m_player[pn].m_bFailed ) ++pProfile->m_iNumExtraStagesFailed; else ++pProfile->m_iNumExtraStagesPassed; } // If you fail in a course, you passed all but the final song. // FIXME: Not true. If playing with 2 players, one player could have failed earlier. if( !ss.m_player[pn].m_bFailed ) { pProfile->m_iNumStagesPassedByPlayMode[ss.m_playMode] ++; pProfile->m_iNumStagesPassedByGrade[ss.m_player[pn].GetGrade()] ++; } }
void SMLoader::LoadFromTokens( RString sStepsType, RString sDescription, RString sDifficulty, RString sMeter, RString sRadarValues, RString sNoteData, Steps &out ) { // we're loading from disk, so this is by definition already saved: out.SetSavedToDisk( true ); Trim( sStepsType ); Trim( sDescription ); Trim( sDifficulty ); Trim( sNoteData ); // LOG->Trace( "Steps::LoadFromTokens(), %s", sStepsType.c_str() ); // backwards compatibility hacks: // HACK: We eliminated "ez2-single-hard", but we should still handle it. if( sStepsType == "ez2-single-hard" ) sStepsType = "ez2-single"; // HACK: "para-single" used to be called just "para" if( sStepsType == "para" ) sStepsType = "para-single"; out.m_StepsType = GAMEMAN->StringToStepsType( sStepsType ); out.m_StepsTypeStr = sStepsType; out.SetDescription( sDescription ); out.SetCredit( sDescription ); // this is often used for both. out.SetChartName(sDescription); // yeah, one more for good measure. out.SetDifficulty( OldStyleStringToDifficulty(sDifficulty) ); // Handle hacks that originated back when StepMania didn't have // Difficulty_Challenge. (At least v1.64, possibly v3.0 final...) if( out.GetDifficulty() == Difficulty_Hard ) { // HACK: SMANIAC used to be Difficulty_Hard with a special description. if( sDescription.CompareNoCase("smaniac") == 0 ) out.SetDifficulty( Difficulty_Challenge ); // HACK: CHALLENGE used to be Difficulty_Hard with a special description. if( sDescription.CompareNoCase("challenge") == 0 ) out.SetDifficulty( Difficulty_Challenge ); } if( sMeter.empty() ) { // some simfiles (e.g. X-SPECIALs from Zenius-I-Vanisher) don't // have a meter on certain steps. Make the meter 1 in these instances. sMeter = "1"; } out.SetMeter( StringToInt(sMeter) ); out.SetSMNoteData( sNoteData ); out.TidyUpData(); }
void MusicWheel::Load( CString sType ) { LOG->Trace( "MusicWheel::Load('%s')", sType.c_str() ); LoadFromMetrics( sType ); LoadVariables(); FOREACH( MusicWheelItem*, m_MusicWheelItems, i ) SAFE_DELETE( *i ); m_MusicWheelItems.clear(); for( int i=0; i<NUM_WHEEL_ITEMS; i++ ) m_MusicWheelItems.push_back( new MusicWheelItem ); LOG->Trace( "MusicWheel::Load('%s')", sType.c_str() ); if (GAMESTATE->m_pCurSong != NULL) LOG->Trace( "Current Song: %s", GAMESTATE->m_pCurSong->GetSongDir().c_str() ); else LOG->Trace( "Current Song: NULL" ); SONGMAN->UpdateRankingCourses(); /* // for debugging. // Whatever Screen uses MusicWheel should set the Style if it needs to be set. if( GAMESTATE->m_CurStyle == NULL ) GAMESTATE->m_CurStyle = GAMEMAN->STYLE_DANCE_SINGLE; */ /* We play a lot of this one, so precache it. */ m_soundChangeSort.Load( THEME->GetPathS(sType,"sort") ); m_soundExpand.Load( THEME->GetPathS(sType,"expand"), true ); m_WheelState = STATE_SELECTING_MUSIC; if( GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2() ) { // make the preferred group the group of the last song played. // if( GAMESTATE->m_sPreferredSongGroup==GROUP_ALL_MUSIC && !PREFSMAN->m_bPickExtraStage ) // { // ASSERT(GAMESTATE->m_pCurSong); // GAMESTATE->m_sPreferredSongGroup = GAMESTATE->m_pCurSong->m_sGroupName; // } Song* pSong; Steps* pSteps; PlayerOptions po; SongOptions so; SONGMAN->GetExtraStageInfo( GAMESTATE->IsExtraStage2(), GAMESTATE->GetCurrentStyle(), pSong, pSteps, po, so ); GAMESTATE->m_pCurSong.Set( pSong ); GAMESTATE->m_pPreferredSong = pSong; FOREACH_HumanPlayer( p ) { GAMESTATE->m_pCurSteps[p].Set( pSteps ); GAMESTATE->m_pPlayerState[p]->m_PlayerOptions = po; GAMESTATE->m_PreferredDifficulty[p].Set( pSteps->GetDifficulty() ); } GAMESTATE->m_SongOptions = so; }
void NetworkSyncManager::StartRequest(short position) { if( !useSMserver ) return; if( GAMESTATE->m_bDemonstrationOrJukebox ) return; LOG->Trace("Requesting Start from Server."); m_packet.ClearPacket(); m_packet.Write1( NSCGSR ); unsigned char ctr=0; Steps * tSteps; tSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; if ((tSteps!=NULL) && (GAMESTATE->IsPlayerEnabled(PLAYER_1))) ctr = uint8_t(ctr+tSteps->GetMeter()*16); tSteps = GAMESTATE->m_pCurSteps[PLAYER_2]; if ((tSteps!=NULL) && (GAMESTATE->IsPlayerEnabled(PLAYER_2))) ctr = uint8_t(ctr+tSteps->GetMeter()); m_packet.Write1(ctr); ctr=0; tSteps = GAMESTATE->m_pCurSteps[PLAYER_1]; if ((tSteps!=NULL) && (GAMESTATE->IsPlayerEnabled(PLAYER_1))) ctr = uint8_t(ctr + (int) tSteps->GetDifficulty()*16); tSteps = GAMESTATE->m_pCurSteps[PLAYER_2]; if ((tSteps!=NULL) && (GAMESTATE->IsPlayerEnabled(PLAYER_2))) ctr = uint8_t(ctr + (int) tSteps->GetDifficulty()); m_packet.Write1(ctr); //Notify server if this is for sync or not. ctr = char(position*16); m_packet.Write1(ctr); if (GAMESTATE->m_pCurSong != NULL) { m_packet.WriteNT(GAMESTATE->m_pCurSong->m_sMainTitle); m_packet.WriteNT(GAMESTATE->m_pCurSong->m_sSubTitle); m_packet.WriteNT(GAMESTATE->m_pCurSong->m_sArtist); } else { m_packet.WriteNT(""); m_packet.WriteNT(""); m_packet.WriteNT(""); } if (GAMESTATE->m_pCurCourse != NULL) m_packet.WriteNT(GAMESTATE->m_pCurCourse->GetFullDisplayTitle()); else m_packet.WriteNT(CString("")); //Send Player (and song) Options m_packet.WriteNT(GAMESTATE->m_SongOptions.GetString()); int players=0; FOREACH_PlayerNumber (p) { ++players; m_packet.WriteNT(GAMESTATE->m_PlayerOptions[p].GetString()); } for (int i=0; i<2-players; ++i) m_packet.WriteNT(""); //Write a NULL if no player //This needs to be reset before ScreenEvaluation could possibly be called for (int i=0; i<NETMAXPLAYERS; ++i) { m_EvalPlayerData[i].name=0; m_EvalPlayerData[i].grade=0; m_EvalPlayerData[i].score=0; m_EvalPlayerData[i].difficulty=(Difficulty)0; for (int j=0; j<NETNUMTAPSCORES; ++j) m_EvalPlayerData[i].tapScores[j] = 0; } //Block until go is recieved. //Switch to blocking mode (this is the only //way I know how to get precievably instantanious results bool dontExit=true; //Don't block if we are server. if (isLanServer) NetPlayerClient->blocking=false; else NetPlayerClient->blocking=true; //The following packet HAS to get through, so we turn blocking on for it as well //Don't block if we are serving NetPlayerClient->SendPack((char*)&m_packet.Data, m_packet.Position); LOG->Trace("Waiting for RECV"); m_packet.ClearPacket(); while (dontExit) { //Keep the server going during the loop. if (isLanServer) LANserver->ServerUpdate(); m_packet.ClearPacket(); if (NetPlayerClient->ReadPack((char *)&m_packet, NETMAXBUFFERSIZE)<1) if (!isLanServer) dontExit=false; // Also allow exit if there is a problem on the socket // Only do if we are not the server, otherwise the sync // gets hosed up due to non blocking mode. if (m_packet.Read1() == (NSServerOffset + NSCGSR)) dontExit=false; //Only allow passing on Start request. //Otherwise scoreboard updates and such will confuse us. } NetPlayerClient->blocking=false; }
static NoteData ParseNoteData(RString &step1, RString &step2, Steps &out, const RString &path) { g_mapDanceNoteToNoteDataColumn.clear(); switch( out.m_StepsType ) { case StepsType_dance_single: g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3; break; case StepsType_dance_double: case StepsType_dance_couple: g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 1; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 2; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 3; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_LEFT] = 4; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_DOWN] = 5; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_UP] = 6; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD2_RIGHT] = 7; break; case StepsType_dance_solo: g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_LEFT] = 0; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPLEFT] = 1; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_DOWN] = 2; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UP] = 3; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_UPRIGHT] = 4; g_mapDanceNoteToNoteDataColumn[DANCE_NOTE_PAD1_RIGHT] = 5; break; DEFAULT_FAIL( out.m_StepsType ); } NoteData newNoteData; newNoteData.SetNumTracks( g_mapDanceNoteToNoteDataColumn.size() ); for( int pad=0; pad<2; pad++ ) // foreach pad { RString sStepData; switch( pad ) { case 0: sStepData = step1; break; case 1: if( step2 == "" ) // no data continue; // skip sStepData = step2; break; DEFAULT_FAIL( pad ); } sStepData.Replace("\n", ""); sStepData.Replace("\r", ""); sStepData.Replace("\t", ""); sStepData.Replace(" ", ""); double fCurrentBeat = 0; double fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE; for( size_t i=0; i<sStepData.size(); ) { char c = sStepData[i++]; switch( c ) { // begins a series case '(': fCurrentIncrementer = 1.0/16 * BEATS_PER_MEASURE; break; case '[': fCurrentIncrementer = 1.0/24 * BEATS_PER_MEASURE; break; case '{': fCurrentIncrementer = 1.0/64 * BEATS_PER_MEASURE; break; case '`': fCurrentIncrementer = 1.0/192 * BEATS_PER_MEASURE; break; // ends a series case ')': case ']': case '}': case '\'': case '>': fCurrentIncrementer = 1.0/8 * BEATS_PER_MEASURE; break; default: // this is a note character { if( c == '!' ) { LOG->UserLog( "Song file", path, "has an unexpected character: '!'." ); continue; } bool jump = false; if( c == '<' ) { /* Arr. Is this a jump or a 1/192 marker? */ if( Is192( sStepData, i ) ) { fCurrentIncrementer = 1.0/192 * BEATS_PER_MEASURE; break; } /* It's a jump. * We need to keep reading notes until we hit a >. */ jump = true; i++; } const int iIndex = BeatToNoteRow( (float)fCurrentBeat ); i--; do { c = sStepData[i++]; if( jump && c == '>' ) break; int iCol1, iCol2; DWIcharToNoteCol( c, (GameController)pad, iCol1, iCol2, path ); if( iCol1 != -1 ) newNoteData.SetTapNote(iCol1, iIndex, TAP_ORIGINAL_TAP); if( iCol2 != -1 ) newNoteData.SetTapNote(iCol2, iIndex, TAP_ORIGINAL_TAP); if(i>=sStepData.length()) { break; //we ran out of data //while looking for the ending > mark } if( sStepData[i] == '!' ) { i++; const char holdChar = sStepData[i++]; DWIcharToNoteCol(holdChar, (GameController)pad, iCol1, iCol2, path ); if( iCol1 != -1 ) newNoteData.SetTapNote(iCol1, iIndex, TAP_ORIGINAL_HOLD_HEAD); if( iCol2 != -1 ) newNoteData.SetTapNote(iCol2, iIndex, TAP_ORIGINAL_HOLD_HEAD); } } while( jump ); fCurrentBeat += fCurrentIncrementer; } break; } } } /* Fill in iDuration. */ for( int t=0; t<newNoteData.GetNumTracks(); ++t ) { FOREACH_NONEMPTY_ROW_IN_TRACK( newNoteData, t, iHeadRow ) { TapNote tn = newNoteData.GetTapNote( t, iHeadRow ); if( tn.type != TapNote::hold_head ) continue; int iTailRow = iHeadRow; bool bFound = false; while( !bFound && newNoteData.GetNextTapNoteRowForTrack(t, iTailRow) ) { const TapNote &TailTap = newNoteData.GetTapNote( t, iTailRow ); if( TailTap.type == TapNote::empty ) continue; newNoteData.SetTapNote( t, iTailRow, TAP_EMPTY ); tn.iDuration = iTailRow - iHeadRow; newNoteData.SetTapNote( t, iHeadRow, tn ); bFound = true; } if( !bFound ) { /* The hold was never closed. */ LOG->UserLog("Song file", path, "failed to close a hold note in \"%s\" on track %i", DifficultyToString(out.GetDifficulty()).c_str(), t); newNoteData.SetTapNote( t, iHeadRow, TAP_EMPTY ); } } }