A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KartReject.cc
1#include "KartReject.hh"
2
3#include "game/kart/KartDynamics.hh"
4#include "game/kart/KartMove.hh"
5#include "game/kart/KartParam.hh"
6#include "game/kart/KartState.hh"
7
8#include "game/field/CollisionDirector.hh"
9#include "game/field/CourseColMgr.hh"
10
11#include <egg/math/Math.hh>
12#include <egg/math/Quat.hh>
13
14namespace Kart {
15
17KartReject::KartReject() = default;
18
20KartReject::~KartReject() = default;
21
23void KartReject::reset() {
24 m_rejectSign = 0.0f;
25}
26
28void KartReject::calcRejectRoad() {
29 if (state()->isInAction()) {
30 return;
31 }
32
33 if (state()->isRejectRoadTrigger()) {
34 EGG::Vector3f down = -EGG::Vector3f::ey;
35 down = down.perpInPlane(move()->up(), true);
36 f32 cos = down.dot(move()->lastDir());
37 f32 sin = down.cross(move()->lastDir()).length();
38 f32 angle = EGG::Mathf::atan2(sin, cos);
39 angle = angle > 0.0f ? angle : -angle;
40
41 f32 minAngle = 60.0f;
42 angle *= RAD2DEG;
43 f32 dVar11 = 1.0f;
44
45 if (move()->up().dot(EGG::Vector3f::ey) < -0.7f) {
46 minAngle *= 0.5f;
47 dVar11 *= 2.0f;
48 }
49
50 if (angle > minAngle) {
51 angle = 0.05f * (angle - 60.0f);
52 EGG::Quatf rot = EGG::Quatf::FromRPY(0.0f,
53 (1.0f + angle * move()->speedRatio()) * dVar11 * DEG2RAD * m_rejectSign, 0.0f);
54 EGG::Quatf local_78 = mainRot().multSwap(rot);
55 local_78.normalise();
56
57 dynamics()->setAngVel0(EGG::Vector3f::zero);
58 dynamics()->setFullRot(local_78);
59 dynamics()->setMainRot(local_78);
60 }
61
62 state()->setHop(false);
63
64 bool didReject = calcRejection();
65
66 if (!state()->isNoSparkInvisibleWall() && !didReject) {
67 state()->setRejectRoadTrigger(false);
68 }
69
70 return;
71 }
72
73 if (state()->isRejectRoad() && !state()->isZipperInvisibleWall() && !state()->isOverZipper() &&
74 !state()->isHalfPipeRamp()) {
75 EGG::Vector3f upXZ = move()->up();
76 upXZ.y = 0.0f;
77
78 if (upXZ.length() > 0.0f && speed() > 0.0f) {
79 upXZ.normalise();
80 EGG::Vector3f local_88 = move()->lastDir().perpInPlane(upXZ, true);
81
82 if (local_88.y > 0.0f) {
83 EGG::Vector3f upCross = EGG::Vector3f::ey.cross(local_88);
84 m_rejectSign = upCross.dot(move()->up()) > 0.0f ? 1.0f : -1.0f;
85
86 state()->setHop(false);
87 state()->setRejectRoadTrigger(true);
88 }
89 }
90 }
91}
92
94bool KartReject::calcRejection() {
96 Field::KCLTypeMask mask = KCL_NONE;
97 state()->setNoSparkInvisibleWall(false);
98 EGG::Vector3f worldUpPos = dynamics()->pos() + bodyUp() * 100.0f;
99 f32 posScalar = 100.0f;
100 f32 radius = posScalar;
101
102 for (size_t i = 0; i < 2; ++i) {
103 EGG::Vector3f local_d0 = dynamics()->mainRot().rotateVector(EGG::Vector3f::ey);
104 EGG::Vector3f worldPos = pos() + (-posScalar * move()->scale().y) * local_d0;
105
106 auto *colDir = Field::CollisionDirector::Instance();
107 if (!colDir->checkSphereFullPush(radius, worldPos, worldUpPos, KCL_TYPE_B0E82DFF, &colInfo,
108 &mask, 0)) {
109 if (i == 0) {
110 posScalar = 0.0f;
111 }
112
113 continue;
114 }
115
116 bool hasFloorCollision = false;
117 bool hasRejectCollision = false;
118 bool hasInvisibleWallCollision = false;
119 EGG::Vector3f tangentOff = EGG::Vector3f::zero;
120
121 if (mask & KCL_TYPE_INVISIBLE_WALL) {
122 hasInvisibleWallCollision =
123 colDir->findClosestCollisionEntry(&mask, KCL_TYPE_INVISIBLE_WALL);
124 }
125
126 const auto *closestColEntry = colDir->closestCollisionEntry();
127 if (hasInvisibleWallCollision && KCL_VARIANT_TYPE(closestColEntry->attribute) == 0) {
128 hasRejectCollision = true;
129 tangentOff = colInfo.wallNrm;
130 state()->setNoSparkInvisibleWall(true);
131 } else {
132 if (!(mask & KCL_TYPE_DRIVER_FLOOR)) {
133 hasFloorCollision = false;
134 } else {
135 hasFloorCollision = colDir->findClosestCollisionEntry(&mask, KCL_TYPE_DRIVER_FLOOR);
136 }
137
138 closestColEntry = colDir->closestCollisionEntry();
139 if (hasFloorCollision && closestColEntry->attribute & 0x4000) {
140 hasRejectCollision = true;
141 tangentOff = colInfo.floorNrm;
142 }
143 }
144
145 if (!hasRejectCollision) {
146 continue;
147 }
148
149 EGG::Vector3f tangentUp = (tangentOff - move()->up()) * 1.0f;
150 move()->setUp(move()->up() + tangentUp);
151 move()->setSmoothedUp(move()->up());
152
153 bool bVar15 = tangentOff.dot(EGG::Vector3f::ey) < -0.17f;
154 if (bVar15 || extVel().y < 0.0f || state()->isNoSparkInvisibleWall()) {
155 radius = -radius;
156 colInfo.tangentOff += worldPos;
157
158 f32 yOffset = bsp().initialYPos * scale().y;
159 f32 speedScalar = bVar15 ?
160 1.0f :
161 static_cast<f32>(static_cast<f64>(EGG::Mathf::abs(speed()) * 0.01f) - 0.3d);
162 speedScalar = std::min(1.0f, std::max(0.0f, speedScalar));
163
164 EGG::Vector3f posOffset =
165 colInfo.tangentOff + radius * tangentOff + yOffset * tangentOff;
166 posOffset.y += move()->hopPosY();
167 posOffset -= pos();
168 setPos(pos() + posOffset * speedScalar);
169 }
170
171 EGG::Vector3f local_13c = move()->lastDir().perpInPlane(move()->smoothedUp(), true);
172 move()->setDir(local_13c);
173 move()->setVel1Dir(local_13c);
174
175 return true;
176 }
177
178 return false;
179}
180
181} // namespace Kart
#define KCL_VARIANT_TYPE(x)
Extracts the "Variant" portion of the 2 byte KCL flag. It's the 3 bits before the "Bast Type".
#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
EGG::Vector3f bodyUp() const
Returns the second column of the rotation matrix, which is the "up" direction.
Pertains to kart-related functionality.
A quaternion, used to represent 3D rotation.
Definition Quat.hh:12
void normalise()
Scales the quaternion to a unit length.
Definition Quat.cc:28
Vector3f rotateVector(const Vector3f &vec) const
Rotates a vector based on the quat.
Definition Quat.cc:55
A 3D float vector.
Definition Vector.hh:87
f32 normalise()
Normalizes the vector and returns the original length.
Definition Vector.cc:44
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:186
f32 length() const
The square root of the vector's dot product.
Definition Vector.hh:191
Vector3f perpInPlane(const EGG::Vector3f &rhs, bool normalise) const
Calculates the orthogonal vector, based on the plane defined by this vector and rhs.
Definition Vector.cc:96