1#include "KartReject.hh"
3#include "game/kart/KartDynamics.hh"
4#include "game/kart/KartMove.hh"
5#include "game/kart/KartParam.hh"
6#include "game/kart/KartState.hh"
8#include "game/field/CollisionDirector.hh"
9#include "game/field/CourseColMgr.hh"
11#include <egg/math/Math.hh>
12#include <egg/math/Quat.hh>
17KartReject::KartReject() =
default;
20KartReject::~KartReject() =
default;
23void KartReject::reset() {
28void KartReject::calcRejectRoad() {
29 auto &status = KartObjectProxy::status();
31 if (status.
onBit(eStatus::InAction)) {
36 EGG::Vector3f down = -EGG::Vector3f::ey;
37 down = down.perpInPlane(move()->up(),
true);
38 f32 cos = down.dot(move()->lastDir());
39 f32 sin = down.cross(move()->lastDir()).length();
40 f32 angle = EGG::Mathf::atan2(sin, cos);
41 angle = angle > 0.0f ? angle : -angle;
47 if (move()->up().dot(EGG::Vector3f::ey) < -0.7f) {
52 if (angle > minAngle) {
53 angle = 0.05f * (angle - 60.0f);
54 EGG::Quatf rot = EGG::Quatf::FromRPY(0.0f,
55 (1.0f + angle * move()->speedRatio()) * dVar11 * DEG2RAD * m_rejectSign, 0.0f);
56 EGG::Quatf local_78 = mainRot().multSwap(rot);
59 dynamics()->setAngVel0(EGG::Vector3f::zero);
60 dynamics()->setFullRot(local_78);
61 dynamics()->setMainRot(local_78);
66 bool didReject = calcRejection();
68 if (status.
offBit(eStatus::NoSparkInvisibleWall) && !didReject) {
69 move()->clearRejectRoad();
78 EGG::Vector3f upXZ = move()->up();
81 if (upXZ.length() > 0.0f && speed() > 0.0f) {
83 EGG::Vector3f local_88 = move()->lastDir().
perpInPlane(upXZ,
true);
85 if (local_88.y > 0.0f) {
86 EGG::Vector3f upCross = EGG::Vector3f::ey.cross(local_88);
87 m_rejectSign = upCross.dot(move()->up()) > 0.0f ? 1.0f : -1.0f;
96bool KartReject::calcRejection() {
97 Field::CollisionInfo colInfo;
98 Field::KCLTypeMask mask = KCL_NONE;
99 auto &status = KartObjectProxy::status();
100 status.
resetBit(eStatus::NoSparkInvisibleWall);
101 EGG::Vector3f worldUpPos = dynamics()->pos() +
bodyUp() * 100.0f;
102 f32 posScalar = 100.0f;
103 f32 radius = posScalar;
105 for (
size_t i = 0; i < 2; ++i) {
106 EGG::Vector3f local_d0 = dynamics()->mainRot().
rotateVector(EGG::Vector3f::ey);
107 EGG::Vector3f worldPos = pos() + (-posScalar * move()->scale().y) * local_d0;
109 auto *colDir = Field::CollisionDirector::Instance();
110 if (!colDir->checkSphereFullPush(radius, worldPos, worldUpPos,
KCL_TYPE_B0E82DFF, &colInfo,
119 EGG::Vector3f tangentOff = EGG::Vector3f::zero;
121 if (!calcCollision(colInfo, mask, tangentOff)) {
125 EGG::Vector3f tangentUp = (tangentOff - move()->up()) * 1.0f;
126 move()->setUp(move()->up() + tangentUp);
127 move()->setSmoothedUp(move()->up());
129 bool bVar15 = tangentOff.dot(EGG::Vector3f::ey) < -0.17f;
130 if (bVar15 || extVel().y < 0.0f || status.
onBit(eStatus::NoSparkInvisibleWall)) {
132 colInfo.tangentOff += worldPos;
134 f32 yOffset = bsp().initialYPos * scale().y;
135 f32 speedScalar = bVar15 ?
137 static_cast<f32
>(
static_cast<f64
>(EGG::Mathf::abs(speed()) * 0.01f) - 0.3);
138 speedScalar = std::min(1.0f, std::max(0.0f, speedScalar));
140 EGG::Vector3f posOffset =
141 colInfo.tangentOff + radius * tangentOff + yOffset * tangentOff;
142 posOffset.y += move()->hopPosY();
144 setPos(pos() + posOffset * speedScalar);
147 EGG::Vector3f local_13c = move()->lastDir().
perpInPlane(move()->smoothedUp(),
true);
148 move()->setDir(local_13c);
149 move()->setVel1Dir(local_13c);
157bool KartReject::calcCollision(Field::CollisionInfo &colInfo, Field::KCLTypeMask mask,
158 EGG::Vector3f &tangentOff) {
159 auto *colDir = Field::CollisionDirector::Instance();
163 colDir->closestCollisionEntry()->variant() == 0) {
164 tangentOff = colInfo.wallNrm;
165 status().
setBit(eStatus::NoSparkInvisibleWall);
171 if (mask & halfPipeInvisMask) {
172 if (colDir->findClosestCollisionEntry(&mask, halfPipeInvisMask)) {
173 tangentOff = colInfo.wallNrm;
174 status().
setBit(eStatus::NoSparkInvisibleWall);
181 colDir->closestCollisionEntry()->attribute.onBit(
182 Field::CollisionDirector::eCollisionAttribute::RejectRoad)) {
183 tangentOff = colInfo.floorNrm;
@ COL_TYPE_HALFPIPE_INVISIBLE_WALL
Invisible wall after a half-pipe jump, like in BC.
#define KCL_TYPE_DRIVER_FLOOR
0x20E80DFF - Any KCL that the player can drive on.
#define KCL_TYPE_INVISIBLE_WALL
0x80002000
#define KCL_TYPE_B0E82DFF
0xB0E82DFF
constexpr bool offBit(Es... es) const
Checks if all of the corresponding bits for the provided enum values are off.
constexpr TBitFlagExt< N, E > & setBit(Es... es)
Sets the corresponding bits for the provided enum values.
constexpr bool onBit(Es... es) const
Checks if any of the corresponding bits for the provided enum values are on.
constexpr TBitFlagExt< N, E > & resetBit(Es... es)
Resets the corresponding bits for the provided enum values.
EGG::Vector3f bodyUp() const
Returns the second column of the rotation matrix, which is the "up" direction.
Pertains to kart-related functionality.
@ RejectRoad
Collision which causes a change in the player's pos and rot.
@ HalfPipeRamp
Set while colliding with zipper KCL.
@ Hop
Set while we are in a drift hop. Clears when we land.
@ RejectRoadTrigger
e.g. DK Summit ending, and Maple Treeway side walls.
@ OverZipper
Set while mid-air from a zipper.
@ ZipperInvisibleWall
Set when colliding with invisible wall above a zipper.
constexpr Vector3f rotateVector(const Vector3f &vec) const
Rotates a vector based on the quat.
constexpr void normalise()
Scales the quaternion to a unit length.
constexpr Vector3f perpInPlane(const EGG::Vector3f &rhs, bool normalise) const
Calculates the orthogonal vector, based on the plane defined by this vector and rhs.