1#include "KartAction.hh"
3#include "game/kart/KartMove.hh"
4#include "game/kart/KartPhysics.hh"
5#include "game/kart/KartState.hh"
7#include "game/item/ItemDirector.hh"
8#include "game/item/KartItem.hh"
10#include <egg/math/Math.hh>
15KartAction::KartAction()
16 : m_currentAction(Action::None), m_hitDepth(
EGG::Vector3f::zero),
17 m_translation(
EGG::Vector3f::ez), m_onStart(nullptr), m_onCalc(nullptr), m_onEnd(nullptr),
18 m_actionParams(nullptr), m_rotationParams(nullptr), m_priority(0) {}
21KartAction::~KartAction() =
default;
24void KartAction::init() {
25 m_currentAction = Action::None;
26 m_flags.makeAllZero();
30void KartAction::calc() {
31 if (m_currentAction == Action::None || !m_onCalc) {
35 if (calcCurrentAction()) {
41void KartAction::calcVehicleSpeed() {
42 move()->setSpeed(m_actionParams->calcSpeedMult * move()->speed());
49bool KartAction::start(Action action) {
50 ASSERT(action != Action::None);
52 auto &status = KartObjectProxy::status();
54 if (status.onBit(eStatus::InRespawn, eStatus::AfterRespawn, eStatus::BeforeRespawn,
59 if (status.onBit(eStatus::ZipperStick)) {
66 action = Action::UNK_1;
73 size_t actionIdx =
static_cast<size_t>(action);
75 if (m_currentAction != Action::None && s_actionParams[actionIdx].priority <= m_priority) {
80 m_currentAction = action;
81 m_actionParams = &s_actionParams[actionIdx];
82 m_priority = m_actionParams->priority;
83 m_onStart = s_onStart[actionIdx];
84 m_onCalc = s_onCalc[actionIdx];
85 m_onEnd = s_onEnd[actionIdx];
86 status.setBit(eStatus::InAction);
88 m_flags.makeAllZero();
102void KartAction::startRotation(
size_t idx) {
103 m_rotation = EGG::Quatf::ident;
106 if (speed() < 0.0f) {
110 m_rotationDirection = dir.cross(bodyFront()).
dot(bodyUp()) > 0.0f ? 1.0f : -1.0f;
112 m_flags.setBit(eFlags::Rotating);
116void KartAction::calcSideFromHitDepth() {
117 m_hitDepth.normalise();
118 m_side = m_hitDepth.perpInPlane(move()->smoothedUp(),
true);
120 if (m_side.squaredLength() <= std::numeric_limits<f32>::epsilon()) {
121 m_side = EGG::Vector3f::ey;
126void KartAction::calcSideFromHitDepthAndTranslation() {
127 calcSideFromHitDepth();
130 f32 sign = (cross.y > 0.0f) ? 1.0f : -1.0f;
132 EGG::Vector3f worldSide = EGG::Vector3f::ey.cross(m_translation);
135 m_side = worldSide.
perpInPlane(move()->smoothedUp(),
true);
137 if (m_side.squaredLength() > std::numeric_limits<f32>::epsilon()) {
140 m_side = EGG::Vector3f::ey;
145void KartAction::end() {
146 status().resetBit(eStatus::InAction, eStatus::LargeFlipHit);
147 dynamics()->setForceUpright(
true);
149 m_currentAction = Action::None;
151 m_flags.makeAllZero();
157bool KartAction::calcCurrentAction() {
159 return (this->*m_onCalc)();
163void KartAction::calcEndAction(
bool endArg) {
164 if (m_currentAction == Action::None) {
169 (this->*m_onEnd)(endArg);
175bool KartAction::calcRotation() {
176 if (!m_rotationParams) {
181 if (m_currentAngle > m_finalAngle * m_rotationParams->slowdownThreshold) {
182 m_angleIncrement *= m_multiplier;
183 if (m_rotationParams->minAngleIncrement > m_angleIncrement) {
184 m_angleIncrement = m_rotationParams->minAngleIncrement;
187 m_multiplier -= m_multiplierDecrement;
188 if (m_rotationParams->minMultiplier > m_multiplier) {
189 m_multiplier = m_rotationParams->minMultiplier;
193 m_currentAngle += m_angleIncrement;
194 if (m_finalAngle < m_currentAngle) {
195 m_currentAngle = m_finalAngle;
203void KartAction::calcUp() {
204 m_up += (move()->up() - m_up) * 0.3f;
208void KartAction::calcLanding() {
209 if (m_currentAngle < m_targetRot || status().offBit(eStatus::TouchingGround)) {
213 m_flags.setBit(eFlags::Landing);
216 dynamics()->setForceUpright(
false);
219 physics()->composeDecayingExtraRot(m_rotation);
223void KartAction::startLaunch(f32 extVelScalar, f32 extVelKart, f32 extVelBike, f32 numRotations,
225 m_targetRot = 360.0f * numRotations;
228 extVel.y = isBike() ? extVelBike : extVelKart;
231 m_hitDepth = move()->dir();
232 calcSideFromHitDepth();
233 }
else if (param6 == 1) {
234 calcSideFromHitDepth();
235 extVel += extVelScalar * m_side;
236 }
else if (param6 == 2) {
237 calcSideFromHitDepthAndTranslation();
238 extVel += extVelScalar * m_side;
241 setRotation(
static_cast<size_t>(numRotations + 3.0f));
242 m_groundStartLaunchTimer = 0;
243 m_rotAxis = move()->smoothedUp().cross(m_side);
245 dynamics()->setExtVel(dynamics()->extVel() + extVel);
249void KartAction::activateCrush(
u16 timer) {
250 move()->activateCrush(m_crushTimer + timer);
251 Item::ItemDirector::Instance()->kartItem(0).clear();
255void KartAction::applyStartSpeed() {
256 move()->setSpeed(m_actionParams->startSpeedMult * move()->speed());
257 if (m_actionParams->startSpeedMult == 0.0f) {
258 move()->clearDrift();
263void KartAction::setRotation(
size_t idx) {
264 ASSERT(idx - 1 < s_rotationParams.size());
265 m_rotationParams = &s_rotationParams[--idx];
267 m_finalAngle = m_rotationParams->finalAngle;
268 m_angleIncrement = m_rotationParams->initialAngleIncrement;
269 m_multiplierDecrement = m_rotationParams->initialMultiplierDecrement;
270 m_currentAngle = 0.0f;
278void KartAction::startStub() {}
281void KartAction::startAction1() {
286void KartAction::startAction2() {
287 constexpr f32 EXT_VEL_SCALAR = 0.0f;
288 constexpr f32 EXT_VEL_KART = 30.0f;
289 constexpr f32 EXT_VEL_BIKE = 30.0f;
290 constexpr f32 NUM_ROTATIONS = 1.0f;
292 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 0);
296void KartAction::startAction3() {
297 constexpr f32 EXT_VEL_SCALAR = 25.0f;
298 constexpr f32 EXT_VEL_KART = 30.0f;
299 constexpr f32 EXT_VEL_BIKE = 30.0f;
300 constexpr f32 NUM_ROTATIONS = 1.0f;
302 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 1);
303 Item::ItemDirector::Instance()->kartItem(0).clear();
307void KartAction::startAction4() {
308 constexpr f32 EXT_VEL_SCALAR = 25.0f;
309 constexpr f32 EXT_VEL_KART = 30.0f;
310 constexpr f32 EXT_VEL_BIKE = 30.0f;
311 constexpr f32 NUM_ROTATIONS = 2.0f;
313 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 1);
314 Item::ItemDirector::Instance()->kartItem(0).clear();
318void KartAction::startAction5() {
319 constexpr f32 EXT_VEL_SCALAR = 13.0f;
320 constexpr f32 EXT_VEL_KART = 40.0f;
321 constexpr f32 EXT_VEL_BIKE = 45.0f;
322 constexpr f32 NUM_ROTATIONS = 1.0f;
324 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 2);
328void KartAction::startLargeFlipAction() {
331 dynamics()->setExtVel(INIT_VEL);
332 dynamics()->setAngVel0(EGG::Vector3f::zero);
334 if (m_currentAction == Action::UNK_8) {
335 calcSideFromHitDepth();
336 dynamics()->setExtVel(dynamics()->extVel() + m_side * -20.0f);
339 Item::ItemDirector::Instance()->kartItem(0).clear();
345 m_framesFlipping = 0;
347 status().setBit(eStatus::LargeFlipHit);
351void KartAction::startAction9() {
356void KartAction::startLongPressAction() {
357 constexpr u32 ACTION_DURATION = 90;
358 constexpr u16 CRUSH_DURATION = 480;
360 m_crushTimer = ACTION_DURATION;
361 activateCrush(CRUSH_DURATION);
365void KartAction::startShortPressAction() {
366 constexpr u32 ACTION_DURATION = 30;
367 constexpr u16 CRUSH_DURATION = 240;
369 m_crushTimer = ACTION_DURATION;
370 activateCrush(CRUSH_DURATION);
374void KartAction::startSpinShrinkAction() {
382bool KartAction::calcStub() {
387bool KartAction::calcAction1() {
389 bool finished = calcRotation();
391 m_rotation.setAxisRotation(DEG2RAD * (m_currentAngle * m_rotationDirection), m_up);
392 physics()->composeExtraRot(m_rotation);
397bool KartAction::calcLaunchAction() {
398 constexpr u32 ACTION_DURATION = 100;
400 if (m_flags.offBit(eFlags::Landing)) {
405 bool actionEnded = m_frame >= ACTION_DURATION;
408 if (m_flags.offBit(eFlags::Landing)) {
409 physics()->composeDecayingExtraRot(m_rotation);
411 }
else if (m_flags.offBit(eFlags::Landing)) {
412 m_rotation.setAxisRotation(DEG2RAD * m_currentAngle, m_rotAxis);
413 physics()->composeExtraRot(m_rotation);
420bool KartAction::calcAction4() {
421 constexpr u32 ACTION_DURATION = 140;
423 auto &status = state()->status();
424 if (status.onBit(eStatus::GroundStart)) {
425 if (m_groundStartLaunchTimer++ == 0) {
428 dynamics()->setExtVel(extVel);
432 if (m_flags.offBit(eFlags::Landing)) {
437 bool actionEnded = m_frame >= ACTION_DURATION;
440 if (m_flags.offBit(eFlags::Landing)) {
441 physics()->composeDecayingExtraRot(m_rotation);
443 }
else if (m_flags.offBit(eFlags::Landing)) {
444 m_rotation.setAxisRotation(DEG2RAD * m_currentAngle, m_rotAxis);
445 physics()->composeExtraRot(m_rotation);
452bool KartAction::calcLargeFlipAction() {
453 constexpr f32 PITCH_DECAY = 0.971f;
454 constexpr f32 TOTAL_DELTA_PITCH = 720.0f;
455 constexpr f32 PHASE_DELTA = 4.0f;
456 constexpr f32 WOBBLE_AMPLITUDE = 18.1f;
457 constexpr f32 BOUNCE_FACTOR = 5.0f;
459 bool decayingRot =
false;
460 bool stuntRot =
false;
462 if (m_flags.onBit(eFlags::LargeFlip)) {
465 if (m_deltaPitch < TOTAL_DELTA_PITCH) {
466 m_deltaPitch += m_velPitch;
467 m_pitch -= m_velPitch;
468 m_velPitch *= (m_velPitch > 1.0f) ? PITCH_DECAY : 1.0f;
475 if (EGG::Mathf::abs(m_flipPhase) < 360.0f) {
476 m_flipPhase += PHASE_DELTA;
477 sin = EGG::Mathf::SinFIdx(DEG2FIDX * m_flipPhase);
483 mat.
setAxisRotation(DEG2RAD * (WOBBLE_AMPLITUDE * sin), EGG::Vector3f::ez);
484 m_rotation.setAxisRotation(DEG2RAD * m_pitch, mat.
ps_multVector(EGG::Vector3f::ex));
489 bool actionEnded =
false;
490 auto &status = KartObjectProxy::status();
491 bool touchingGround = status.onBit(eStatus::TouchingGround);
493 if (m_flags.offBit(eFlags::LandingFromFlip) && touchingGround && move()->up().y > 0.0f &&
495 m_flags.setBit(eFlags::LandingFromFlip);
496 dynamics()->setExtVel(move()->up().proj(EGG::Vector3f::ey) * BOUNCE_FACTOR);
499 if ((m_currentAction != Action::UNK_8 && m_frame < 10) || !touchingGround) {
500 dynamics()->setExtVel(
EGG::Vector3f(0.0f, dynamics()->extVel().y, 0.0f));
503 if ((touchingGround && move()->up().dot(EGG::Vector3f::ey) > 0.0f) || m_frame >= 300) {
505 status.resetBit(eStatus::LargeFlipHit);
508 if (m_frame <= 120) {
509 if (m_flags.onBit(eFlags::LargeFlip)) {
510 if (m_framesFlipping > 30) {
514 if (m_frame >= 40 && m_frame <= 80) {
516 m_flags.setBit(eFlags::LargeFlip);
517 status.resetBit(eStatus::LargeFlipHit);
526 physics()->composeDecayingStuntRot(m_rotation);
527 }
else if (stuntRot) {
528 physics()->composeStuntRot(m_rotation);
535bool KartAction::calcPressAction() {
537 extVel.y = std::min(0.0f, extVel.y);
538 dynamics()->setExtVel(extVel);
540 return m_frame > m_crushTimer;
547void KartAction::endStub(
bool ) {}
550void KartAction::endAction1(
bool arg) {
552 physics()->composeDecayingExtraRot(m_rotation);
557void KartAction::endLaunchAction(
bool arg) {
559 physics()->composeDecayingExtraRot(m_rotation);
567const std::array<KartAction::ActionParams, KartAction::MAX_ACTION> KartAction::s_actionParams = {{
588const std::array<KartAction::RotationParams, 5> KartAction::s_rotationParams = {{
589 {10.0f, 1.5f, 0.9f, 0.005f, 0.6f, 360.0f},
590 {11.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 720.0f},
591 {11.0f, 1.5f, 0.9f, 0.0028f, 0.8f, 1080.0f},
592 {7.0f, 1.5f, 0.9f, 0.005f, 0.6f, 450.0f},
593 {9.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 810.0f},
596const std::array<KartAction::StartActionFunc, KartAction::MAX_ACTION> KartAction::s_onStart = {{
597 &KartAction::startStub,
598 &KartAction::startAction1,
599 &KartAction::startAction2,
600 &KartAction::startAction3,
601 &KartAction::startAction4,
602 &KartAction::startAction5,
603 &KartAction::startStub,
604 &KartAction::startLargeFlipAction,
605 &KartAction::startLargeFlipAction,
606 &KartAction::startAction9,
607 &KartAction::startStub,
608 &KartAction::startStub,
609 &KartAction::startLongPressAction,
610 &KartAction::startStub,
611 &KartAction::startShortPressAction,
612 &KartAction::startSpinShrinkAction,
613 &KartAction::startStub,
614 &KartAction::startStub,
617const std::array<KartAction::CalcActionFunc, KartAction::MAX_ACTION> KartAction::s_onCalc = {{
618 &KartAction::calcStub,
619 &KartAction::calcAction1,
620 &KartAction::calcLaunchAction,
621 &KartAction::calcLaunchAction,
622 &KartAction::calcAction4,
623 &KartAction::calcLaunchAction,
624 &KartAction::calcStub,
625 &KartAction::calcLargeFlipAction,
626 &KartAction::calcLargeFlipAction,
627 &KartAction::calcAction1,
628 &KartAction::calcStub,
629 &KartAction::calcStub,
630 &KartAction::calcPressAction,
631 &KartAction::calcStub,
632 &KartAction::calcPressAction,
633 &KartAction::calcAction1,
634 &KartAction::calcStub,
635 &KartAction::calcStub,
638const std::array<KartAction::EndActionFunc, KartAction::MAX_ACTION> KartAction::s_onEnd = {{
639 &KartAction::endStub,
640 &KartAction::endAction1,
641 &KartAction::endLaunchAction,
642 &KartAction::endLaunchAction,
643 &KartAction::endLaunchAction,
644 &KartAction::endLaunchAction,
645 &KartAction::endStub,
646 &KartAction::endStub,
647 &KartAction::endStub,
648 &KartAction::endAction1,
649 &KartAction::endStub,
650 &KartAction::endStub,
651 &KartAction::endStub,
652 &KartAction::endStub,
653 &KartAction::endStub,
654 &KartAction::endAction1,
655 &KartAction::endStub,
656 &KartAction::endStub,
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.
Pertains to kart-related functionality.
f32 normalise()
Normalizes the vector and returns the original length.
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Vector3f perpInPlane(const EGG::Vector3f &rhs, bool normalise) const
Calculates the orthogonal vector, based on the plane defined by this vector and rhs.