void MessageOverlordConnection::sendAchievements(set<Achievement*> achievements) { stringstream s; s << "{"; s << "\"achievements\":"; s << "{"; bool first = true; set<Achievement*>::const_iterator it; for (it = achievements.begin(); it != achievements.end(); it++) { if (!first) { s << ","; } else { first = false; } Achievement *achievement = *it; string achievementName = achievement->getName(); s << "\"" << achievementName << "\": {}"; } s << "}"; s << "}"; string jsonMessage = s.str(); messageInterface.sendMessage(jsonMessage); }
/** A handy shortcut to increase points for an achievement key of the * current player. */ static void increaseAchievement(unsigned int index, const std::string &key, int increase = 1) { Achievement *a = getCurrentAchievementsStatus()->getAchievement(index); if (!a) { Log::fatal("PlayerManager", "Achievement '%d' not found.", index); } a->increase(key, increase); } // increaseAchievement
int listSpecificAchievementCallback(void *userdata, int argc, char **argv, char **azColName) { Achievement *results; results = static_cast<Achievement *>(userdata); char* col; for(int i = 0; i< argc-1 ; i++) { col = azColName[i]; if(stricmp(col,"Ach_name")== 0) results->setName(argv[i]); else if(stricmp(col,"Status")== 0) results->setStatus(argv[i]); else if(stricmp(col,"Description")== 0) results->setDescription(argv[i]); else if(stricmp(col,"Id")==0) results->setId(argv[i]); } return 0; }
/** Loads the saved state of all achievements from an XML file. * \param input The XML node to load the data from. */ void AchievementsStatus::load(const XMLNode * input) { std::vector<XMLNode*> xml_achievements; input->getNodes("achievement", xml_achievements); for (unsigned int i = 0; i < xml_achievements.size(); i++) { uint32_t achievement_id(0); xml_achievements[i]->get("id", &achievement_id); Achievement * achievement = getAchievement(achievement_id); if (achievement == NULL) { Log::warn("AchievementsStatus", "Found saved achievement data for a non-existent " "achievement. Discarding."); continue; } achievement->load(xml_achievements[i]); } // for i in xml_achievements } // load
/** Synchronises the achievements between local and online usage. It takes * the list of online achievements, and marks them all to be achieved * locally. Then it issues 'achieved' requests to the server for all local * achievements that are not set online. */ void AchievementsStatus::sync(const std::vector<uint32_t> & achieved_ids) { std::vector<bool> done; for(unsigned int i =0; i < achieved_ids.size(); ++i) { if(done.size()< achieved_ids[i]+1) done.resize(achieved_ids[i]+1); done[achieved_ids[i]] = true; Achievement * achievement = getAchievement(achieved_ids[i]); if(achievement != NULL) achievement->setAchieved(); } std::map<uint32_t, Achievement*>::iterator i; // String to collect all local ids that are not synched // to the online account std::string ids; for(i=m_achievements.begin(); i!=m_achievements.end(); i++) { unsigned int id = i->second->getID(); if(i->second->isAchieved() && (id>=done.size() || !done[id]) ) { ids=ids+StringUtils::toString(id)+","; } } if(ids.size()>0) { ids = ids.substr(0, ids.size() - 1); // delete the last "," in the string Log::info("Achievements", "Synching achievement %d to server.", ids.c_str()); Online::HTTPRequest * request = new Online::HTTPRequest(true, 2); PlayerManager::setUserDetails(request, "achieving"); request->addParameter("achievementid", ids); request->queue(); } } // sync
/** Called at the end of a race. Updates highscores, pauses the game, and * informs the unlock manager about the finished race. This function must * be called after all other stats were updated from the different game * modes. */ void World::terminateRace() { m_schedule_pause = false; m_schedule_unpause = false; // Update the estimated finishing time for all karts that haven't // finished yet. const unsigned int kart_amount = getNumKarts(); for(unsigned int i = 0; i < kart_amount ; i++) { if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated()) { m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i])); } } // i<kart_amount // Update highscores, and retrieve the best highscore if relevant // to show it in the GUI int best_highscore_rank = -1; int best_finish_time = -1; std::string highscore_who = ""; StateManager::ActivePlayer* best_player = NULL; if (!this->isNetworkWorld()) { updateHighscores(&best_highscore_rank, &best_finish_time, &highscore_who, &best_player); } // Check achievements PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_COLUMBUS, getTrack()->getIdent(), 1); if (raceHasLaps()) { PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_MARATHONER, "laps", race_manager->getNumLaps()); } Achievement *achiev = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER); if (achiev) { std::string mode_name = getIdent(); // Get the race mode name int winner_position = 1; unsigned int opponents = achiev->getInfo()->getGoalValue("opponents"); // Get the required opponents number if (mode_name == IDENT_FTL) { winner_position = 2; opponents++; } for(unsigned int i = 0; i < kart_amount; i++) { // Retrieve the current player StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer(); if (p && p->getConstProfile() == PlayerManager::getCurrentPlayer()) { // Check if the player has won if (m_karts[i]->getPosition() == winner_position && kart_amount > opponents ) { // Update the achievement mode_name = StringUtils::toLowerCase(mode_name); if (achiev->getValue("opponents") <= 0) PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER, "opponents", opponents); PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER, mode_name, 1); } } } // for i < kart_amount } // if (achiev) Achievement *win = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_UNSTOPPABLE); //if achivement has been unlocked if (win->getValue("wins") < 5 ) { for(unsigned int i = 0; i < kart_amount; i++) { // Retrieve the current player StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer(); if (p && p->getConstProfile() == PlayerManager::getCurrentPlayer()) { // Check if the player has won if (m_karts[i]->getPosition() == 1 ) { // Increase number of consecutive wins PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_UNSTOPPABLE, "wins", 1); } else { //Set number of consecutive wins to 0 win->reset(); } } } } PlayerManager::getCurrentPlayer()->raceFinished(); if (m_race_gui) m_race_gui->clearAllMessages(); // we can't delete the race gui here, since it is needed in case of // a restart: the constructor of it creates some textures which assume // that no scene nodes exist. In case of a restart there are scene nodes, // so we can't create the race gui again, so we keep it around // and save the pointer. assert(m_saved_race_gui==NULL); m_saved_race_gui = m_race_gui; RaceResultGUI* results = RaceResultGUI::getInstance(); m_race_gui = results; if (best_highscore_rank > 0) { results->setHighscore(highscore_who, best_player, best_highscore_rank, best_finish_time); } else { results->clearHighscores(); } results->push(); WorldStatus::terminateRace(); } // terminateRace
bool SQLiteConnector::createAchievement(Achievement saved) { char sentence[256]; if(dbConnect()) { // sprintf(sentence,"UPDATE Achievements SET Ach_name='%s', Description='%s', Status='%s' WHERE Id='%s');",saved.getName(),saved.getDescription(),saved.getStatus(),saved.getId()); sprintf(sentence,"INSERT OR REPLACE INTO Achievements (Id, Ach_name, Description, Status) Values ('%s', '%s', '%s', '%s');",saved.getId(),saved.getName(),saved.getDescription(),saved.getStatus()); msg = sqlite3_exec(db,sentence,NULL,NULL,&error); if (msg != SQLITE_OK) { //cout << error << endl; return false; } dbDisconnect(); return true; } return false; }
void AchievementSet::LoadProgress( const char* sLoadStateFilename ) { char buffer[4096]; long nFileSize = 0; unsigned int CondNumHits[50]; // 50 conditions per achievement unsigned int CondSourceVal[50]; unsigned int CondSourceLastVal[50]; unsigned int CondTargetVal[50]; unsigned int CondTargetLastVal[50]; unsigned int nID = 0; unsigned int nNumCond = 0; char cheevoProgressString[4096]; unsigned int i = 0; unsigned int j = 0; char* pGivenProgressMD5 = NULL; char* pGivenCheevoMD5 = NULL; char cheevoMD5TestMangled[4096]; int nMemStringLen = 0; if( !RAUsers::LocalUser().IsLoggedIn() ) return; if( sLoadStateFilename == NULL ) return; sprintf_s( buffer, 4096, "%s%s.rap", RA_DIR_DATA, sLoadStateFilename ); char* pRawFile = _MallocAndBulkReadFileToBuffer( buffer, nFileSize ); if( pRawFile != NULL ) { unsigned int nOffs = 0; while( nOffs < (unsigned int)(nFileSize-2) && pRawFile[nOffs] != '\0' ) { char* pIter = &pRawFile[nOffs]; // Parse achievement id and num conditions nID = strtol( pIter, &pIter, 10 ); pIter++; nNumCond = strtol( pIter, &pIter, 10 ); pIter++; // Concurrently build the md5 checkstring sprintf_s( cheevoProgressString, 4096, "%d:%d:", nID, nNumCond ); ZeroMemory( CondNumHits, 50*sizeof(unsigned int) ); ZeroMemory( CondSourceVal, 50*sizeof(unsigned int) ); ZeroMemory( CondSourceLastVal, 50*sizeof(unsigned int) ); ZeroMemory( CondTargetVal, 50*sizeof(unsigned int) ); ZeroMemory( CondTargetLastVal, 50*sizeof(unsigned int) ); for( i = 0; i < nNumCond && i < 50; ++i ) { // Parse next condition state CondNumHits[i] = strtol( pIter, &pIter, 10 ); pIter++; CondSourceVal[i] = strtol( pIter, &pIter, 10 ); pIter++; CondSourceLastVal[i] = strtol( pIter, &pIter, 10 ); pIter++; CondTargetVal[i] = strtol( pIter, &pIter, 10 ); pIter++; CondTargetLastVal[i] = strtol( pIter, &pIter, 10 ); pIter++; // Concurrently build the md5 checkstring sprintf_s( buffer, 4096, "%d:%d:%d:%d:%d:", CondNumHits[i], CondSourceVal[i], CondSourceLastVal[i], CondTargetVal[i], CondTargetLastVal[i] ); strcat_s( cheevoProgressString, 4096, buffer ); } // Read the given md5: pGivenProgressMD5 = strtok_s( pIter, ":", &pIter ); pGivenCheevoMD5 = strtok_s( pIter, ":", &pIter ); // Regenerate the md5 and see if it sticks: sprintf_s( cheevoMD5TestMangled, 4096, "%s%s%s%d", RAUsers::LocalUser().Username().c_str(), cheevoProgressString, RAUsers::LocalUser().Username().c_str(), nID ); std::string sRecalculatedProgressMD5 = RAGenerateMD5( cheevoMD5TestMangled ); if( sRecalculatedProgressMD5.compare( pGivenProgressMD5 ) == 0 ) { // Embed in achievement: Achievement* pAch = Find( nID ); if( pAch != NULL ) { std::string sMemStr = pAch->CreateMemString(); // Recalculate the current achievement to see if it's compatible: std::string sMemMD5 = RAGenerateMD5( sMemStr ); if( sMemMD5.compare( 0, 32, pGivenCheevoMD5 ) == 0 ) { for( size_t nGrp = 0; nGrp < pAch->NumConditionGroups(); ++nGrp ) { for( j = 0; j < pAch->NumConditions( nGrp ); ++j ) { Condition& cond = pAch->GetCondition( nGrp, j ); cond.OverrideCurrentHits( CondNumHits[ j ] ); cond.CompSource().SetValues( CondSourceVal[ j ], CondSourceLastVal[ j ] ); cond.CompTarget().SetValues( CondTargetVal[ j ], CondTargetLastVal[ j ] ); pAch->SetDirtyFlag( Dirty_Conditions ); } } } else { ASSERT( !"Achievement progress savestate incompatible (achievement has changed?)" ); RA_LOG( "Achievement progress savestate incompatible (achievement has changed?)" ); } } else { ASSERT( !"Achievement doesn't exist!" ); RA_LOG( "Achievement doesn't exist!" ); } } else { //assert(!"MD5 invalid... what to do... maybe they're trying to hack achievements?"); } nOffs = (pIter - pRawFile); } free( pRawFile ); pRawFile = NULL; } }
void AchievementSet::SaveProgress( const char* sSaveStateFilename ) { if( !RAUsers::LocalUser().IsLoggedIn() ) return; if( sSaveStateFilename == NULL ) return; SetCurrentDirectory( Widen( g_sHomeDir ).c_str() ); char buffer[ 4096 ]; sprintf_s( buffer, 4096, "%s.rap", sSaveStateFilename ); FILE* pf = NULL; fopen_s( &pf, buffer, "w" ); if( pf == NULL ) { ASSERT( !"Could not save progress!" ); return; } for( size_t i = 0; i < NumAchievements(); ++i ) { Achievement* pAch = &m_Achievements[i]; if( !pAch->Active() ) continue; // Write ID of achievement and num conditions: char cheevoProgressString[4096]; memset( cheevoProgressString, '\0', 4096 ); for( unsigned int nGrp = 0; nGrp < pAch->NumConditionGroups(); ++nGrp ) { sprintf_s( buffer, "%d:%d:", pAch->ID(), pAch->NumConditions( nGrp ) ); strcat_s( cheevoProgressString, 4096, buffer ); for( unsigned int j = 0; j < pAch->NumConditions( nGrp ); ++j ) { Condition& cond = pAch->GetCondition( nGrp, j ); sprintf_s( buffer, 4096, "%d:%d:%d:%d:%d:", cond.CurrentHits(), cond.CompSource().RawValue(), cond.CompSource().RawPreviousValue(), cond.CompTarget().RawValue(), cond.CompTarget().RawPreviousValue() ); strcat_s( cheevoProgressString, 4096, buffer ); } } // Generate a slightly different key to md5ify: char sCheevoProgressMangled[4096]; sprintf_s( sCheevoProgressMangled, 4096, "%s%s%s%d", RAUsers::LocalUser().Username().c_str(), cheevoProgressString, RAUsers::LocalUser().Username().c_str(), pAch->ID() ); std::string sMD5Progress = RAGenerateMD5( std::string( sCheevoProgressMangled ) ); std::string sMD5Achievement = RAGenerateMD5( pAch->CreateMemString() ); fwrite( cheevoProgressString, sizeof(char), strlen(cheevoProgressString), pf ); fwrite( sMD5Progress.c_str(), sizeof(char), sMD5Progress.length(), pf ); fwrite( ":", sizeof(char), 1, pf ); fwrite( sMD5Achievement.c_str(), sizeof(char), sMD5Achievement.length(), pf ); fwrite( ":", sizeof(char), 1, pf ); // Check! } fclose( pf ); }