A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KartState.cc
1#include "KartState.hh"
2
3#include "game/kart/CollisionGroup.hh"
4#include "game/kart/KartCollide.hh"
5#include "game/kart/KartDynamics.hh"
6#include "game/kart/KartJump.hh"
7#include "game/kart/KartMove.hh"
8
9#include "game/system/RaceManager.hh"
10
11namespace Kart {
12
14 f32 range;
15 s16 frames;
16};
17
20static constexpr std::array<StartBoostEntry, 6> START_BOOST_ENTRIES = {{
21 {0.85f, 0},
22 {0.88f, 10},
23 {0.905f, 20},
24 {0.925f, 30},
25 {0.94f, 45},
26 {0.95f, 70},
27}};
28
30KartState::KartState() {
35
36 m_bAutoDrift = inputs()->driftIsAuto();
37
38 m_airtime = 0;
39 m_cannonPointId = 0;
41}
42
44void KartState::init() {
45 reset();
46}
47
49void KartState::reset() {
54
55 m_airtime = 0;
56 m_top.setZero();
57 m_hwgTimer = 0;
58 m_boostRampType = -1;
59 m_jumpPadVariant = -1;
60 m_halfPipeInvisibilityTimer = 0;
61 m_startBoostCharge = 0.0f;
62 m_stickX = 0.0f;
64 m_trickableTimer = 0;
65}
66
71 const auto *raceMgr = System::RaceManager::Instance();
72 if (raceMgr->isStageReached(System::RaceManager::Stage::Race)) {
73 if (!m_bInAction && !m_bBeforeRespawn && !m_bCannonStart && !m_bInCannon &&
75 const auto &currentState = inputs()->currentState();
76 const auto &lastState = inputs()->lastState();
77 m_stickX = currentState.stick.x;
78 m_stickY = currentState.stick.y;
79
81 if (m_stickX < 0.0f) {
82 m_bStickLeft = true;
83 } else if (m_stickX > 0.0f) {
84 m_bStickRight = true;
85 }
86 }
87
88 if (!m_bBurnout) {
89 m_bAccelerate = currentState.accelerate();
90 m_bAccelerateStart = m_bAccelerate && !lastState.accelerate();
91 m_bBrake = currentState.brake();
92
93 if (!m_bAutoDrift) {
94 m_bDriftInput = currentState.drift();
95 m_bHopStart = m_bDriftInput && !lastState.drift();
96 }
97 }
98 }
99
101 } else {
102 if (!raceMgr->isStageReached(System::RaceManager::Stage::Countdown)) {
103 return;
104 }
105
106 const auto &currentState = inputs()->currentState();
107 m_stickX = currentState.stick.x;
108 m_bChargeStartBoost = currentState.accelerate();
109
111 }
112}
113
118 resetFlags();
119
120 collide()->calcBeforeRespawn();
121
123 collide()->calcBoundingRadius();
124}
125
127void KartState::resetFlags() {
128 m_bAccelerate = false;
129 m_bBrake = false;
130 m_bDriftInput = false;
131 m_bHopStart = false;
132 m_bAccelerateStart = false;
133 m_bGroundStart = false;
134 m_bStickLeft = false;
135 m_bWallCollisionStart = false;
136 m_bAirStart = false;
137 m_bStickRight = false;
138
140
141 m_bCollidingOffroad = false;
142 m_bJumpPadDisableYsusForce = false;
143
144 m_stickY = 0.0f;
145 m_stickX = 0.0f;
146}
147
156 bool wasTouchingGround = m_bTouchingGround;
157 bool wasWallCollision = m_bWallCollision || m_bWall3Collision;
158
159 m_bWall3Collision = false;
160 m_bWallCollision = false;
162 m_bAnyWheelCollision = false;
163 m_bAllWheelsCollision = false;
164 m_bTouchingGround = false;
165
166 if (m_hwgTimer > 0) {
167 if (--m_hwgTimer == 0) {
168 m_bUNK2 = false;
169 m_bSomethingWallCollision = false;
170 }
171 }
172
173 m_top.setZero();
174 bool softWallCollision = false;
175
176 if (collide()->someSoftWallTimer() > 0) {
177 if (collide()->someNonSoftWallTimer() == 0) {
178 softWallCollision = true;
179 } else {
180 f32 softSusp = collide()->suspBottomHeightSoftWall() /
181 static_cast<f32>(collide()->someSoftWallTimer());
182 f32 nonSusp = collide()->suspBottomHeightNonSoftWall() /
183 static_cast<f32>(collide()->someNonSoftWallTimer());
184
185 if (softSusp - nonSusp >= 40.0f) {
186 m_bSoftWallDrift = false;
187 } else {
188 softWallCollision = true;
189 }
190 }
191 }
192
193 u16 wheelCollisions = 0;
194 u16 softWallCount = 0;
195 EGG::Vector3f wallNrm = EGG::Vector3f::zero;
196 bool trickable = false;
197
198 for (u16 tireIdx = 0; tireIdx < tireCount(); ++tireIdx) {
199 const auto &colData = collisionData(tireIdx);
200 if (hasFloorCollision(tirePhysics(tireIdx))) {
201 m_top += colData.floorNrm;
202 trickable = trickable || colData.bTrickable;
203 ++wheelCollisions;
204 }
205
206 if (softWallCollision && colData.bSoftWall) {
207 ++softWallCount;
208 wallNrm += colData.noBounceWallNrm;
209 }
210 }
211
212 if (wheelCollisions > 0) {
214 if (wheelCollisions == tireCount()) {
216 }
217 }
218
219 CollisionData &colData = collisionData();
220 if (colData.bFloor) {
222 m_top += colData.floorNrm;
223 trickable = trickable || colData.bTrickable;
224
225 if (m_bOverZipper) {
226 halfPipe()->end(true);
227 }
228 }
229
230 bool hitboxGroupSoftWallCollision = false;
231 if (softWallCollision && colData.bSoftWall) {
232 hitboxGroupSoftWallCollision = true;
233 ++softWallCount;
234 wallNrm += colData.wallNrm;
235 }
236
237 bool bVar3 = colData.bInvisibleWallOnly && m_halfPipeInvisibilityTimer > 0;
238 m_halfPipeInvisibilityTimer = std::max(0, m_halfPipeInvisibilityTimer - 1);
239
240 m_wallBonkTimer = std::max(0, m_wallBonkTimer - 1);
241
242 bool hwg = false;
243
244 if ((colData.bWall || colData.bWall3) && !bVar3) {
245 if (colData.bWall) {
246 m_bWallCollision = true;
247 }
248
249 if (colData.bWall3) {
250 m_bWall3Collision = true;
251 }
252
253 if (!wasWallCollision) {
255 }
256
257 m_wallBonkTimer = 2;
258
259 if (m_hwgTimer == 0 && colData.movement.y > 1.0f) {
260 EGG::Vector3f movement = colData.movement;
261 movement.normalise();
262
263 if (movement.dot(EGG::Vector3f::ey) > 0.8f &&
264 colData.wallNrm.dot(EGG::Vector3f::ey) > 0.85f &&
265 (movement.x * colData.wallNrm.x + movement.z * colData.wallNrm.z < 0.0f ||
266 collide()->colPerpendicularity() >= 1.0f)) {
267 colData.wallNrm.y = 0.0f;
268 colData.wallNrm.normalise();
269 wallNrm = colData.wallNrm;
270
271 if (wallNrm.length() < 0.05f) {
272 wallNrm = movement;
273 wallNrm.y = 0.0f;
274 }
275
276 hwg = true;
277 }
278 }
279 }
280
281 if (colData.bInvisibleWall && m_bHalfPipeRamp &&
282 collide()->surfaceFlags().offBit(KartCollide::eSurfaceFlags::StopHalfPipeState)) {
284 }
285
286 if (softWallCount > 0 || hwg) {
287 m_bUNK2 = true;
288 m_softWallSpeed = wallNrm;
289 m_softWallSpeed.normalise();
290 if (softWallCount > 0 && !m_bHop) {
291 m_bSoftWallDrift = true;
292 }
293
294 if (hwg) {
295 m_bHWG = true;
296 }
297
298 if (hitboxGroupSoftWallCollision || hwg || isBike()) {
299 m_bSomethingWallCollision = true;
300 m_hwgTimer = 10;
301
302 if (hwg) {
303 m_hwgTimer *= 2;
304 }
305 }
306 }
307
308 m_bAirtimeOver20 = false;
309 m_trickableTimer = std::max(0, m_trickableTimer - 1);
310
311 if (wheelCollisions < 1 && !colData.bFloor) {
312 if (wasTouchingGround) {
313 m_bAirStart = true;
314 }
315
316 if (++m_airtime > 20) {
317 m_bAirtimeOver20 = true;
318 }
319 } else {
320 m_top.normalise();
321
322 m_bTouchingGround = true;
323 m_bAfterCannon = false;
324
325 if (!m_bInAction) {
326 m_bActionMidZipper = false;
327 m_bEndHalfPipe = false;
328 }
329
330 if (m_bOverZipper) {
331 halfPipe()->end(true);
332 }
333
334 if (trickable) {
335 m_trickableTimer = 3;
336 }
337
338 m_bTrickable = m_trickableTimer > 0;
339
340 if (!m_bJumpPad) {
341 m_bJumpPadMushroomCollision = false;
342 }
343
344 if (!wasTouchingGround) {
345 m_bGroundStart = true;
346 }
347
348 if (m_bInATrick && jump()->cooldown() == 0) {
349 move()->landTrick();
350 dynamics()->setForceUpright(true);
351 jump()->end();
352 }
353
354 m_airtime = 0;
355 }
356}
357
363 constexpr f32 START_BOOST_DELTA_ONE = 0.02f;
364 constexpr f32 START_BOOST_DELTA_TWO = 0.002f;
365 constexpr f32 START_BOOST_FALLOFF = 0.96f;
366
368 m_startBoostCharge += START_BOOST_DELTA_ONE -
369 (START_BOOST_DELTA_ONE - START_BOOST_DELTA_TWO) * m_startBoostCharge;
370 } else {
371 m_startBoostCharge *= START_BOOST_FALLOFF;
372 }
373
374 m_startBoostCharge = std::max(0.0f, std::min(1.0f, m_startBoostCharge));
375}
376
381 if (System::RaceManager::Instance()->getCountdownTimer() != 0) {
382 return;
383 }
384
385 if (m_bAccelerate) {
386 if (m_startBoostCharge > START_BOOST_ENTRIES.back().range) {
387 m_startBoostIdx = std::numeric_limits<size_t>::max();
388 } else if (m_startBoostCharge > START_BOOST_ENTRIES.front().range) {
389 // Ranges are exclusive on the lower bound and inclusive on the upper bound
390 for (size_t i = 1; i < START_BOOST_ENTRIES.size(); ++i) {
391 if (m_startBoostCharge > START_BOOST_ENTRIES[i - 1].range &&
392 m_startBoostCharge <= START_BOOST_ENTRIES[i].range) {
393 m_startBoostIdx = i;
394 break;
395 }
396 }
397 }
398 }
399
400 if (m_startBoostIdx <= 0) {
401 return;
402 }
403
405 m_bChargeStartBoost = false;
406}
407
412 if (m_startBoostIdx == std::numeric_limits<size_t>::max()) {
413 move()->burnout().start();
414 } else {
415 move()->applyStartBoost(START_BOOST_ENTRIES[idx].frames);
416 }
417}
418
422 m_bHalfPipeRamp = false;
423 m_bRejectRoad = false;
424}
425
428 m_bAccelerate = false;
429 m_bBrake = false;
430 m_bDriftInput = false;
431 m_bDriftManual = false;
432 m_bBeforeRespawn = false;
433 m_bWall3Collision = false;
434 m_bWallCollision = false;
435 m_bHopStart = false;
436 m_bAccelerateStart = false;
437 m_bGroundStart = false;
439 m_bAnyWheelCollision = false;
440 m_bAllWheelsCollision = false;
441 m_bStickLeft = false;
442 m_bWallCollisionStart = false;
443 m_bAirtimeOver20 = false;
444 m_bStickyRoad = false;
445 m_bTouchingGround = false;
446 m_bHop = false;
447 m_bBoost = false;
448 m_bAirStart = false;
449 m_bStickRight = false;
450 m_bMushroomBoost = false;
451 m_bDriftAuto = false;
452 m_bSlipdriftCharge = false;
453 m_bWheelie = false;
454 m_bJumpPad = false;
455 m_bRampBoost = false;
456}
457
460 m_bInAction = false;
461 m_bTriggerRespawn = false;
462 m_bCannonStart = false;
463 m_bInCannon = false;
464 m_bTrickStart = false;
465 m_bInATrick = false;
467 m_bHalfPipeRamp = false;
468 m_bOverZipper = false;
469 m_bJumpPadMushroomCollision = false;
472 m_bZipperBoost = false;
473 m_bZipperStick = false;
474 m_bZipperTrick = false;
475 m_bRespawnKillY = false;
476 m_bBurnout = false;
477 m_bTrickRot = false;
478 m_bJumpPadMushroomVelYInc = false;
479 m_bChargingSsmt = false;
480 m_bRejectRoad = false;
481 m_bRejectRoadTrigger = false;
482 m_bTrickable = false;
483}
484
487 m_bWheelieRot = false;
488 m_bSkipWheelCalc = false;
489 m_bJumpPadMushroomTrigger = false;
490 m_bNoSparkInvisibleWall = false;
491 m_bCollidingOffroad = false;
492 m_bInRespawn = false;
493 m_bAfterRespawn = false;
494 m_bCrushed = false;
495 m_bJumpPadFixedSpeed = false;
496 m_bJumpPadDisableYsusForce = false;
497}
498
501 m_bUNK2 = false;
502 m_bSomethingWallCollision = false;
503 m_bSoftWallDrift = false;
504 m_bHWG = false;
505 m_bAfterCannon = false;
506 m_bActionMidZipper = false;
507 m_bChargeStartBoost = false;
508 m_bEndHalfPipe = false;
509}
510
511} // namespace Kart
bool m_bZipperBoost
Set when boosting after landing from a zipper.
Definition KartState.hh:675
bool m_bRespawnKillY
Set while respawning to cap external velocity at 0.
Definition KartState.hh:679
bool m_bBoost
Set while in a boost.
Definition KartState.hh:650
bool m_bChargeStartBoost
Like m_bAccelerate but during countdown.
Definition KartState.hh:713
bool m_bHop
Set while we are in a drift hop. Clears when we land.
Definition KartState.hh:649
bool m_bBeforeRespawn
Set on respawn collision, cleared on position snap.
Definition KartState.hh:635
void clearBitfield1()
Helper function to clear all bit flags at 0x8-0xB in KartState.
Definition KartState.cc:459
size_t m_startBoostIdx
Used to map m_startBoostCharge to a start boost duration.
Definition KartState.hh:734
void clearBitfield0()
Helper function to clear all bit flags at 0x4-0x7 in KartState.
Definition KartState.cc:427
bool m_bHopStart
Set if m_bDriftInput was toggled on this frame.
Definition KartState.hh:638
bool m_bHWG
Set when "Horizontal Wall Glitch" is active.
Definition KartState.hh:710
bool m_bBurnout
Set during a burnout on race start.
Definition KartState.hh:680
bool m_bDriftAuto
Currently in a drift w/ automatic.
Definition KartState.hh:654
bool m_bStickRight
Set on right stick input. Mutually exclusive to m_bStickLeft.
Definition KartState.hh:652
void clearBitfield2()
Helper function to clear all bit flags at 0xC-0xF in KartState.
Definition KartState.cc:486
void calcStartBoost()
STAGE 1 - Each frame, calculates the start boost charge.
Definition KartState.cc:362
bool m_bRejectRoad
Collision which causes a change in the player's pos and rot.
Definition KartState.hh:684
bool m_bWallCollision
Set if we are colliding with a wall.
Definition KartState.hh:637
bool m_bZipperTrick
Set while tricking mid-air from a zipper.
Definition KartState.hh:677
s16 m_wallBonkTimer
2f counter that stunts your speed after hitting a wall.
Definition KartState.hh:735
void calcCollisions()
Each frame, checks for collision and saves relevant bit flags.
Definition KartState.cc:155
bool m_bAllWheelsCollision
Set when all wheels are touching floor collision.
Definition KartState.hh:643
bool m_bDriftInput
A "fake" button, normally set if you meet the speed requirement to hop.
Definition KartState.hh:633
void clearBitfield3()
Helper function to clear all bit flags at 0x10-0x13 in KartState.
Definition KartState.cc:500
void calcHandleStartBoost()
On countdown end, calculates and applies our start boost charge.
Definition KartState.cc:380
f32 m_stickY
One of 15 discrete stick values from [-1.0, 1.0].
Definition KartState.hh:732
bool m_bChargingSsmt
Tracks whether we are charging a stand-still mini-turbo.
Definition KartState.hh:683
bool m_bAccelerateStart
Set if m_bAccelerate was toggled on this frame.
Definition KartState.hh:639
bool m_bDriftManual
Currently in a drift w/ manual.
Definition KartState.hh:634
bool m_bAutoDrift
True if auto transmission, false if manual.
Definition KartState.hh:720
void handleStartBoost(size_t idx)
Applies the relevant start boost duration.
Definition KartState.cc:411
void calc()
Every frame, resets the input state and saves collision-related bit flags.
Definition KartState.cc:117
bool m_bZipperStick
Set while mid-air and still influenced by the zipper.
Definition KartState.hh:676
bool m_bMushroomBoost
Set while we are in a mushroom boost.
Definition KartState.hh:653
bool m_bDisableBackwardsAccel
Enforces a 20f delay when reversing after charging SSMT.
Definition KartState.hh:678
bool m_bHalfPipeRamp
Set while colliding with zipper KCL.
Definition KartState.hh:671
f32 m_stickX
One of 15 discrete stick values from [-1.0, 1.0].
Definition KartState.hh:731
bool m_bVehicleBodyFloorCollision
Set if the vehicle body is colliding with the floor.
Definition KartState.hh:641
bool m_bBoostOffroadInvincibility
Set if we should ignore offroad slowdown this frame.
Definition KartState.hh:670
bool m_bAnyWheelCollision
Set when any wheel is touching floor collision.
Definition KartState.hh:642
bool m_bStickyRoad
Like the rBC stairs.
Definition KartState.hh:647
bool m_bWall3Collision
Set when colliding with wall KCL COL_TYPE_WALL_2.
Definition KartState.hh:636
f32 m_startBoostCharge
0-1 representation of start boost charge. Burnout if >0.95f.
Definition KartState.hh:733
bool m_bWheelie
Set while we are in a wheelie (even during the countdown).
Definition KartState.hh:656
bool m_bZipperInvisibleWall
Set when colliding with invisible wall above a zipper.
Definition KartState.hh:674
bool m_bTouchingGround
Set when any part of the vehicle is colliding with floor KCL.
Definition KartState.hh:648
bool m_bRejectRoadTrigger
e.g. DK Summit ending, and Maple Treeway side walls.
Definition KartState.hh:685
bool m_bStickLeft
Set on left stick input. Mutually exclusive to m_bStickRight.
Definition KartState.hh:644
void calcInput()
Each frame, read input and save related bit flags. Also handles start boosts.
Definition KartState.cc:70
bool m_bWallCollisionStart
Set if we have just started colliding with a wall.
Definition KartState.hh:645
bool m_bOverZipper
Set while mid-air from a zipper.
Definition KartState.hh:672
bool m_bAccelerate
Accel button is pressed.
Definition KartState.hh:627
void resetEjection()
Resets certain bitfields pertaining to ejections (reject road, half pipe zippers, etc....
Definition KartState.cc:421
bool m_bGroundStart
Set first frame landing from airtime.
Definition KartState.hh:640
bool m_bAirtimeOver20
Set after 20 frames of airtime, resets on landing.
Definition KartState.hh:646
Pertains to kart-related functionality.
A 3D float vector.
Definition Vector.hh:87
f32 normalise()
Normalizes the vector and returns the original length.
Definition Vector.cc:44
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:186
f32 length() const
The square root of the vector's dot product.
Definition Vector.hh:191
Information about the current collision and its properties.
bool bFloor
Set if colliding with KCL which satisfies KCL_TYPE_FLOOR.
bool bWall3
Set if colliding with COL_TYPE_WALL_2.
bool bWall
Set if colliding with KCL which satisfies KCL_TYPE_WALL.