1#include "RaceManager.hh"
3#include "game/system/CourseMap.hh"
4#include "game/system/KPadDirector.hh"
5#include "game/system/RaceConfig.hh"
6#include "game/system/map/MapdataCheckPath.hh"
7#include "game/system/map/MapdataStartPoint.hh"
9#include "game/kart/KartObjectManager.hh"
10#include "game/kart/KartState.hh"
15void RaceManager::init() {
24 u32 startPointIdx = 0;
26 MapdataStartPoint *kartpoint = CourseMap::Instance()->getStartPoint(startPointIdx);
32 angles = EGG::Vector3f::ex;
37void RaceManager::endPlayerRace(u32 ) {
39 m_stage = Stage::FinishGlobal;
43void RaceManager::calc() {
44 constexpr u16 STAGE_INTRO_DURATION = 172;
46 m_timerManager.calc();
51 if (++m_introTimer >= STAGE_INTRO_DURATION) {
52 m_stage = Stage::Countdown;
53 KPadDirector::Instance()->startGhostProxies();
56 case Stage::Countdown:
57 if (++m_timer >= STAGE_COUNTDOWN_DURATION) {
58 m_timerManager.setStarted(
true);
59 m_stage = Stage::Race;
71MapdataJugemPoint *RaceManager::jugemPoint()
const {
72 s8 jugemId = std::max<s8>(m_player.jugemId(), 0);
73 return System::CourseMap::Instance()->getJugemPoint(
static_cast<u16
>(jugemId));
77RaceManager *RaceManager::CreateInstance() {
79 s_instance =
new RaceManager;
84void RaceManager::DestroyInstance() {
86 auto *instance = s_instance;
92RaceManager::RaceManager()
93 : m_random(RNG_SEED), m_stage(Stage::Intro), m_introTimer(0), m_timer(0) {}
96RaceManager::~RaceManager() {
99 WARN(
"RaceManager instance not explicitly handled!");
104RaceManager::Player::Player() {
106 m_raceCompletion = 0.0f;
108 m_checkpointStartLapCompletion = 0.0f;
109 m_lapCompletion = 0.999999f;
111 auto *courseMap = CourseMap::Instance();
113 if (courseMap->getCheckPointCount() > 0 && courseMap->getCheckPathCount() > 0) {
114 m_maxKcp = courseMap->checkPoint()->lastKcpType();
121 m_drivingWrongWay =
false;
122 m_inputs = &KPadDirector::Instance()->playerInput();
126void RaceManager::Player::init() {
127 auto *courseMap = CourseMap::Instance();
129 if (courseMap->getCheckPointCount() != 0 && courseMap->getCheckPathCount() != 0) {
130 const EGG::Vector3f &pos = Kart::KartObjectManager::Instance()->object(0)->pos();
132 s16 checkpointId = courseMap->findSector(pos, 0, distanceRatio);
134 m_checkpointId = std::max<s16>(0, checkpointId);
135 m_jugemId = courseMap->getCheckPoint(m_checkpointId)->jugemIndex();
142void RaceManager::Player::calc() {
143 auto *courseMap = CourseMap::Instance();
144 const auto *kart = Kart::KartObjectManager::Instance()->object(0);
146 if (courseMap->getCheckPointCount() == 0 || courseMap->getCheckPathCount() == 0 ||
152 s16 checkpointId = courseMap->findSector(kart->pos(), m_checkpointId, distanceRatio);
154 if (checkpointId == -1) {
158 System::MapdataCheckPoint *checkpoint =
nullptr;
160 if (m_checkpointFactor < 0.0f || m_checkpointId != checkpointId) {
161 checkpoint = calcCheckpoint(checkpointId, distanceRatio);
163 checkpoint = CourseMap::Instance()->getCheckPoint(m_checkpointId);
166 m_raceCompletion =
static_cast<f32
>(m_currentLap) +
167 (m_checkpointStartLapCompletion + m_checkpointFactor * distanceRatio);
168 m_raceCompletion = std::min(m_raceCompletion,
static_cast<f32
>(m_currentLap) + 0.99999f);
170 const EGG::Vector3f &bodyFront = kart->bodyFront();
171 if (bodyFront.x != 0.0f && bodyFront.z != 0.0f) {
172 EGG::Vector2f frontXZ = EGG::Vector2f(bodyFront.x, bodyFront.z);
174 m_drivingWrongWay = checkpoint->dir().dot(frontXZ) <= -0.5f;
183 ASSERT(lap <= m_lapTimers.size());
186 return m_lapTimers[0];
189 const Timer ¤tLap = m_lapTimers[lap - 1];
190 const Timer &previousLap = m_lapTimers[lap - 2];
191 if (!currentLap.valid || !previousLap.valid) {
192 return Timer(std::numeric_limits<u16>::max(), 0, 0);
195 return currentLap - previousLap;
200 auto *courseMap = CourseMap::Instance();
202 u16 oldCheckpointId = m_checkpointId;
203 m_checkpointId = checkpointId;
205 f32 lapProportion = courseMap->checkPath()->lapProportion();
206 MapdataCheckPath *checkPath = courseMap->checkPath()->findCheckpathForCheckpoint(checkpointId);
207 m_checkpointFactor = checkPath->oneOverCount() * lapProportion;
209 m_checkpointStartLapCompletion =
static_cast<f32
>(checkPath->depth()) * lapProportion +
210 (m_checkpointFactor *
static_cast<f32
>(checkpointId - checkPath->start()));
212 f32 newLapCompletion = m_checkpointStartLapCompletion + distanceRatio * m_checkpointFactor;
213 f32 deltaLapCompletion = m_lapCompletion - newLapCompletion;
216 const MapdataCheckPoint *oldCheckpoint = courseMap->getCheckPoint(oldCheckpointId);
218 s8 newJugemIdx = newCheckpoint->jugemIndex();
219 if (newJugemIdx >= 0) {
220 m_jugemId = newJugemIdx;
223 if (!newCheckpoint->isNormalCheckpoint()) {
224 if (newCheckpoint->checkArea() > m_maxKcp) {
225 m_maxKcp = newCheckpoint->checkArea();
226 }
else if (m_maxKcp == courseMap->checkPoint()->lastKcpType()) {
227 if ((newCheckpoint->isFinishLine() &&
228 areCheckpointsSubsequent(oldCheckpoint, checkpointId)) ||
229 deltaLapCompletion > 0.95f) {
235 if ((oldCheckpoint->isFinishLine() &&
236 areCheckpointsSubsequent(newCheckpoint, oldCheckpointId)) ||
237 deltaLapCompletion < -0.95f) {
241 m_lapCompletion = newLapCompletion;
243 return newCheckpoint;
247bool RaceManager::Player::areCheckpointsSubsequent(
const MapdataCheckPoint *checkpoint,
248 u16 nextCheckpointId)
const {
249 for (
size_t i = 0; i < checkpoint->nextCount(); ++i) {
250 if (nextCheckpointId == checkpoint->nextPoint(i)->id()) {
259void RaceManager::Player::decrementLap() {
260 auto *courseMap = CourseMap::Instance();
262 if (courseMap->getCheckPointCount() > 0 && courseMap->getCheckPathCount() > 0) {
263 m_maxKcp = courseMap->checkPoint()->lastKcpType();
272void RaceManager::Player::incrementLap() {
274 if (++m_currentLap <= m_maxLap) {
278 const auto *kart = Kart::KartObjectManager::Instance()->object(0);
279 u16 addMs = CourseMap::Instance()->getCheckPointEntryOffsetMs(m_checkpointId, kart->pos(),
282 const Timer ¤tTimer = RaceManager::Instance()->timerManager().currentTimer();
283 Timer timer = currentTimer +
static_cast<f32
>(addMs);
286 ASSERT(
static_cast<size_t>(m_maxLap - 1) < m_lapTimers.size());
287 m_lapTimers[m_maxLap - 1] = timer;
292 m_maxLap = m_currentLap;
297void RaceManager::Player::endRace(
const Timer &finishTime) {
298 m_raceTimer = finishTime;
299 RaceManager::Instance()->endPlayerRace(0);
302RaceManager *RaceManager::s_instance =
nullptr;
void findKartStartPoint(EGG::Vector3f &pos, EGG::Vector3f &angles, u8 placement, u8 playerCount)
Timer getLapSplit(size_t idx) const
Gets the lap split, which is the difference between the given lap and the previous one.
f32 m_checkpointFactor
The proportion of a lap for the current checkpoint.
void findKartStartPoint(EGG::Vector3f &pos, EGG::Vector3f &angles)
@ BeforeRespawn
Set on respawn collision, cleared on position snap.
High-level handling for generic system operations, such as input reading, race configuration,...
A simple struct to represent a lap or race finish time.