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_rotAxis = move()->smoothedUp().cross(m_side);
244 dynamics()->setExtVel(dynamics()->extVel() + extVel);
248void KartAction::activateCrush(
u16 timer) {
249 move()->activateCrush(m_crushTimer + timer);
250 Item::ItemDirector::Instance()->kartItem(0).clear();
254void KartAction::applyStartSpeed() {
255 move()->setSpeed(m_actionParams->startSpeedMult * move()->speed());
256 if (m_actionParams->startSpeedMult == 0.0f) {
257 move()->clearDrift();
262void KartAction::setRotation(
size_t idx) {
263 ASSERT(idx - 1 < s_rotationParams.size());
264 m_rotationParams = &s_rotationParams[--idx];
266 m_finalAngle = m_rotationParams->finalAngle;
267 m_angleIncrement = m_rotationParams->initialAngleIncrement;
268 m_multiplierDecrement = m_rotationParams->initialMultiplierDecrement;
269 m_currentAngle = 0.0f;
277void KartAction::startStub() {}
280void KartAction::startAction1() {
285void KartAction::startAction2() {
286 constexpr f32 EXT_VEL_SCALAR = 0.0f;
287 constexpr f32 EXT_VEL_KART = 30.0f;
288 constexpr f32 EXT_VEL_BIKE = 30.0f;
289 constexpr f32 NUM_ROTATIONS = 1.0f;
291 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 0);
295void KartAction::startAction3() {
296 constexpr f32 EXT_VEL_SCALAR = 25.0f;
297 constexpr f32 EXT_VEL_KART = 30.0f;
298 constexpr f32 EXT_VEL_BIKE = 30.0f;
299 constexpr f32 NUM_ROTATIONS = 1.0f;
301 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 1);
302 Item::ItemDirector::Instance()->kartItem(0).clear();
306void KartAction::startAction5() {
307 constexpr f32 EXT_VEL_SCALAR = 13.0f;
308 constexpr f32 EXT_VEL_KART = 40.0f;
309 constexpr f32 EXT_VEL_BIKE = 45.0f;
310 constexpr f32 NUM_ROTATIONS = 1.0f;
312 startLaunch(EXT_VEL_SCALAR, EXT_VEL_KART, EXT_VEL_BIKE, NUM_ROTATIONS, 2);
316void KartAction::startLargeFlipAction() {
319 dynamics()->setExtVel(INIT_VEL);
320 dynamics()->setAngVel0(EGG::Vector3f::zero);
322 if (m_currentAction == Action::UNK_8) {
323 calcSideFromHitDepth();
324 dynamics()->setExtVel(dynamics()->extVel() + m_side * -20.0f);
327 Item::ItemDirector::Instance()->kartItem(0).clear();
333 m_framesFlipping = 0;
335 status().setBit(eStatus::LargeFlipHit);
339void KartAction::startAction9() {
344void KartAction::startLongPressAction() {
345 constexpr u32 ACTION_DURATION = 90;
346 constexpr u16 CRUSH_DURATION = 480;
348 m_crushTimer = ACTION_DURATION;
349 activateCrush(CRUSH_DURATION);
353void KartAction::startShortPressAction() {
354 constexpr u32 ACTION_DURATION = 30;
355 constexpr u16 CRUSH_DURATION = 240;
357 m_crushTimer = ACTION_DURATION;
358 activateCrush(CRUSH_DURATION);
365bool KartAction::calcStub() {
370bool KartAction::calcAction1() {
372 bool finished = calcRotation();
374 m_rotation.setAxisRotation(DEG2RAD * (m_currentAngle * m_rotationDirection), m_up);
375 physics()->composeExtraRot(m_rotation);
380bool KartAction::calcLaunchAction() {
381 constexpr u32 ACTION_DURATION = 100;
383 if (m_flags.offBit(eFlags::Landing)) {
388 bool actionEnded = m_frame >= ACTION_DURATION;
391 if (m_flags.offBit(eFlags::Landing)) {
392 physics()->composeDecayingExtraRot(m_rotation);
394 }
else if (m_flags.offBit(eFlags::Landing)) {
395 m_rotation.setAxisRotation(DEG2RAD * m_currentAngle, m_rotAxis);
396 physics()->composeExtraRot(m_rotation);
403bool KartAction::calcLargeFlipAction() {
404 constexpr f32 PITCH_DECAY = 0.971f;
405 constexpr f32 TOTAL_DELTA_PITCH = 720.0f;
406 constexpr f32 PHASE_DELTA = 4.0f;
407 constexpr f32 WOBBLE_AMPLITUDE = 18.1f;
408 constexpr f32 BOUNCE_FACTOR = 5.0f;
410 bool decayingRot =
false;
411 bool stuntRot =
false;
413 if (m_flags.onBit(eFlags::LargeFlip)) {
416 if (m_deltaPitch < TOTAL_DELTA_PITCH) {
417 m_deltaPitch += m_velPitch;
418 m_pitch -= m_velPitch;
419 m_velPitch *= (m_velPitch > 1.0f) ? PITCH_DECAY : 1.0f;
426 if (EGG::Mathf::abs(m_flipPhase) < 360.0f) {
427 m_flipPhase += PHASE_DELTA;
428 sin = EGG::Mathf::SinFIdx(DEG2FIDX * m_flipPhase);
434 mat.
setAxisRotation(DEG2RAD * (WOBBLE_AMPLITUDE * sin), EGG::Vector3f::ez);
435 m_rotation.setAxisRotation(DEG2RAD * m_pitch, mat.
ps_multVector(EGG::Vector3f::ex));
440 bool actionEnded =
false;
441 auto &status = KartObjectProxy::status();
442 bool touchingGround = status.onBit(eStatus::TouchingGround);
444 if (m_flags.offBit(eFlags::LandingFromFlip) && touchingGround && move()->up().y > 0.0f &&
446 m_flags.setBit(eFlags::LandingFromFlip);
447 dynamics()->setExtVel(move()->up().proj(EGG::Vector3f::ey) * BOUNCE_FACTOR);
450 if ((m_currentAction != Action::UNK_8 && m_frame < 10) || !touchingGround) {
451 dynamics()->setExtVel(
EGG::Vector3f(0.0f, dynamics()->extVel().y, 0.0f));
454 if ((touchingGround && move()->up().dot(EGG::Vector3f::ey) > 0.0f) || m_frame >= 300) {
456 status.resetBit(eStatus::LargeFlipHit);
459 if (m_frame <= 120) {
460 if (m_flags.onBit(eFlags::LargeFlip)) {
461 if (m_framesFlipping > 30) {
465 if (m_frame >= 40 && m_frame <= 80) {
467 m_flags.setBit(eFlags::LargeFlip);
468 status.resetBit(eStatus::LargeFlipHit);
477 physics()->composeDecayingStuntRot(m_rotation);
478 }
else if (stuntRot) {
479 physics()->composeStuntRot(m_rotation);
486bool KartAction::calcPressAction() {
488 extVel.y = std::min(0.0f, extVel.y);
489 dynamics()->setExtVel(extVel);
491 return m_frame > m_crushTimer;
498void KartAction::endStub(
bool ) {}
501void KartAction::endAction1(
bool arg) {
503 physics()->composeDecayingExtraRot(m_rotation);
508void KartAction::endLaunchAction(
bool arg) {
510 physics()->composeDecayingExtraRot(m_rotation);
518const std::array<KartAction::ActionParams, KartAction::MAX_ACTION> KartAction::s_actionParams = {{
539const std::array<KartAction::RotationParams, 5> KartAction::s_rotationParams = {{
540 {10.0f, 1.5f, 0.9f, 0.005f, 0.6f, 360.0f},
541 {11.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 720.0f},
542 {11.0f, 1.5f, 0.9f, 0.0028f, 0.8f, 1080.0f},
543 {7.0f, 1.5f, 0.9f, 0.005f, 0.6f, 450.0f},
544 {9.0f, 1.5f, 0.9f, 0.0028f, 0.7f, 810.0f},
547const std::array<KartAction::StartActionFunc, KartAction::MAX_ACTION> KartAction::s_onStart = {{
548 &KartAction::startStub,
549 &KartAction::startAction1,
550 &KartAction::startAction2,
551 &KartAction::startAction3,
552 &KartAction::startStub,
553 &KartAction::startAction5,
554 &KartAction::startStub,
555 &KartAction::startLargeFlipAction,
556 &KartAction::startLargeFlipAction,
557 &KartAction::startAction9,
558 &KartAction::startStub,
559 &KartAction::startStub,
560 &KartAction::startLongPressAction,
561 &KartAction::startStub,
562 &KartAction::startShortPressAction,
563 &KartAction::startStub,
564 &KartAction::startStub,
565 &KartAction::startStub,
568const std::array<KartAction::CalcActionFunc, KartAction::MAX_ACTION> KartAction::s_onCalc = {{
569 &KartAction::calcStub,
570 &KartAction::calcAction1,
571 &KartAction::calcLaunchAction,
572 &KartAction::calcLaunchAction,
573 &KartAction::calcStub,
574 &KartAction::calcLaunchAction,
575 &KartAction::calcStub,
576 &KartAction::calcLargeFlipAction,
577 &KartAction::calcLargeFlipAction,
578 &KartAction::calcAction1,
579 &KartAction::calcStub,
580 &KartAction::calcStub,
581 &KartAction::calcPressAction,
582 &KartAction::calcStub,
583 &KartAction::calcPressAction,
584 &KartAction::calcStub,
585 &KartAction::calcStub,
586 &KartAction::calcStub,
589const std::array<KartAction::EndActionFunc, KartAction::MAX_ACTION> KartAction::s_onEnd = {{
590 &KartAction::endStub,
591 &KartAction::endAction1,
592 &KartAction::endLaunchAction,
593 &KartAction::endLaunchAction,
594 &KartAction::endStub,
595 &KartAction::endLaunchAction,
596 &KartAction::endStub,
597 &KartAction::endStub,
598 &KartAction::endStub,
599 &KartAction::endAction1,
600 &KartAction::endStub,
601 &KartAction::endStub,
602 &KartAction::endStub,
603 &KartAction::endStub,
604 &KartAction::endStub,
605 &KartAction::endStub,
606 &KartAction::endStub,
607 &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.