// TODO: Remove this class in favor and merge its functionality into the Lua // conditions already present in BGA. #include "global.h" #include "ConditionalBGA.h" #include #include "GameState.h" #include "GameManager.h" #include "song.h" #include "GameConstantsAndTypes.h" #include "RageLog.h" #include "BGAnimation.h" #include "ThemeManager.h" #include "RageUtil.h" #include "RageFile.h" #include "StatsManager.h" #include "Steps.h" #include "PlayerState.h" ConditionalBGA::ConditionalBGA() { } ConditionalBGA::~ConditionalBGA() { } void ConditionalBGA::Load(CString szScreenName) { RageFile file; CString szThemeDir = THEME->GetCurThemeDir(); CString szConditionalBGAFile = szThemeDir += szScreenName += " ConditionalBGA.ini"; // char filepath[512]; // strcpy(filepath,""); // empty the path first // strcpy(filepath,szConditionalBGAFile.c_str()); LOG->Trace("ConditionalBGA Load:%s",szConditionalBGAFile.c_str()); bool loaded = file.Open(szConditionalBGAFile,RageFile::READ); // FILE* fp = NULL; // fp = fopen(filepath,"r"); if(!loaded) { LOG->Trace("ConditionalBGA File Not Found"); return; } else { CString currentline; int bgano=0; while(!file.AtEOF()) { file.GetLine(currentline); // get the current line // kill any possible comments CStringArray asKillComments; asKillComments.clear(); // get rid of anything in there split(currentline, "#",asKillComments); // A comment starting with # if(!asKillComments.empty()) { currentline = asKillComments[0]; // there was some commentstuff here, take the first bit to be the actual data } asKillComments.clear(); // get rid of anything in there split(currentline, "/",asKillComments); // A comment starting with // or /* if(!asKillComments.empty()) { currentline = asKillComments[0]; // there was some commentstuff here, take the first bit to be the actual data } TrimRight(currentline); // nuke trailing whitespace // start parsing the data if(currentline.c_str()[0] == '[') // we found a new bganimation { if(!m_bgainfo.empty()) // last one wasnt empty { CheckBgaRequirements(m_bgainfo[bgano]); bgano++; } BgaCondInfo temp; m_bgainfo.push_back(temp); ClearINFO(bgano); // wipe out the old info structure. CStringArray asSplitLine; split(currentline,"[",asSplitLine); split(asSplitLine[0],"]",asSplitLine); if(!asSplitLine.empty() && asSplitLine.size() >= 1) m_bgainfo[bgano].bganame = asSplitLine[asSplitLine.size() - 1]; } else { CStringArray asSplitLine; split(currentline,":",asSplitLine); if(asSplitLine.empty()) continue; if(!asSplitLine[0].CompareNoCase("clear") && asSplitLine.size() > 1) { if(!asSplitLine[1].CompareNoCase("true") || !asSplitLine[1].CompareNoCase("cleared") || !asSplitLine[1].CompareNoCase("clear")) // true / clear (any clear condition) m_bgainfo[bgano].cleared = CBGA_CSCLEARED; else if(!asSplitLine[1].CompareNoCase("false") || !asSplitLine[1].CompareNoCase("failed")) // false / failed m_bgainfo[bgano].cleared = CBGA_CSFAILED; else if(!asSplitLine[1].CompareNoCase("maxcombo") || !asSplitLine[1].CompareNoCase("fullcombo")) // passed with maxcombo m_bgainfo[bgano].cleared = CBGA_CSMAXCOMBO; else if(!asSplitLine[1].CompareNoCase("brokencombo")) // passed with a broken combo m_bgainfo[bgano].cleared = CBGA_CSBROKECOMBO; // LOG->Trace("Clear Conditon: %d",info.cleared); } if(!asSplitLine[0].CompareNoCase("songtitle") && asSplitLine.size() > 1) { m_bgainfo[bgano].songtitle = asSplitLine[1]; // LOG->Trace("SongTitle: %s",info.songtitle.c_str()); } if(!asSplitLine[0].CompareNoCase("songartist") && asSplitLine.size() > 1) { m_bgainfo[bgano].songartist = asSplitLine[1]; // LOG->Trace("SongArtist: %s",info.songartist.c_str()); } if(!asSplitLine[0].CompareNoCase("songday") && asSplitLine.size() > 1) { CStringArray asDays; split( asSplitLine[1], ",", asDays ); for( unsigned d=0; d 32)) // ignore if date is out of range { m_bgainfo[bgano].songdays.push_back(dn); } } // for(d=0; dTrace("SongDay: %d",info.songdays[d]); // } } if(!asSplitLine[0].CompareNoCase("songmonth") && asSplitLine.size() > 1) { CStringArray asMonths; split( asSplitLine[1], ",", asMonths ); for( unsigned d=0; d 12)) // ignore if date is out of range { m_bgainfo[bgano].songmonths.push_back(dn); } } // for(d=0; dTrace("SongMonth: %d",info.songmonths[d]); // } } // foot meter ratings if(!asSplitLine[0].CompareNoCase("songdifficulty") && asSplitLine.size() > 1) { CStringArray asDifficulties; split( asSplitLine[1], ",", asDifficulties ); for(unsigned d=0;d 1) { m_bgainfo[bgano].dpoused = true; m_bgainfo[bgano].disallowedpo.FromString(asSplitLine[1]); } // heavy, light e.t.c. if(!asSplitLine[0].CompareNoCase("songrating") && asSplitLine.size() > 1) { CStringArray asDifficulties; split( asSplitLine[1], ",", asDifficulties ); for( unsigned d=0; dTrace("Difficulty: %d",info.difficulties[d]); // } } if(!asSplitLine[0].CompareNoCase("grade") && asSplitLine.size() > 1) { CStringArray asGrades; split( asSplitLine[1], ",", asGrades ); for( unsigned d=0; d 1) { LOG->Info("Comparing Styles"); CStringArray asStyles; split( asSplitLine[1], ",", asStyles ); for( unsigned d=0; dInfo( "Style:%s", asStyles[d].c_str() ); m_bgainfo[bgano].styles.push_back(GAMEMAN->GameAndStringToStyle(GAMESTATE->m_pCurGame,asStyles[d])); } } } } if(bganimtouse.CompareNoCase("")!=0) { LOG->Info("Best Match BGA Was: %s",bganimtouse.c_str()); bganim.LoadFromAniDir( THEME->GetPathToB(bganimtouse) ); bganim.PlayCommand( "On" ); } } file.Close(); } void ConditionalBGA::Update( float fDeltaTime ) { bganim.Update(fDeltaTime); } void ConditionalBGA::DrawPrimitives() { bganim.Draw(); } void ConditionalBGA::ClearINFO(int iEntry) { m_bgainfo[iEntry].bganame = ""; m_bgainfo[iEntry].songtitle = ""; m_bgainfo[iEntry].songartist = ""; m_bgainfo[iEntry].songdays.clear(); m_bgainfo[iEntry].songdows.clear(); m_bgainfo[iEntry].songmeters.clear(); m_bgainfo[iEntry].difficulties.clear(); m_bgainfo[iEntry].songmonths.clear(); m_bgainfo[iEntry].styles.clear(); m_bgainfo[iEntry].cleared = CBGA_CSUNUSED; m_bgainfo[iEntry].dpoused = false; } void ConditionalBGA::CheckBgaRequirements(BgaCondInfo info) { LOG->Trace("Checking Conditions For BGA: %s",info.bganame.c_str()); /* for(unsigned d=0; dTrace("Difficulty: %d",info.difficulties[d]); } for(d=0; dTrace("SongMonth: %d",info.songmonths[d]); } for(d=0; dTrace("SongDay: %d",info.songdays[d]); } LOG->Trace("Clear Conditon: %d",info.cleared); LOG->Trace("SongTitle: %s",info.songtitle.c_str()); LOG->Trace("SongArtist: %s",info.songartist.c_str()); */ bool valid = true; // valid until proven otherwise. bool hasconditions = false; // if there is a bga with no conditions for display // then we dont want it to appear if(info.songtitle.CompareNoCase("")!=0) // not equal { // LOG->Info("COMP: %s",info.songtitle.c_str()); hasconditions = true; if(GAMESTATE->m_pCurSong != NULL) { if(!GAMESTATE->m_pCurSong->m_sMainTitle.CompareNoCase(info.songtitle)) { LOG->Info("SongTitle Matches"); // valid } else valid = false; // different song } else // song not being played at the time { valid = false; } } if(info.songartist.CompareNoCase("")!=0 && valid) // not equal { // LOG->Info("COMP: %s",info.songtitle.c_str()); hasconditions = true; if(GAMESTATE->m_pCurSong != NULL) { if(!GAMESTATE->m_pCurSong->m_sArtist.CompareNoCase(info.songartist)) { LOG->Info("SongArtist Matches"); // valid } else valid = false; // different song } else // song not being played at the time { valid = false; } } if(!info.difficulties.empty() && valid) // dont bother checking any more if its already been invalidated. { // LOG->Info("Checking Difficulties"); hasconditions = true; bool foundmatchingdiff=false; for(unsigned d=0;dm_pCurSteps[pn] != NULL) { if(GAMESTATE->m_pCurSteps[pn]->GetDifficulty() == info.difficulties[d]) { foundmatchingdiff = true; LOG->Info("Found Valid Difficulty"); } } } } valid = foundmatchingdiff; } if(info.dpoused) { PlayerOptions po = info.disallowedpo; bool bModsValid = true; FOREACH_EnabledPlayer( pn ) { unsigned md; for(md=0;mdm_pPlayerState[pn]->m_PlayerOptions.m_fAccels[md] != 0.0f) { bModsValid=false; LOG->Info("Found Invalid Accel Mod"); } } for(md=0;mdm_pPlayerState[pn]->m_PlayerOptions.m_fEffects[md] != 0.0f) { bModsValid=false; LOG->Info("Found Invalid Effect Mod"); } } for(md=0;mdm_pPlayerState[pn]->m_PlayerOptions.m_fAppearances[md] != 0.0f) { bModsValid=false; LOG->Info("Found Invalid Appearance Mod"); } } for(md=0;mdm_pPlayerState[pn]->m_PlayerOptions.m_bTurns[md] != 0.0f) { bModsValid=false; LOG->Info("Found Invalid Turn Mod"); } } for(md=0;mdm_pPlayerState[pn]->m_PlayerOptions.m_bTransforms[md] != 0.0f) { bModsValid=false; LOG->Info("Found Invalid Transform Mod"); } } } valid = bModsValid; } if(!info.songmeters.empty() && valid) // dont bother checking any more if its already been invalidated. { hasconditions = true; bool foundmatchingmeter=false; for(unsigned d=0;dInfo("MeterRating: %d",info.songmeters[d]); FOREACH_EnabledPlayer( pn ) { if(GAMESTATE->m_pCurSteps[pn] != NULL) { if(info.songmeters[d] < 0) // negative values stored mean we want to check a value greaterthan or equal to its negative { // first make it positive then check to see if the footrating is >= to it int tmp = 0 - info.songmeters[d]; if(GAMESTATE->m_pCurSteps[pn]->GetMeter() >= tmp) { LOG->Info("Found Valid MeterRating"); foundmatchingmeter = true; } } else if(GAMESTATE->m_pCurSteps[pn]->GetMeter() == info.songmeters[d]) { LOG->Info("Found Valid MeterRating"); foundmatchingmeter = true; } } } } valid = foundmatchingmeter; } if(!info.styles.empty() && valid) { hasconditions = true; bool foundmatchingstyle=false; for(unsigned d=0;dInfo("info.styles = %d m_CurStyle = %d",info.styles[d],GAMESTATE->m_pCurStyle); if(info.styles[d] == GAMESTATE->m_pCurStyle) { foundmatchingstyle = true; LOG->Info("Found Valid Style"); } } valid = foundmatchingstyle; } if(!info.grades.empty() && valid) // dont bother checking any more if its already been invalidated. { // LOG->Info("Checking Difficulties"); hasconditions = true; bool foundmatchinggrades=true; // assume true until proven otherwise if(info.grades.size() == 1) // only looking for a single grade { LOG->Info("Checking Single Grade"); bool foundaplayerwithgrade = false; FOREACH_EnabledPlayer( pn ) { if(STATSMAN->m_CurStageStats.m_player[pn].GetGrade() == info.grades[0]) { LOG->Info("Found Valid Grade"); foundaplayerwithgrade = true; } } foundmatchinggrades = foundaplayerwithgrade; } else if(STATSMAN->m_vPlayedStageStats.size() < info.grades.size()) // we've not played enough stages to achieve a grade history condition { LOG->Info("Not Enough Stages Played To Compare Grade History"); foundmatchinggrades = false; } else // we have to check the history of grades to ensure they met the spec asked { LOG->Info("Checking Grade History"); LOG->Info("Stage Stats Size: %u NumConditionalGrades: %u", unsigned(STATSMAN->m_vPlayedStageStats.size()), unsigned(info.grades.size())); bool foundavalidgradeforstage = false; for(unsigned d=info.grades.size()-1,g=STATSMAN->m_vPlayedStageStats.size()-1;d>0;d--,g--) { if(d>g) ASSERT(0); // this should never happen. FOREACH_EnabledPlayer( pn ) { LOG->Info("Player%d Grade: %d :: Expected Grade: %d",pn,STATSMAN->m_vPlayedStageStats[g].m_player[pn].GetGrade(),info.grades[d]); if(STATSMAN->m_vPlayedStageStats[g].m_player[pn].GetGrade() == info.grades[d]) { LOG->Info("One Valid Grade"); foundavalidgradeforstage = true; } } } foundmatchinggrades = foundavalidgradeforstage; } valid = foundmatchinggrades; } if(!info.songmonths.empty() && valid) { time_t rawtime; time(&rawtime); struct tm ptm; localtime_r( &rawtime, &ptm ); int month = ptm.tm_mon; /* Month 0..11 */ LOG->Info("Month: %d",month); bool foundvalidmonth = false; for(unsigned d=0;dInfo("Month: %d, THIS Month: %d",info.songmonths[d],month); if(info.songmonths[d] == month) { foundvalidmonth = true; LOG->Info("Found Valid Month"); } } valid = foundvalidmonth; } if(!info.songdays.empty() && valid) { time_t rawtime; time(&rawtime); struct tm ptm; localtime_r( &rawtime, &ptm ); int day = ptm.tm_mday; /* day in the month */ LOG->Info("DAy: %d",day); bool foundvalidday = false; for(unsigned d=0;dInfo("Day: %d, THIS Day: %d",info.songdays[d],day); if(info.songdays[d] == day) { foundvalidday = true; LOG->Info("Found Valid Day"); } } valid = foundvalidday; } if(info.cleared != CBGA_CSUNUSED && valid) // already found invalid? forget it :> { bool foundclearcond = false; if(info.cleared == CBGA_CSFAILED) { if(GAMESTATE->AllAreDead() || STATSMAN->m_CurStageStats.AllFailed()) // they met the fail condition { LOG->Info("Failed Condition"); foundclearcond = true; } } else if(info.cleared == CBGA_CSCLEARED) { if(!STATSMAN->m_CurStageStats.AllFailed() || !GAMESTATE->AllAreDead() ) // stage was cleared { LOG->Info("Cleared Condition"); foundclearcond = true; } } else if(info.cleared == CBGA_CSMAXCOMBO) { FOREACH_EnabledPlayer( pn ) { if(STATSMAN->m_CurStageStats.m_player[pn].FullCombo()) { foundclearcond = true; LOG->Info("MaxCombo Condition"); } } } else if(info.cleared == CBGA_CSBROKECOMBO) { FOREACH_EnabledPlayer( pn ) { if(!STATSMAN->m_CurStageStats.m_player[pn].FullCombo()) { LOG->Info("BrokenCombo Condition"); foundclearcond = true; } } } valid = foundclearcond; } if(valid && hasconditions) { LOG->Info("Valid"); bganimtouse = info.bganame; } } /* * (c) 2004 Andrew Livy * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, and/or sell copies of the Software, and to permit persons to * whom the Software is furnished to do so, provided that the above * copyright notice(s) and this permission notice appear in all copies of * the Software and that both the above copyright notice(s) and this * permission notice appear in supporting documentation. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */