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() {
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;
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;
213 m_move->setVel1Dir(m_move->dir());
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;
249void KartJumpBike::calcRot() {
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);
263 case TrickType::BikeFlipTrickNose:
264 case TrickType::BikeFlipTrickTail:
265 m_rot.setRPY(-(m_angle * DEG2RAD) * m_rotSign, 0.0f, 0.0f);
267 case TrickType::FlipTrickYLeft:
268 case TrickType::FlipTrickYRight:
269 m_rot.setRPY(0.0f, m_angle * DEG2RAD * m_rotSign, 0.0f);
271 case TrickType::BikeSideStuntTrick: {
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);
void setAxisRotation(f32 angle, const Vector3f &axis)
Rotates the matrix about an axis.
Vector3f ps_multVector(const Vector3f &vec) const
Paired-singles impl. of multVector.
Responsible for reacting to player inputs and moving the bike.
virtual void cancelWheelie()
Clears the wheelie bit flag and resets the rotation decrement.
Pertains to kart-related functionality.
f32 length() const
The square root of the vector's dot product.