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) {
24KartJump::~KartJump() =
default;
27void KartJump::calcRot() {
28 m_angleDelta *= m_angleDeltaFactor;
29 m_angleDelta = std::max(m_angleDelta, m_properties.angleDeltaMin);
30 m_angleDeltaFactor -= m_angleDeltaFactorDec;
31 m_angleDeltaFactor = std::max(m_angleDeltaFactor, m_properties.angleDeltaFactorMin);
32 m_angle += m_angleDelta;
33 m_angle = std::min(m_angle, m_finalAngle);
36 case TrickType::KartFlipTrickZ:
37 m_rot.setRPY(0.0f, 0.0f, -(m_angle * DEG2RAD) * m_rotSign);
39 case TrickType::FlipTrickYLeft:
40 case TrickType::FlipTrickYRight:
41 m_rot.setRPY(0.0f, m_angle * DEG2RAD * m_rotSign, 0.0f);
47 physics()->composeStuntRot(m_rot);
51void KartJump::setupProperties() {
52 static constexpr std::array<TrickProperties, 3> TRICK_PROPERTIES = {{
53 {11.0f, 1.5f, 0.9f, 0.0018f},
54 {14.0f, 1.5f, 0.9f, 0.0006f},
55 {7.5f, 2.5f, 0.93f, 0.05f},
58 static constexpr std::array<f32, 3> FINAL_ANGLES = {{
64 if (m_variant == SurfaceVariant::SingleFlipTrick) {
65 m_properties = TRICK_PROPERTIES[0];
66 m_finalAngle = FINAL_ANGLES[0];
67 }
else if (m_variant == SurfaceVariant::StuntTrick) {
68 m_properties = TRICK_PROPERTIES[1];
69 m_finalAngle = FINAL_ANGLES[1];
70 }
else if (m_type == TrickType::BikeSideStuntTrick) {
71 m_properties = TRICK_PROPERTIES[2];
72 m_finalAngle = FINAL_ANGLES[2];
75 m_angleDelta = m_properties.initialAngleDiff;
76 m_angleDeltaFactorDec = m_properties.angleDiffMulDec;
78 m_angleDeltaFactor = 1.0f;
79 m_rot = EGG::Quatf::ident;
83void KartJump::reset() {
88void KartJump::tryStart(
const EGG::Vector3f &left) {
89 auto &status = KartObjectProxy::status();
91 if (status.offBit(eStatus::TrickStart)) {
95 if (m_move->speedRatioCapped() > 0.5f) {
96 s32 boostRampType = state()->boostRampType();
98 if (boostRampType == 0) {
99 m_variant = SurfaceVariant::StuntTrick;
100 }
else if (boostRampType == 1) {
101 m_variant = SurfaceVariant::SingleFlipTrick;
103 m_variant = SurfaceVariant::DoubleFlipTrick;
109 status.resetBit(eStatus::TrickStart);
113void KartJump::calc() {
114 m_cooldown = std::max(0, m_cooldown - 1);
116 if (status().onBit(eStatus::TrickRot)) {
123bool KartJump::someFlagCheck() {
124 return status().onBit(eStatus::InAction, eStatus::TrickStart, eStatus::InATrick,
125 eStatus::OverZipper);
129void KartJump::calcInput() {
130 constexpr s16 TRICK_ALLOW_TIMER = 14;
132 System::Trick trick = inputs()->currentState().trick;
134 if (!someFlagCheck() && trick != System::Trick::None) {
136 m_nextAllowTimer = TRICK_ALLOW_TIMER;
139 auto &status = KartObjectProxy::status();
141 u32 airtime = state()->airtime();
142 if (airtime == 0 || m_nextAllowTimer < 1 || airtime > 10 ||
143 (status.offBit(eStatus::Trickable) && state()->boostRampType() < 0) ||
145 m_nextAllowTimer = std::max(0, m_nextAllowTimer - 1);
148 status.setBit(eStatus::TrickStart);
150 if (status.onBit(eStatus::RampBoost)) {
151 m_boostRampEnabled =
true;
154 if (status.onBit(eStatus::TouchingGround) &&
155 collide()->surfaceFlags().offBit(KartCollide::eSurfaceFlags::BoostRamp)) {
156 m_boostRampEnabled =
false;
161void KartJump::end() {
162 auto &status = KartObjectProxy::status();
164 if (status.onBit(eStatus::TrickRot)) {
165 physics()->composeDecayingStuntRot(m_rot);
168 status.resetBit(eStatus::InATrick, eStatus::TrickRot);
169 m_boostRampEnabled =
false;
173void KartJump::setAngle(
const EGG::Vector3f &left) {
174 static constexpr std::array<std::array<AngleProperties, 3>, 3> ANGLE_PROPERTIES = {{
192 f32 vel1YDot = m_move->vel1Dir().dot(EGG::Vector3f::ey);
193 EGG::Vector3f vel1YCross = m_move->vel1Dir().cross(EGG::Vector3f::ey);
194 f32 vel1YCrossMag = vel1YCross.length();
195 f32 pitch = EGG::Mathf::abs(EGG::Mathf::atan2(vel1YCrossMag, vel1YDot));
196 f32 angle = 90.0f - (pitch * RAD2DEG);
197 u32 weightClass =
static_cast<u32
>(param()->stats().weightClass);
198 f32 targetAngle = ANGLE_PROPERTIES[weightClass][
static_cast<u32
>(m_variant)].targetAngle;
200 if (status().onBit(eStatus::JumpPad) || angle > targetAngle) {
204 f32 rotAngle = ANGLE_PROPERTIES[weightClass][
static_cast<u32
>(m_variant)].rotAngle;
206 if (angle + rotAngle > targetAngle) {
207 rotAngle = targetAngle - angle;
210 EGG::Matrix34f nextDir;
211 nextDir.setAxisRotation(-rotAngle * DEG2RAD, left);
212 m_move->setDir(nextDir.ps_multVector(m_move->dir()));
213 m_move->setVel1Dir(m_move->dir());
217void KartJump::start(
const EGG::Vector3f &left) {
220 status().setBit(eStatus::InATrick);
225void KartJump::init() {
226 if (m_variant == SurfaceVariant::DoubleFlipTrick) {
227 m_type = TrickType::StuntTrickBasic;
231 if (m_nextTrick < System::Trick::Left) {
232 m_type = TrickType::KartFlipTrickZ;
233 m_rotSign = (m_nextTrick == System::Trick::Up) ? -1.0f : 1.0f;
235 m_type =
static_cast<TrickType
>(m_nextTrick);
236 m_rotSign = (m_type == TrickType::FlipTrickYRight) ? -1.0f : 1.0f;
240 status().setBit(eStatus::TrickRot);
243KartJumpBike::KartJumpBike(KartMove *move) : KartJump(move) {}
246KartJumpBike::~KartJumpBike() =
default;
251 constexpr f32 PI_OVER_9 = 0.34906584f;
253 constexpr f32 PI_OVER_3 = 1.0471976f;
255 m_angleDelta *= m_angleDeltaFactor;
256 m_angleDelta = std::max(m_angleDelta, m_properties.angleDeltaMin);
257 m_angleDeltaFactor -= m_angleDeltaFactorDec;
258 m_angleDeltaFactor = std::max(m_angleDeltaFactor, m_properties.angleDeltaFactorMin);
259 m_angle += m_angleDelta;
260 m_angle = std::min(m_angle, m_finalAngle);
265 m_rot.setRPY(-(m_angle * DEG2RAD) * m_rotSign, 0.0f, 0.0f);
269 m_rot.setRPY(0.0f, m_angle * DEG2RAD * m_rotSign, 0.0f);
272 f32 sin = EGG::Mathf::SinFIdx(m_angle * DEG2FIDX);
273 m_rot.setRPY(sin * -PI_OVER_9, (sin * m_rotSign) * -PI_OVER_3,
274 (sin * m_rotSign) * PI_OVER_9);
280 physics()->composeStuntRot(m_rot);
285 KartJump::start(left);
292void KartJumpBike::init() {
293 constexpr f32 DOUBLE_FLIP_TRICK_FINAL_ANGLE = 180.0f;
295 if (m_variant == SurfaceVariant::DoubleFlipTrick) {
296 if (m_nextTrick < System::Trick::Left) {
300 m_type = TrickType::BikeSideStuntTrick;
301 m_rotSign = (m_nextTrick == System::Trick::Right) ? -1.0f : 1.0f;
303 m_finalAngle = DOUBLE_FLIP_TRICK_FINAL_ANGLE;
305 m_type =
static_cast<TrickType
>(m_nextTrick);
307 (m_type == TrickType::FlipTrickYRight || m_type == TrickType::BikeFlipTrickTail) ?
313 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.