/** Find the position (rank) of every kart. ATM it uses a stable O(n^2) * algorithm by counting for each kart how many other karts are ahead of * it. */ void LinearWorld::updateRacePosition() { // Mostly for debugging: beginSetKartPositions(); const unsigned int kart_amount = (unsigned int) 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++) { AbstractKart* 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 unsigned int my_id = kart->getWorldKartId(); const float my_distance = m_kart_info[my_id].m_overall_distance; // Count karts ahead of the current kart, i.e. kart that are // already finished or have covered a larger overall distance. for (unsigned int j = 0 ; j < kart_amount ; j++) { // don't compare a kart with itself and ignore eliminated karts if(j == my_id || m_karts[j]->isEliminated()) continue; // If the other kart has: // - finished the race (but this kart hasn't) // - or is ahead // - or has the same distance (very unlikely) but started earlier // it is ahead --> increase position if((!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) || m_kart_info[j].m_overall_distance > my_distance || (m_kart_info[j].m_overall_distance == my_distance && m_karts[j]->getInitialPosition()<kart->getInitialPosition() ) ) { p++; } } //next kart #ifndef DEBUG setKartPosition(i, p); #else rank_changed |= kart->getPosition()!=p; if (!setKartPosition(i,p)) { Log::error("[LinearWorld]", "Same rank used twice!!"); Log::debug("[LinearWorld]", "Info used to decide ranking :"); for (unsigned int d=0; d<kart_amount; d++) { Log::debug("[LinearWorld]", "Kart %s has finished (%d), is at lap (%u)," "is at distance (%u), is eliminated(%d)", m_karts[d]->getIdent().c_str(), m_karts[d]->hasFinishedRace(), getLapForKart(d), m_kart_info[d].m_overall_distance, m_karts[d]->isEliminated()); } Log::debug("[LinearWorld]", "Who has each ranking so far :"); for (unsigned int d=0; d<i; d++) { Log::debug("[LinearWorld]", "%s has rank %d", m_karts[d]->getIdent().c_str(), m_karts[d]->getPosition()); } Log::debug("[LinearWorld]", " --> And %s is being set at rank %d", kart->getIdent().c_str(), p); history->Save(); assert(false); } #endif // Switch on faster music if not already done so, if the // first kart is doing its last lap. if(!m_faster_music_active && p == 1 && kart_info.m_race_lap == race_manager->getNumLaps() - 1 && useFastMusicNearEnd() ) { 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) { Log::debug("[LinearWorld]", "Counting laps at %u seconds.", getTime()); for (unsigned int i=0; i<kart_amount; i++) { AbstractKart* kart = m_karts[i]; Log::debug("[LinearWorld]", "counting karts ahead of %s (laps %u," " progress %u, finished %d, eliminated %d, initial position %u.", kart->getIdent().c_str(), m_kart_info[i].m_race_lap, m_kart_info[i].m_overall_distance, kart->hasFinishedRace(), kart->isEliminated(), kart->getInitialPosition()); // 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()) continue; KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const int my_id = kart->getWorldKartId(); const float my_distance = m_kart_info[my_id].m_overall_distance; for (unsigned int j = 0 ; j < kart_amount ; j++) { if(j == my_id) continue; if(m_karts[j]->isEliminated()) { Log::debug("[LinearWorld]", " %u: %s because it is eliminated.", p, m_karts[j]->getIdent().c_str()); continue; } if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) { p++; Log::debug("[LinearWorld]", " %u: %s because it has finished the race.", p, m_karts[j]->getIdent().c_str()); continue; } if(m_kart_info[j].m_overall_distance > my_distance) { p++; Log::debug("[LinearWorld]", " %u: %s because it is ahead %u.", p, m_karts[j]->getIdent().c_str(), m_kart_info[j].m_overall_distance); continue; } if(m_kart_info[j].m_overall_distance == my_distance && m_karts[j]->getInitialPosition()<kart->getInitialPosition()) { p++; Log::debug("[LinearWorld]"," %u: %s has same distance, but started ahead %d", p, m_karts[j]->getIdent().c_str(), m_karts[j]->getInitialPosition()); } } // next kart j } // for i<kart_amount Log::debug("LinearWorld]", "-------------------------------------------"); } // if rank_changed #endif #endif endSetKartPositions(); } // updateRacePosition
bool handleContextMenuAction(s32 cmd_id) { World *world = World::getWorld(); Physics *physics = world ? world->getPhysics() : NULL; switch(cmd_id) { case DEBUG_GRAPHICS_RELOAD_SHADERS: Log::info("Debug", "Reloading shaders..."); ShaderBase::updateShaders(); break; case DEBUG_GRAPHICS_RESET: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); break; case DEBUG_GRAPHICS_WIREFRAME: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleWireframe(); break; case DEBUG_GRAPHICS_MIPMAP_VIZ: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleMipVisualization(); break; case DEBUG_GRAPHICS_NORMALS_VIZ: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleNormals(); break; case DEBUG_GRAPHICS_SSAO_VIZ: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleSSAOViz(); break; case DEBUG_GRAPHICS_RSM_VIZ: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleRSM(); break; case DEBUG_GRAPHICS_RH_VIZ: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleRH(); break; case DEBUG_GRAPHICS_GI_VIZ: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleGI(); break; case DEBUG_GRAPHICS_SHADOW_VIZ: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleShadowViz(); break; case DEBUG_GRAPHICS_LIGHT_VIZ: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleLightViz(); break; case DEBUG_GRAPHICS_DISTORT_VIZ: if (physics) physics->setDebugMode(IrrDebugDrawer::DM_NONE); irr_driver->resetDebugModes(); irr_driver->toggleDistortViz(); break; case DEBUG_GRAPHICS_BULLET_1: irr_driver->resetDebugModes(); if (!world) return false; physics->setDebugMode(IrrDebugDrawer::DM_KARTS_PHYSICS); break; case DEBUG_GRAPHICS_BULLET_2: { irr_driver->resetDebugModes(); if (!world) return false; Physics *physics = world->getPhysics(); physics->setDebugMode(IrrDebugDrawer::DM_NO_KARTS_GRAPHICS); break; } case DEBUG_GRAPHICS_BOUNDING_BOXES_VIZ: irr_driver->resetDebugModes(); irr_driver->toggleBoundingBoxesViz(); break; case DEBUG_PROFILER: UserConfigParams::m_profiler_enabled = !UserConfigParams::m_profiler_enabled; break; case DEBUG_PROFILER_GENERATE_REPORT: profiler.setCaptureReport(!profiler.getCaptureReport()); break; case DEBUG_THROTTLE_FPS: main_loop->setThrottleFPS(false); break; case DEBUG_FONT_DUMP_GLYPH_PAGE: font_manager->getFont<BoldFace>()->dumpGlyphPage("bold"); font_manager->getFont<DigitFace>()->dumpGlyphPage("digit"); font_manager->getFont<RegularFace>()->dumpGlyphPage("regular"); case DEBUG_FONT_RELOAD: font_manager->getFont<BoldFace>()->reset(); font_manager->getFont<DigitFace>()->reset(); font_manager->getFont<RegularFace>()->reset(); break; case DEBUG_FPS: UserConfigParams::m_display_fps = !UserConfigParams::m_display_fps; break; case DEBUG_SAVE_REPLAY: ReplayRecorder::get()->save(); break; case DEBUG_SAVE_HISTORY: history->Save(); break; case DEBUG_POWERUP_BOWLING: addPowerup(PowerupManager::POWERUP_BOWLING); break; case DEBUG_POWERUP_BUBBLEGUM: addPowerup(PowerupManager::POWERUP_BUBBLEGUM); break; case DEBUG_POWERUP_CAKE: addPowerup(PowerupManager::POWERUP_CAKE); break; case DEBUG_POWERUP_PARACHUTE: addPowerup(PowerupManager::POWERUP_PARACHUTE); break; case DEBUG_POWERUP_PLUNGER: addPowerup(PowerupManager::POWERUP_PLUNGER); break; case DEBUG_POWERUP_RUBBERBALL: addPowerup(PowerupManager::POWERUP_RUBBERBALL); break; case DEBUG_POWERUP_SWATTER: addPowerup(PowerupManager::POWERUP_SWATTER); break; case DEBUG_POWERUP_SWITCH: addPowerup(PowerupManager::POWERUP_SWITCH); break; case DEBUG_POWERUP_ZIPPER: addPowerup(PowerupManager::POWERUP_ZIPPER); break; case DEBUG_POWERUP_NITRO: { if (!world) return false; const unsigned int num_local_players = race_manager->getNumLocalPlayers(); for (unsigned int i = 0; i < num_local_players; i++) { AbstractKart* kart = world->getLocalPlayerKart(i); kart->setEnergy(100.0f); } break; } case DEBUG_ATTACHMENT_ANVIL: addAttachment(Attachment::ATTACH_ANVIL); break; case DEBUG_ATTACHMENT_BOMB: addAttachment(Attachment::ATTACH_BOMB); break; case DEBUG_ATTACHMENT_PARACHUTE: addAttachment(Attachment::ATTACH_PARACHUTE); break; case DEBUG_GUI_TOGGLE: { if (!world) return false; RaceGUIBase* gui = world->getRaceGUI(); if (gui != NULL) gui->m_enabled = !gui->m_enabled; break; } case DEBUG_GUI_HIDE_KARTS: if (!world) return false; for (unsigned int n = 0; n<world->getNumKarts(); n++) { AbstractKart* kart = world->getKart(n); if (kart->getController()->isPlayerController()) kart->getNode()->setVisible(false); } break; case DEBUG_GUI_CAM_TOP: CameraDebug::setDebugType(CameraDebug::CM_DEBUG_TOP_OF_KART); Camera::changeCamera(0, Camera::CM_TYPE_DEBUG); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; case DEBUG_GUI_CAM_WHEEL: CameraDebug::setDebugType(CameraDebug::CM_DEBUG_GROUND); Camera::changeCamera(0, Camera::CM_TYPE_DEBUG); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; case DEBUG_GUI_CAM_BEHIND_KART: CameraDebug::setDebugType(CameraDebug::CM_DEBUG_BEHIND_KART); Camera::changeCamera(0, Camera::CM_TYPE_DEBUG); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; case DEBUG_GUI_CAM_SIDE_OF_KART: CameraDebug::setDebugType(CameraDebug::CM_DEBUG_SIDE_OF_KART); Camera::changeCamera(0, Camera::CM_TYPE_DEBUG); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; case DEBUG_GUI_CAM_FREE: { Camera *camera = Camera::getActiveCamera(); Camera::changeCamera(camera->getIndex(), Camera::CM_TYPE_FPS); irr_driver->getDevice()->getCursorControl()->setVisible(false); // Reset camera rotation CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera()); if(cam) { cam->setDirection(vector3df(0, 0, 1)); cam->setUpVector(vector3df(0, 1, 0)); } break; } case DEBUG_GUI_CAM_NORMAL: { Camera *camera = Camera::getActiveCamera(); Camera::changeCamera(camera->getIndex(), Camera::CM_TYPE_NORMAL); irr_driver->getDevice()->getCursorControl()->setVisible(true); break; } case DEBUG_GUI_CAM_SMOOTH: { CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera()); if(cam) { cam->setSmoothMovement(!cam->getSmoothMovement()); } break; } case DEBUG_GUI_CAM_ATTACH: { CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera()); if(cam) { cam->setAttachedFpsCam(!cam->getAttachedFpsCam()); } break; } case DEBUG_VIEW_KART_ONE: changeCameraTarget(1); break; case DEBUG_VIEW_KART_TWO: changeCameraTarget(2); break; case DEBUG_VIEW_KART_THREE: changeCameraTarget(3); break; case DEBUG_VIEW_KART_FOUR: changeCameraTarget(4); break; case DEBUG_VIEW_KART_FIVE: changeCameraTarget(5); break; case DEBUG_VIEW_KART_SIX: changeCameraTarget(6); break; case DEBUG_VIEW_KART_SEVEN: changeCameraTarget(7); break; case DEBUG_VIEW_KART_EIGHT: changeCameraTarget(8); break; case DEBUG_PRINT_START_POS: if (!world) return false; for (unsigned int i = 0; i<world->getNumKarts(); i++) { AbstractKart *kart = world->getKart(i); Log::warn(kart->getIdent().c_str(), "<start position=\"%d\" x=\"%f\" y=\"%f\" z=\"%f\" h=\"%f\"/>", i, kart->getXYZ().getX(), kart->getXYZ().getY(), kart->getXYZ().getZ(), kart->getHeading()*RAD_TO_DEGREE ); } break; case DEBUG_VISUAL_VALUES: { #if !defined(__APPLE__) DebugSliderDialog *dsd = new DebugSliderDialog(); dsd->setSliderHook("red_slider", 0, 255, [](){ return int(irr_driver->getAmbientLight().r * 255.f); }, [](int v){ video::SColorf ambient = irr_driver->getAmbientLight(); ambient.setColorComponentValue(0, v / 255.f); irr_driver->setAmbientLight(ambient); } ); dsd->setSliderHook("green_slider", 0, 255, [](){ return int(irr_driver->getAmbientLight().g * 255.f); }, [](int v){ video::SColorf ambient = irr_driver->getAmbientLight(); ambient.setColorComponentValue(1, v / 255.f); irr_driver->setAmbientLight(ambient); } ); dsd->setSliderHook("blue_slider", 0, 255, [](){ return int(irr_driver->getAmbientLight().b * 255.f); }, [](int v){ video::SColorf ambient = irr_driver->getAmbientLight(); ambient.setColorComponentValue(2, v / 255.f); irr_driver->setAmbientLight(ambient); } ); dsd->setSliderHook("ssao_radius", 0, 100, [](){ return int(irr_driver->getSSAORadius() * 10.f); }, [](int v){irr_driver->setSSAORadius(v / 10.f); } ); dsd->setSliderHook("ssao_k", 0, 100, [](){ return int(irr_driver->getSSAOK() * 10.f); }, [](int v){irr_driver->setSSAOK(v / 10.f); } ); dsd->setSliderHook("ssao_sigma", 0, 100, [](){ return int(irr_driver->getSSAOSigma() * 10.f); }, [](int v){irr_driver->setSSAOSigma(v / 10.f); } ); #endif } break; case DEBUG_ADJUST_LIGHTS: { #if !defined(__APPLE__) // Some sliders use multipliers because the spinner widget // only supports integers DebugSliderDialog *dsd = new DebugSliderDialog(); dsd->changeLabel("Red", "Red (x10)"); dsd->setSliderHook("red_slider", 0, 100, []() { return int(findNearestLight()->getColor().X * 100); }, [](int intensity) { LightNode* nearest = findNearestLight(); core::vector3df color = nearest->getColor(); nearest->setColor(intensity / 100.0f, color.Y, color.Z); } ); dsd->changeLabel("Green", "Green (x10)"); dsd->setSliderHook("green_slider", 0, 100, []() { return int(findNearestLight()->getColor().Y * 100); }, [](int intensity) { LightNode* nearest = findNearestLight(); core::vector3df color = nearest->getColor(); nearest->setColor(color.X, intensity / 100.0f, color.Z); } ); dsd->changeLabel("Blue", "Blue (x10)"); dsd->setSliderHook("blue_slider", 0, 100, []() { return int(findNearestLight()->getColor().Z * 100); }, [](int intensity) { LightNode* nearest = findNearestLight(); core::vector3df color = nearest->getColor(); nearest->setColor(color.X, color.Y, intensity / 100.0f); } ); dsd->changeLabel("SSAO radius", "energy (x10)"); dsd->setSliderHook("ssao_radius", 0, 100, []() { return int(findNearestLight()->getEnergy() * 10); }, [](int v){ findNearestLight()->setEnergy(v / 10.0f); } ); dsd->changeLabel("SSAO k", "radius"); dsd->setSliderHook("ssao_k", 0, 100, []() { return int(findNearestLight()->getRadius()); }, [](int v){ findNearestLight()->setRadius(float(v)); } ); dsd->changeLabel("SSAO Sigma", "[None]"); #endif break; } case DEBUG_SCRIPT_CONSOLE: new ScriptingConsole(); break; } // switch return false; }
/** Called when a kart must be eliminated. */ void FollowTheLeaderRace::countdownReachedZero() { if(m_leader_intervals.size()>1) m_leader_intervals.erase(m_leader_intervals.begin()); WorldStatus::setTime(m_leader_intervals[0]); // If the leader kart is not the first kart, remove the first // kart, otherwise remove the last kart. int position_to_remove = m_karts[0]->getPosition()==1 ? getCurrentNumKarts() : 1; AbstractKart *kart = getKartAtPosition(position_to_remove); if(!kart || kart->isEliminated()) { fprintf(stderr,"Problem with removing leader: position %d not found\n", position_to_remove); for(unsigned int i=0; i<m_karts.size(); i++) { fprintf(stderr,"kart %d: eliminated %d position %d\n", i,m_karts[i]->isEliminated(), m_karts[i]->getPosition()); } // for i } // else { if(UserConfigParams::m_ftl_debug) { printf("[ftl] Eliminiating kart '%s' at position %d.\n", kart->getIdent().c_str(), position_to_remove); } eliminateKart(kart->getWorldKartId()); // In case that the kart on position 1 was removed, we have // to set the correct position (which equals the remaining // number of karts) for the removed kart, as well as recompute // the position for all other karts if(position_to_remove==1) { // We have to add 1 to the number of karts to get the correct // position, since the eliminated kart was already removed // from the value returned by getCurrentNumKarts (and we have // to remove the kart before we can call updateRacePosition). // Note that we can not call WorldWithRank::setKartPosition // here, since it would not properly support debugging kart // ranks (since this kart would get its position set again // in updateRacePosition). We only set the rank of the eliminated // kart, and updateRacePosition will then call setKartPosition // for the now eliminated kart. kart->setPosition(getCurrentNumKarts()+1); updateRacePosition(); } // Time doesn't make any sense in FTL (and it is not displayed) kart->finishedRace(-1.0f); // Move any camera for this kart to the leader, facing backwards, // so that the eliminated player has something to watch. if (race_manager->getNumPlayers() > 1) { for(unsigned int i=0; i<Camera::getNumCameras(); i++) { Camera *camera = Camera::getCamera(i); if(camera->getKart()==kart) { camera->setMode(Camera::CM_LEADER_MODE); camera->setKart(getKart(0)); } } // for i<number of cameras } } // if kart to eliminate exists // almost over, use fast music if(getCurrentNumKarts()==3) { music_manager->switchToFastMusic(); } if (isRaceOver()) { // Handle special FTL situation: the leader is kart number 3 when // the last kart gets eliminated. In this case kart on position 1 // is eliminated, and the kart formerly on position 2 is on // position 1, the leader now position 2. In this case the kart // on position 1 would get more points for this victory. So if // this is the case, change the position if(m_karts[0]->getPosition()!=1) { // Adjust the position of all still driving karts that // are ahead of the leader by +1, and move the leader // to position 1. for (unsigned int i=1; i<m_karts.size(); i++) { if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated() && m_karts[i]->getPosition()<m_karts[0]->getPosition()) { m_karts[i]->setPosition(m_karts[i]->getPosition()+1); } } m_karts[0]->setPosition(1); } // Mark all still racing karts to be finished. for (unsigned int n=0; n<m_karts.size(); n++) { if (!m_karts[n]->isEliminated() && !m_karts[n]->hasFinishedRace()) { m_karts[n]->finishedRace(getTime()); } } } // End of race is detected from World::updateWorld() } // countdownReachedZero
/** 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++) { AbstractKart* 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 unsigned int my_id = kart->getWorldKartId(); const float my_distance = m_kart_info[my_id].m_overall_distance; // Count karts ahead of the current kart, i.e. kart that are // already finished or have covered a larger overall distance. for (unsigned int j = 0 ; j < kart_amount ; j++) { // don't compare a kart with itself and ignore eliminated karts if(j == my_id || m_karts[j]->isEliminated()) continue; // If the other kart has: // - finished the race (but this kart hasn't) // - or is ahead // - or has the same distance (very unlikely) but started earlier // it is ahead --> increase position if((!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) || m_kart_info[j].m_overall_distance > my_distance || (m_kart_info[j].m_overall_distance == my_distance && m_karts[j]->getInitialPosition()<kart->getInitialPosition() ) ) { p++; } } //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(" << m_kart_info[d].m_overall_distance << "), 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++) { AbstractKart* kart = m_karts[i]; std::cout << "counting karts ahead of " << kart->getIdent() << " (laps " << m_kart_info[i].m_race_lap << ", progress " << m_kart_info[i].m_overall_distance << " finished " << kart->hasFinishedRace() << " eliminated " << kart->isEliminated() << " initial position "<< kart->getInitialPosition() << ").\n"; // 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()) continue; KartInfo& kart_info = m_kart_info[i]; int p = 1 ; const int my_id = kart->getWorldKartId(); const float my_distance = m_kart_info[my_id].m_overall_distance; for (unsigned int j = 0 ; j < kart_amount ; j++) { if(j == my_id) continue; if(m_karts[j]->isEliminated()) { std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because it is eliminated.\n"; continue; } if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace()) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because it has finished the race.\n"; continue; } if(m_kart_info[j].m_overall_distance > my_distance) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " because it is ahead " << m_kart_info[j].m_overall_distance <<".\n"; continue; } if(m_kart_info[j].m_overall_distance == my_distance && m_karts[j]->getInitialPosition()<kart->getInitialPosition() ) { p++; std::cout << " " << p << " : " << m_karts[j]->getIdent() << " has same distance, but started ahead " << m_karts[j]->getInitialPosition()<<".\n"; } } // next kart j } // for i<kart_amount std::cout << "-------------------------------------------\n"; } // if rank_changed #endif #endif endSetKartPositions(); } // updateRacePosition
/** Waits till each kart is resting on the ground * * Does simulation steps still all karts reach the ground, i.e. are not * moving anymore */ void World::resetAllKarts() { // Reset the physics 'remaining' time to 0 so that the number // of timesteps is reproducible if doing a physics-based history run getPhysics()->getPhysicsWorld()->resetLocalTime(); // If track checking is requested, check all rescue positions if // they are heigh enough. if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES && UserConfigParams::m_track_debug) { Vec3 eps = Vec3(0,1.5f*m_karts[0]->getKartHeight(),0); for(unsigned int quad=0; quad<QuadGraph::get()->getNumNodes(); quad++) { const Quad &q = QuadGraph::get()->getQuadOfNode(quad); const Vec3 center = q.getCenter(); // We have to test for all karts, since the karts have different // heights and so things might change from kart to kart. for(unsigned int kart_id=0; kart_id<m_karts.size(); kart_id++) { AbstractKart *kart = m_karts[kart_id]; kart->setXYZ(center); btQuaternion heading(btVector3(0.0f, 1.0f, 0.0f), m_track->getAngle(quad) ); kart->setRotation(heading); btTransform pos; pos.setOrigin(center+eps); pos.setRotation(btQuaternion(btVector3(0.0f, 1.0f, 0.0f), m_track->getAngle(quad)) ); kart->getBody()->setCenterOfMassTransform(pos); bool kart_over_ground = m_physics->projectKartDownwards(kart); if(kart_over_ground) { const Vec3 &xyz = kart->getTrans().getOrigin() + Vec3(0,0.3f,0); if(dynamic_cast<Kart*>(kart)) dynamic_cast<Kart*>(kart)->getTerrainInfo() ->update(xyz); const Material *material = kart->getMaterial(); if(!material || material->isDriveReset()) kart_over_ground = false; } if(!kart_over_ground) { printf("Kart '%s' not over quad '%d'\n", kart->getIdent().c_str(), quad); printf("Center point: %f %f %f\n", center.getX(), center.getY(), center.getZ()); } } // for kart_id<m_karts.size() } // for quad < quad_graph.getNumNodes for(unsigned int kart_id=0; kart_id<m_karts.size(); kart_id++) { // Reset the karts back to the original start position. // This call is a bit of an overkill, but setting the correct // transforms, positions, motion state is a bit of a hassle. m_karts[kart_id]->reset(); } } // if m_track_debug m_schedule_pause = false; m_schedule_unpause = false; //Project karts onto track from above. This will lower each kart so //that at least one of its wheel will be on the surface of the track for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++) { ///start projection from top of kart btVector3 up_offset(0, 0.5f * ((*i)->getKartHeight()), 0); (*i)->getVehicle()->getRigidBody()->translate (up_offset); bool kart_over_ground = m_physics->projectKartDownwards(*i); if (!kart_over_ground) { fprintf(stderr, "ERROR: no valid starting position for kart %d " "on track %s.\n", (int)(i-m_karts.begin()), m_track->getIdent().c_str()); if (UserConfigParams::m_artist_debug_mode) { fprintf(stderr, "Activating fly mode.\n"); (*i)->flyUp(); continue; } else { exit(-1); } } } bool all_finished=false; // kart->isInRest() is not fully correct, since it only takes the // velocity in count, which might be close to zero when the kart // is just hitting the floor, before being pushed up again by // the suspension. So we just do a longer initial simulation, // which should be long enough for all karts to be firmly on ground. for(int i=0; i<60; i++) m_physics->update(1.f/60.f); // Stil wait will all karts are in rest (and handle the case that a kart // fell through the ground, which can happen if a kart falls for a long // time, therefore having a high speed when hitting the ground. while(!all_finished) { m_physics->update(1.f/60.f); all_finished=true; for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++) { if(!(*i)->isInRest()) { Vec3 normal; Vec3 hit_point; const Material *material; // We can't use (*i)->getXYZ(), since this is only defined // after update() was called. Instead we have to get the // real position of the rigid body. btTransform t; (*i)->getBody()->getMotionState()->getWorldTransform(t); // This test can not be done only once before the loop, since // it can happen that the kart falls through the track later! Vec3 to = t.getOrigin()+Vec3(0, -10000, 0); m_track->getTriangleMesh().castRay(t.getOrigin(), to, &hit_point, &material, &normal); if(!material) { fprintf(stderr, "ERROR: no valid starting position for " "kart %d on track %s.\n", (int)(i-m_karts.begin()), m_track->getIdent().c_str()); if (UserConfigParams::m_artist_debug_mode) { fprintf(stderr, "Activating fly mode.\n"); (*i)->flyUp(); continue; } else { exit(-1); } } all_finished=false; break; } } } // while for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++) { // Now store the current (i.e. in rest) suspension length for each // kart, so that the karts can visualise the suspension. (*i)->setSuspensionLength(); // Initialise the camera (if available), now that the correct // kart position is set if((*i)->getCamera()) (*i)->getCamera()->setInitialTransform(); // Update the kart transforms with the newly computed position // after all karts are reset (*i)->setTrans((*i)->getBody()->getWorldTransform()); } } // resetAllKarts
/** Saves the current replay data. * \param ticks Number of physics time steps - should be 1. */ void ReplayRecorder::update(int ticks) { if (m_incorrect_replay || m_complete_replay) return; World *world = World::getWorld(); const bool single_player = race_manager->getNumPlayers() == 1; unsigned int num_karts = world->getNumKarts(); float time = world->getTime(); for(unsigned int i=0; i<num_karts; i++) { AbstractKart *kart = world->getKart(i); // If a single player give up in game menu, stop recording if (kart->isEliminated() && single_player) return; if (kart->isGhostKart()) continue; #ifdef DEBUG m_count++; #endif if (time - m_last_saved_time[i] < stk_config->m_replay_dt) { #ifdef DEBUG m_count_skipped_time++; #endif continue; } m_last_saved_time[i] = time; m_count_transforms[i]++; if (m_count_transforms[i] >= m_transform_events[i].size()) { // Only print this message once. if (m_count_transforms[i] == m_transform_events[i].size()) { char buffer[100]; sprintf(buffer, "Can't store more events for kart %s.", kart->getIdent().c_str()); Log::warn("ReplayRecorder", buffer); m_incorrect_replay = single_player; } continue; } TransformEvent *p = &(m_transform_events[i][m_count_transforms[i]-1]); PhysicInfo *q = &(m_physic_info[i][m_count_transforms[i]-1]); KartReplayEvent *r = &(m_kart_replay_event[i][m_count_transforms[i]-1]); p->m_time = World::getWorld()->getTime(); p->m_transform.setOrigin(kart->getXYZ()); p->m_transform.setRotation(kart->getVisualRotation()); q->m_speed = kart->getSpeed(); q->m_steer = kart->getSteerPercent(); const int num_wheels = kart->getVehicle()->getNumWheels(); for (int j = 0; j < 4; j++) { if (j > num_wheels || num_wheels == 0) q->m_suspension_length[j] = 0.0f; else { q->m_suspension_length[j] = kart->getVehicle() ->getWheelInfo(j).m_raycastInfo.m_suspensionLength; } } kart->getKartGFX()->getGFXStatus(&(r->m_nitro_usage), &(r->m_zipper_usage), &(r->m_skidding_state), &(r->m_red_skidding)); r->m_jumping = kart->isJumping(); } // for i if (world->getPhase() == World::RESULT_DISPLAY_PHASE && !m_complete_replay) { m_complete_replay = true; save(); } } // update