/** Called at the end of a race. Checks if the current times are worth a new * score, if so it notifies the HighscoreManager so the new score is added * and saved. */ void World::updateHighscores(int* best_highscore_rank, int* best_finish_time, std::string* highscore_who, StateManager::ActivePlayer** best_player) { *best_highscore_rank = -1; *best_player = NULL; if(!m_use_highscores) return; // Add times to highscore list. First compute the order of karts, // so that the timing of the fastest kart is added first (otherwise // someone might get into the highscore list, only to be kicked out // again by a faster kart in the same race), which might be confusing // if we ever decide to display a message (e.g. during a race) unsigned int *index = new unsigned int[m_karts.size()]; const unsigned int kart_amount = (unsigned int) m_karts.size(); for (unsigned int i=0; i<kart_amount; i++ ) { index[i] = 999; // first reset the contents of the array } for (unsigned int i=0; i<kart_amount; i++ ) { const int pos = m_karts[i]->getPosition()-1; if(pos < 0 || pos >= (int)kart_amount) continue; // wrong position index[pos] = i; } for (unsigned int pos=0; pos<kart_amount; pos++) { if(index[pos] == 999) { // no kart claimed to be in this position, most likely means // the kart location data is wrong #ifdef DEBUG Log::error("[World]", "Incorrect kart positions:"); for (unsigned int i=0; i<m_karts.size(); i++ ) { Log::error("[World]", "i=%d position %d.",i, m_karts[i]->getPosition()); } #endif continue; } // Only record times for player karts and only if // they finished the race if(!m_karts[index[pos]]->getController()->isPlayerController()) continue; if (!m_karts[index[pos]]->hasFinishedRace()) continue; assert(index[pos] < m_karts.size()); Kart *k = (Kart*)m_karts[index[pos]]; Highscores* highscores = getHighscores(); PlayerController *controller = (PlayerController*)(k->getController()); int highscore_rank = 0; if (controller->getPlayer()->getProfile() != NULL) // if we have the player profile here highscore_rank = highscores->addData(k->getIdent(), controller->getPlayer()->getProfile()->getName(), k->getFinishTime()); if (highscore_rank > 0) { if (*best_highscore_rank == -1 || highscore_rank < *best_highscore_rank) { *best_highscore_rank = highscore_rank; *best_finish_time = (int)(k->getFinishTime()); *best_player = controller->getPlayer(); *highscore_who = k->getIdent(); } highscore_manager->saveHighscores(); } } // next position delete []index; } // updateHighscores
/** Find the position (rank) of every kart */ void LinearWorld::updateRacePosition() { // Mostly for debugging: beginSetKartPositions(); const unsigned int kart_amount = m_karts.size(); #ifdef DEBUG bool rank_changed = false; #endif // NOTE: if you do any changes to this loop, the next loop (see // DEBUG_KART_RANK below) needs to have the same changes applied // so that debug output is still correct!!!!!!!!!!! for (unsigned int i=0; i<kart_amount; i++) { Kart* kart = m_karts[i]; // Karts that are either eliminated or have finished the // race already have their (final) position assigned. If // these karts would get their rank updated, it could happen // that a kart that finished first will be overtaken after // crossing the finishing line and become second! if(kart->isEliminated() || kart->hasFinishedRace()) { // This is only necessary to support debugging inconsistencies // in kart position parameters. setKartPosition(i, kart->getPosition()); continue; } KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const int my_id = kart->getWorldKartId(); const int my_laps = getLapForKart(my_id); const float my_progression = getDistanceDownTrackForKart(my_id); // Count karts ahead of the current kart, i.e. kart that are already finished, // have done more laps, or the same number of laps, but a greater distance. for (unsigned int j = 0 ; j < kart_amount ; j++) { if(j == kart->getWorldKartId()) continue; // don't compare a kart with itself if(m_karts[j]->isEliminated()) continue; // dismiss eliminated karts if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) { p++; continue; } /* has done more or less lapses */ assert(j==m_karts[j]->getWorldKartId()); int other_laps = getLapForKart(j); if (other_laps != my_laps) { if(other_laps > my_laps) { p++; // Other kart has more lapses } continue; } // Now both karts have the same number of lapses. Test progression. // A kart is ahead if it's driven further, or driven the same // distance, but started further to the back. float other_progression = getDistanceDownTrackForKart(j); if(other_progression > my_progression || (other_progression == my_progression && m_karts[j]->getInitialPosition() > kart->getInitialPosition()) ) { p++; #if _DEBUG_PRINTS_LIKE_MAD_ std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because he has is further within the track (my progression is " << my_progression << ", his progression is " << other_progression << ")\n"; #endif } } //next kart #ifndef DEBUG setKartPosition(i, p); #else rank_changed |= kart->getPosition()!=p; if (!setKartPosition(i,p)) { std::cerr << "ERROR, same rank used twice!!\n"; std::cerr << "Info used to decide ranking :\n"; for (unsigned int d=0; d<kart_amount; d++) { std::cerr << " kart " << m_karts[d]->getIdent() << " has finished(" << m_karts[d]->hasFinishedRace() << "), is at lap (" << getLapForKart(d) << "), is at distance(" << getDistanceDownTrackForKart(d) << "), is eliminated(" << m_karts[d]->isEliminated() << ")" << std::endl; } std::cerr << "Who has each ranking so far :\n"; for (unsigned int d=0; d<i; d++) { std::cerr << " " << m_karts[d]->getIdent() << " has rank " << m_karts[d]->getPosition() << std::endl; } std::cerr << " --> And " << kart->getIdent() << " is being set at rank " << p << std::endl; history->Save(); assert(false); } #endif // Switch on faster music if not already done so, if the // first kart is doing its last lap, and if the estimated // remaining time is less than 30 seconds. if(!m_faster_music_active && kart_info.m_race_lap == race_manager->getNumLaps()-1 && p==1 && useFastMusicNearEnd() && kart_info.m_estimated_finish > 0 && kart_info.m_estimated_finish - getTime() < 30.0f ) { music_manager->switchToFastMusic(); m_faster_music_active=true; } } // for i<kart_amount // Define this to get a detailled analyses each time a race position // changes. #ifdef DEBUG #undef DEBUG_KART_RANK #ifdef DEBUG_KART_RANK if(rank_changed) { std::cout << "Counting laps at "<<getTime()<<" seconds.\n"; for (unsigned int i=0; i<kart_amount; i++) { Kart* kart = m_karts[i]; if(kart->isEliminated() || kart->hasFinishedRace()) continue; KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const int my_id = kart->getWorldKartId(); const int my_laps = getLapForKart(my_id); const float my_progression = getDistanceDownTrackForKart(my_id); std::cout << "counting karts ahead of " << kart->getIdent() << " (laps "<<m_kart_info[i].m_race_lap<<", progress " << my_progression<<").\n"; for (unsigned int j = 0 ; j < kart_amount ; j++) { if(j == kart->getWorldKartId()) continue; // don't compare a kart with itself if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because he has finished.\n"; continue; } int other_laps = getLapForKart(j); if (other_laps != my_laps) { if(other_laps > my_laps) { p++; // Other kart has more lapses std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because he has more laps than me.\n"; } continue; } float other_progression = getDistanceDownTrackForKart(j); if(other_progression > my_progression || (other_progression == my_progression && m_karts[j]->getInitialPosition() > kart->getInitialPosition()) ) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because he is further within the track (my progression is " << my_progression << ", his progression is " << other_progression << ")\n"; } } //next kart } // for i<kart_amount std::cout << "-------------------------------------------\n"; } // if rank_changed #endif #endif endSetKartPositions(); } // updateRacePosition