/** Determine the nearest kart or item and update the current target * accordingly. */ void Swatter::chooseTarget() { // TODO: for the moment, only handle karts... const World *world = World::getWorld(); Kart *closest_kart = NULL; float min_dist2 = FLT_MAX; for(unsigned int i=0; i<world->getNumKarts(); i++) { Kart *kart = world->getKart(i); // TODO: isSwatterReady(), isSquashable()? if(kart->isEliminated() || kart==m_kart) continue; // don't squash an already hurt kart if (kart->isInvulnerable() || kart->isSquashed()) continue; float dist2 = (kart->getXYZ()-m_kart->getXYZ()).length2(); if(dist2<min_dist2) { min_dist2 = dist2; closest_kart = kart; } } m_target = closest_kart; // may be NULL }
/** Activates the next debug mode, or switches the mode off again. */ void IrrDebugDrawer::nextDebugMode() { // Go to next debug mode. Note that debug mode 3 ( m_debug_mode = (DebugModeType) ((m_debug_mode+1) % 3); World *world = World::getWorld(); unsigned int num_karts = world->getNumKarts(); for(unsigned int i=0; i<num_karts; i++) { Kart *kart = world->getKart(i); if(kart->isEliminated()) continue; kart->getNode()->setVisible(!(m_debug_mode & DM_NO_KARTS_GRAPHICS)); } } // nextDebugMode
/** Squash karts or items that are around the end position (determined using * a joint) of the swatter. */ void Swatter::squashThingsAround() { const KartProperties* kp = m_kart->getKartProperties(); // Square of the minimum distance float min_dist2 = kp->getSwatterDistance2(); const World* world = World::getWorld(); // Get the node corresponding to the joint at the center of the swatter // (by swatter, I mean the thing hold in the hand, not the whole thing) scene::ISceneNode* swatter_node = m_scene_node->getJointNode("Swatter"); assert(swatter_node); Vec3 swatter_pos = swatter_node->getAbsolutePosition(); m_swat_sound->position(swatter_pos); m_swat_sound->play(); // Squash karts around for(unsigned int i=0; i<world->getNumKarts(); i++) { Kart *kart = world->getKart(i); // TODO: isSwatterReady() if(kart->isEliminated() || kart==m_kart) continue; // don't swat an already hurt kart if (kart->isInvulnerable() || kart->isSquashed()) continue; float dist2 = (kart->getXYZ()-swatter_pos).length2(); if(dist2 >= min_dist2) continue; // too far away, ignore this kart kart->setSquash(kp->getSquashDuration(), kp->getSquashSlowdown()); if (kart->getAttachment()->getType()==Attachment::ATTACH_BOMB) { // make bomb explode kart->getAttachment()->update(10000); HitEffect *he = new Explosion(m_kart->getXYZ(), "explosion"); if(m_kart->getController()->isPlayerController()) he->setPlayerKartHit(); projectile_manager->addHitEffect(he); m_kart->handleExplosion(m_kart->getXYZ(), /*direct_hit*/ true); } // if kart has bomb attached World::getWorld()->kartHit(kart->getWorldKartId()); } // for i < num_kartrs // TODO: squash items }
/** 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
//----------------------------------------------------------------------------- RaceGUIBase::KartIconDisplayInfo* LinearWorld::getKartsDisplayInfo() { int laps_of_leader = -1; float time_of_leader = -1; // Find the best time for the lap. We can't simply use // the time of the kart at position 1, since the kart // might have been overtaken by now const unsigned int kart_amount = getNumKarts(); for(unsigned int i = 0; i < kart_amount ; i++) { RaceGUIBase::KartIconDisplayInfo& rank_info = m_kart_display_info[i]; Kart* kart = m_karts[i]; // reset color rank_info.r = 1.0; rank_info.g = 1.0; rank_info.b = 1.0; rank_info.lap = -1; if(kart->isEliminated()) continue; const float lap_time = getTimeAtLapForKart(kart->getWorldKartId()); const int current_lap = getLapForKart( kart->getWorldKartId() ); rank_info.lap = current_lap; if(current_lap > laps_of_leader) { // more laps than current leader --> new leader and new time computation laps_of_leader = current_lap; time_of_leader = lap_time; } else if(current_lap == laps_of_leader) { // Same number of laps as leader: use fastest time time_of_leader=std::min(time_of_leader,lap_time); } } // we now know the best time of the lap. fill the remaining bits of info for(unsigned int i = 0; i < kart_amount ; i++) { RaceGUIBase::KartIconDisplayInfo& rank_info = m_kart_display_info[i]; KartInfo& kart_info = m_kart_info[i]; Kart* kart = m_karts[i]; const int position = kart->getPosition(); if(laps_of_leader>0 && // Don't compare times when crossing the start line first (getTime() - getTimeAtLapForKart(kart->getWorldKartId())<5.0f || rank_info.lap != laps_of_leader) && raceHasLaps()) { // Display for 5 seconds std::string str; if(position == 1) { str = " " + StringUtils::timeToString( getTimeAtLapForKart(kart->getWorldKartId()) ); } else { float timeBehind; timeBehind = (kart_info.m_race_lap==laps_of_leader ? getTimeAtLapForKart(kart->getWorldKartId()) : getTime()) - time_of_leader; str = "+" + StringUtils::timeToString(timeBehind); } rank_info.m_text = irr::core::stringw(str.c_str()); } else { rank_info.m_text = ""; } int numLaps = race_manager->getNumLaps(); if(kart_info.m_race_lap>=numLaps) { // kart is finished, display in green rank_info.g = rank_info.b = 0; } else if(kart_info.m_race_lap>=0 && numLaps>1) { rank_info.g = rank_info.b = 1.0f-(float)kart_info.m_race_lap/((float)numLaps-1.0f); } } // next kart return m_kart_display_info; } // getKartsDisplayInfo