3#include "game/kart/KartCollide.hh"
4#include "game/kart/KartMove.hh"
5#include "game/kart/KartParam.hh"
6#include "game/kart/KartPhysics.hh"
7#include "game/kart/KartState.hh"
9#include "game/system/KPadController.hh"
11#include <egg/math/Math.hh>
16KartJump::KartJump(
KartMove *move) : m_move(move) {
20 m_type = TrickType::StuntTrickBasic;
25KartJump::~KartJump() =
default;
28void KartJump::calcRot() {
29 m_angleDelta *= m_angleDeltaFactor;
30 m_angleDelta = std::max(m_angleDelta, m_properties.angleDeltaMin);
31 m_angleDeltaFactor -= m_angleDeltaFactorDec;
32 m_angleDeltaFactor = std::max(m_angleDeltaFactor, m_properties.angleDeltaFactorMin);
33 m_angle += m_angleDelta;
34 m_angle = std::min(m_angle, m_finalAngle);
37 case TrickType::KartFlipTrickZ:
38 m_rot.setRPY(0.0f, 0.0f, -(m_angle * DEG2RAD) * m_rotSign);
40 case TrickType::FlipTrickYLeft:
41 case TrickType::FlipTrickYRight:
42 m_rot.setRPY(0.0f, m_angle * DEG2RAD * m_rotSign, 0.0f);
48 physics()->composeStuntRot(m_rot);
52void KartJump::setupProperties() {
53 static constexpr std::array<TrickProperties, 3> TRICK_PROPERTIES = {{
54 {11.0f, 1.5f, 0.9f, 0.0018f},
55 {14.0f, 1.5f, 0.9f, 0.0006f},
56 {7.5f, 2.5f, 0.93f, 0.05f},
59 static constexpr std::array<f32, 3> FINAL_ANGLES = {{
65 if (m_variant == SurfaceVariant::SingleFlipTrick) {
66 m_properties = TRICK_PROPERTIES[0];
67 m_finalAngle = FINAL_ANGLES[0];
68 }
else if (m_variant == SurfaceVariant::StuntTrick) {
69 m_properties = TRICK_PROPERTIES[1];
70 m_finalAngle = FINAL_ANGLES[1];
71 }
else if (m_type == TrickType::BikeSideStuntTrick) {
72 m_properties = TRICK_PROPERTIES[2];
73 m_finalAngle = FINAL_ANGLES[2];
76 m_angleDelta = m_properties.initialAngleDiff;
77 m_angleDeltaFactorDec = m_properties.angleDiffMulDec;
79 m_angleDeltaFactor = 1.0f;
80 m_rot = EGG::Quatf::ident;
84void KartJump::reset() {
89void KartJump::tryStart(
const EGG::Vector3f &left) {
90 auto &status = KartObjectProxy::status();
92 if (status.offBit(eStatus::TrickStart)) {
96 if (m_move->speedRatioCapped() > 0.5f) {
97 s32 boostRampType = state()->boostRampType();
99 if (boostRampType == 0) {
100 m_variant = SurfaceVariant::StuntTrick;
101 }
else if (boostRampType == 1) {
102 m_variant = SurfaceVariant::SingleFlipTrick;
104 m_variant = SurfaceVariant::DoubleFlipTrick;
110 status.resetBit(eStatus::TrickStart);
114void KartJump::calc() {
115 m_cooldown = std::max(0, m_cooldown - 1);
117 if (status().onBit(eStatus::TrickRot)) {
124bool KartJump::someFlagCheck() {
125 return status().onBit(eStatus::InAction, eStatus::TrickStart, eStatus::InATrick,
126 eStatus::OverZipper);
130void KartJump::calcInput() {
131 constexpr s16 TRICK_ALLOW_TIMER = 14;
133 System::Trick trick = inputs()->currentState().trick;
135 if (!someFlagCheck() && trick != System::Trick::None) {
137 m_nextAllowTimer = TRICK_ALLOW_TIMER;
140 auto &status = KartObjectProxy::status();
142 u32 airtime = state()->airtime();
143 if (airtime == 0 || m_nextAllowTimer < 1 || airtime > 10 ||
144 (status.offBit(eStatus::Trickable) && state()->boostRampType() < 0) ||
146 m_nextAllowTimer = std::max(0, m_nextAllowTimer - 1);
149 status.setBit(eStatus::TrickStart);
151 if (status.onBit(eStatus::RampBoost)) {
152 m_boostRampEnabled =
true;
155 if (status.onBit(eStatus::TouchingGround) &&
156 collide()->surfaceFlags().offBit(KartCollide::eSurfaceFlags::BoostRamp)) {
157 m_boostRampEnabled =
false;
162void KartJump::end() {
163 auto &status = KartObjectProxy::status();
165 if (status.onBit(eStatus::TrickRot)) {
166 physics()->composeDecayingStuntRot(m_rot);
169 status.resetBit(eStatus::InATrick, eStatus::TrickRot);
170 m_boostRampEnabled =
false;
174void KartJump::setAngle(
const EGG::Vector3f &left) {
175 static constexpr std::array<std::array<AngleProperties, 3>, 3> ANGLE_PROPERTIES = {{
193 f32 vel1YDot = m_move->vel1Dir().dot(EGG::Vector3f::ey);
194 EGG::Vector3f vel1YCross = m_move->vel1Dir().cross(EGG::Vector3f::ey);
195 f32 vel1YCrossMag = vel1YCross.length();
196 f32 pitch = EGG::Mathf::abs(EGG::Mathf::atan2(vel1YCrossMag, vel1YDot));
197 f32 angle = 90.0f - (pitch * RAD2DEG);
198 u32 weightClass =
static_cast<u32
>(param()->stats().weightClass);
199 f32 targetAngle = ANGLE_PROPERTIES[weightClass][
static_cast<u32
>(m_variant)].targetAngle;
201 if (status().onBit(eStatus::JumpPad) || angle > targetAngle) {
205 f32 rotAngle = ANGLE_PROPERTIES[weightClass][
static_cast<u32
>(m_variant)].rotAngle;
207 if (angle + rotAngle > targetAngle) {
208 rotAngle = targetAngle - angle;
211 EGG::Matrix34f nextDir;
212 nextDir.setAxisRotation(-rotAngle * DEG2RAD, left);
213 m_move->setDir(nextDir.ps_multVector(m_move->dir()));
214 m_move->setVel1Dir(m_move->dir());
218void KartJump::start(
const EGG::Vector3f &left) {
221 status().setBit(eStatus::InATrick);
226void KartJump::init() {
227 if (m_variant == SurfaceVariant::DoubleFlipTrick) {
228 m_type = TrickType::StuntTrickBasic;
232 if (m_nextTrick < System::Trick::Left) {
233 m_type = TrickType::KartFlipTrickZ;
234 m_rotSign = (m_nextTrick == System::Trick::Up) ? -1.0f : 1.0f;
236 m_type =
static_cast<TrickType
>(m_nextTrick);
237 m_rotSign = (m_type == TrickType::FlipTrickYRight) ? -1.0f : 1.0f;
241 status().setBit(eStatus::TrickRot);
244KartJumpBike::KartJumpBike(KartMove *move) : KartJump(move) {}
247KartJumpBike::~KartJumpBike() =
default;
252 constexpr f32 PI_OVER_9 = 0.34906584f;
254 constexpr f32 PI_OVER_3 = 1.0471976f;
256 m_angleDelta *= m_angleDeltaFactor;
257 m_angleDelta = std::max(m_angleDelta, m_properties.angleDeltaMin);
258 m_angleDeltaFactor -= m_angleDeltaFactorDec;
259 m_angleDeltaFactor = std::max(m_angleDeltaFactor, m_properties.angleDeltaFactorMin);
260 m_angle += m_angleDelta;
261 m_angle = std::min(m_angle, m_finalAngle);
266 m_rot.setRPY(-(m_angle * DEG2RAD) * m_rotSign, 0.0f, 0.0f);
270 m_rot.setRPY(0.0f, m_angle * DEG2RAD * m_rotSign, 0.0f);
273 f32 sin = EGG::Mathf::SinFIdx(m_angle * DEG2FIDX);
274 m_rot.setRPY(sin * -PI_OVER_9, (sin * m_rotSign) * -PI_OVER_3,
275 (sin * m_rotSign) * PI_OVER_9);
281 physics()->composeStuntRot(m_rot);
286 KartJump::start(left);
293void KartJumpBike::init() {
294 constexpr f32 DOUBLE_FLIP_TRICK_FINAL_ANGLE = 180.0f;
296 if (m_variant == SurfaceVariant::DoubleFlipTrick) {
297 if (m_nextTrick < System::Trick::Left) {
301 m_type = TrickType::BikeSideStuntTrick;
302 m_rotSign = (m_nextTrick == System::Trick::Right) ? -1.0f : 1.0f;
304 m_finalAngle = DOUBLE_FLIP_TRICK_FINAL_ANGLE;
306 m_type =
static_cast<TrickType
>(m_nextTrick);
308 (m_type == TrickType::FlipTrickYRight || m_type == TrickType::BikeFlipTrickTail) ?
314 status().setBit(eStatus::TrickRot);
Responsible for reacting to player inputs and moving the bike.
virtual void cancelWheelie()
Clears the wheelie bit flag and resets the rotation decrement.
Responsible for reacting to player inputs and moving the kart.
Pertains to kart-related functionality.
@ FlipTrickYLeft
A left trick with kart/bike.
@ BikeSideStuntTrick
A side StuntTrick with a bike.
@ BikeFlipTrickTail
A down trick with bike.
@ BikeFlipTrickNose
An up trick with bike.
@ FlipTrickYRight
A right trick with kart/bike.