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"
9#include "game/system/RaceManager.hh"
20static constexpr std::array<StartBoostEntry, 6> START_BOOST_ENTRIES = {{
30KartState::KartState() {
41void KartState::init() {
46void KartState::reset() {
55 m_jumpPadVariant = -1;
56 m_halfPipeInvisibilityTimer = 0;
67 const auto *raceMgr = System::RaceManager::Instance();
68 if (raceMgr->isStageReached(System::RaceManager::Stage::Race)) {
71 const auto ¤tState = inputs()->currentState();
72 const auto &lastState = inputs()->lastState();
86 .changeBit(currentState.accelerate() && !lastState.accelerate(),
92 .changeBit(currentState.drift() && !lastState.drift(),
100 if (!raceMgr->isStageReached(System::RaceManager::Stage::Countdown)) {
104 const auto ¤tState = inputs()->currentState();
118 collide()->calcBeforeRespawn();
121 collide()->calcBoundingRadius();
125void KartState::resetFlags() {
130 eStatus::CollidingOffroad, eStatus::JumpPadDisableYsusForce);
151 if (m_hwgTimer > 0) {
152 if (--m_hwgTimer == 0) {
153 m_status.
resetBit(eStatus::UNK2, eStatus::SomethingWallCollision);
158 bool softWallCollision =
false;
160 if (collide()->someSoftWallTimer() > 0) {
161 if (collide()->someNonSoftWallTimer() == 0) {
162 softWallCollision =
true;
164 f32 softSusp = collide()->suspBottomHeightSoftWall() /
165 static_cast<f32
>(collide()->someSoftWallTimer());
166 f32 nonSusp = collide()->suspBottomHeightNonSoftWall() /
167 static_cast<f32
>(collide()->someNonSoftWallTimer());
169 if (softSusp - nonSusp >= 40.0f) {
170 m_status.
resetBit(eStatus::SoftWallDrift);
172 softWallCollision =
true;
177 u16 wheelCollisions = 0;
178 u16 softWallCount = 0;
180 bool trickable =
false;
182 for (
u16 tireIdx = 0; tireIdx < tireCount(); ++tireIdx) {
183 const auto &colData = collisionData(tireIdx);
184 if (hasFloorCollision(tirePhysics(tireIdx))) {
185 m_top += colData.floorNrm;
186 trickable = trickable || colData.bTrickable;
190 if (softWallCollision && colData.bSoftWall) {
192 wallNrm += colData.noBounceWallNrm;
196 if (wheelCollisions > 0) {
198 if (wheelCollisions == tireCount()) {
206 m_top += colData.floorNrm;
207 trickable = trickable || colData.bTrickable;
210 halfPipe()->end(
true);
214 bool hitboxGroupSoftWallCollision =
false;
215 if (softWallCollision && colData.bSoftWall) {
216 hitboxGroupSoftWallCollision =
true;
218 wallNrm += colData.wallNrm;
221 bool bVar3 = colData.bInvisibleWallOnly && m_halfPipeInvisibilityTimer > 0;
222 m_halfPipeInvisibilityTimer = std::max(0, m_halfPipeInvisibilityTimer - 1);
237 if (!wasWallCollision) {
241 if (m_status.
offBit(eStatus::TriggerRespawn, eStatus::InRespawn,
243 eStatus::CannonStart, eStatus::InCannon)) {
244 action()->
start(Kart::Action::UNK_1);
251 if (m_hwgTimer == 0 && colData.movement.y > 1.0f) {
255 if (movement.
dot(EGG::Vector3f::ey) > 0.8f &&
256 colData.wallNrm.
dot(EGG::Vector3f::ey) > 0.85f &&
257 (movement.x * colData.wallNrm.x + movement.z * colData.wallNrm.z < 0.0f ||
258 collide()->colPerpendicularity() >= 1.0f)) {
259 colData.wallNrm.y = 0.0f;
261 wallNrm = colData.wallNrm;
263 if (wallNrm.
length() < 0.05f) {
274 collide()->surfaceFlags().offBit(KartCollide::eSurfaceFlags::StopHalfPipeState)) {
278 if (softWallCount > 0 || hwg) {
279 m_status.
setBit(eStatus::UNK2);
280 m_softWallSpeed = wallNrm;
283 m_status.
setBit(eStatus::SoftWallDrift);
290 if (hitboxGroupSoftWallCollision || hwg || isBike()) {
291 m_status.
setBit(eStatus::SomethingWallCollision);
301 m_trickableTimer = std::max(0, m_trickableTimer - 1);
303 if (wheelCollisions < 1 && !colData.
bFloor) {
304 if (wasTouchingGround) {
305 m_status.
setBit(eStatus::AirStart);
308 if (++m_airtime > 20) {
316 if (m_status.
offBit(eStatus::InAction)) {
321 halfPipe()->end(
true);
325 m_trickableTimer = 3;
328 m_status.
changeBit(m_trickableTimer > 0, eStatus::Trickable);
330 if (m_status.
offBit(eStatus::JumpPad)) {
331 m_status.
resetBit(eStatus::JumpPadMushroomCollision);
334 if (!wasTouchingGround) {
338 if (m_status.
onBit(eStatus::InATrick) && jump()->cooldown() == 0) {
340 dynamics()->setForceUpright(
true);
353 constexpr f32 START_BOOST_DELTA_ONE = 0.02f;
354 constexpr f32 START_BOOST_DELTA_TWO = 0.002f;
355 constexpr f32 START_BOOST_FALLOFF = 0.96f;
371 if (System::RaceManager::Instance()->getCountdownTimer() != 0) {
380 for (
size_t i = 1; i < START_BOOST_ENTRIES.size(); ++i) {
403 move()->burnout().start();
405 move()->applyStartBoost(START_BOOST_ENTRIES[idx].frames);
@ COL_TYPE_SPECIAL_WALL
Various other wall types, determined by variant.
constexpr TBitFlagExt< N, E > & changeBit(bool on, Es... es)
Changes the state of the corresponding bits for the provided enum values.
constexpr bool offBit(Es... es) const
Checks if all of the corresponding bits for the provided enum values are off.
constexpr TBitFlagExt< N, E > & makeAllZero()
Resets all the bits to zero across the entire bitfield array.
constexpr bool onBit(Es... es) const
Checks if any of the corresponding bits for the provided enum values are on.
constexpr TBitFlagExt< N, E > & resetBit(Es... es)
Resets the corresponding bits for the provided enum values.
constexpr TBitFlagExt< N, E > & setBit(Es... es)
Sets the corresponding bits for the provided enum values.
bool start(Action action)
Starts an action.
size_t m_startBoostIdx
Used to map m_startBoostCharge to a start boost duration.
void calcStartBoost()
STAGE 1 - Each frame, calculates the start boost charge.
s16 m_wallBonkTimer
2f counter that stunts your speed after hitting a wall.
void calcCollisions()
Each frame, checks for collision and saves relevant bit flags.
void calcHandleStartBoost()
On countdown end, calculates and applies our start boost charge.
f32 m_stickY
One of 15 discrete stick values from [-1.0, 1.0].
void handleStartBoost(size_t idx)
Applies the relevant start boost duration.
void calc()
Every frame, resets the input state and saves collision-related bit flags.
f32 m_stickX
One of 15 discrete stick values from [-1.0, 1.0].
f32 m_startBoostCharge
0-1 representation of start boost charge. Burnout if >0.95f.
void calcInput()
Each frame, read input and save related bit flags. Also handles start boosts.
void resetEjection()
Resets certain bitfields pertaining to ejections (reject road, half pipe zippers, etc....
Pertains to kart-related functionality.
@ HopStart
Set if m_bDriftInput was toggled on this frame.
@ RejectRoad
Collision which causes a change in the player's pos and rot.
@ HalfPipeRamp
Set while colliding with zipper KCL.
@ HWG
Set when "Horizontal Wall Glitch" is active.
@ Hop
Set while we are in a drift hop. Clears when we land.
@ StickLeft
Set on left stick input. Mutually exclusive to m_bStickRight.
@ VehicleBodyFloorCollision
Set if the vehicle body is colliding with the floor.
@ ChargeStartBoost
Like m_bAccelerate but during countdown.
@ RejectRoadTrigger
e.g. DK Summit ending, and Maple Treeway side walls.
@ GroundStart
Set first frame landing from airtime.
@ AllWheelsCollision
Set when all wheels are touching floor collision.
@ Accelerate
Accel button is pressed.
@ StickRight
Set on right stick input. Mutually exclusive to m_bStickLeft.
@ ActionMidZipper
Set when we enter an action while mid-air from a zipper.
@ DriftInput
A "fake" button, normally set if you meet the speed requirement to hop.
@ AirtimeOver20
Set after 20 frames of airtime, resets on landing.
@ OverZipper
Set while mid-air from a zipper.
@ AccelerateStart
Set if m_bAccelerate was toggled on this frame.
@ Burnout
Set during a burnout on race start.
@ WallCollisionStart
Set if we have just started colliding with a wall.
@ AnyWheelCollision
Set when any wheel is touching floor collision.
@ AutoDrift
True if auto transmission, false if manual.
@ Wall3Collision
Set when colliding with wall KCL COL_TYPE_WALL_2.
@ TouchingGround
Set when any part of the vehicle is colliding with floor KCL.
@ ZipperInvisibleWall
Set when colliding with invisible wall above a zipper.
@ BeforeRespawn
Set on respawn collision, cleared on position snap.
@ WallCollision
Set if we are colliding with a wall.
f32 normalise()
Normalizes the vector and returns the original length.
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
f32 length() const
The square root of the vector's dot product.
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.