1#include "ObjectChoropu.hh"
3#include "game/field/ObjectDirector.hh"
4#include "game/field/RailManager.hh"
6#include "game/system/RaceManager.hh"
12 : ObjectCollidable(params), StateManager(this) {
13 constexpr f32 MAX_SPEED = 20.0f;
15 m_startFrameOffset =
static_cast<s16
>(params.setting(1));
16 m_idleDuration = params.setting(0);
17 m_isStationary = strcmp(getName(),
"choropu") != 0;
19 s16 railIdx = params.pathId();
21 auto *rail = RailManager::Instance()->rail(railIdx);
22 rail->checkSphereFull();
26 if (!m_isStationary) {
27 const auto &flowTable = ObjectDirector::Instance()->flowTable();
28 const auto *collisionSet =
29 flowTable.set(flowTable.slot(flowTable.getIdFromName(
"choropu_ground")));
32 s16 height = parse<s16>(collisionSet->params.cylinder.height);
33 size_t groundCount =
static_cast<size_t>(MAX_GROUND_LEN / EGG::Mathf::abs(height * 2)) + 1;
34 m_groundObjs = std::span<ObjectChoropuGround *>(
new ObjectChoropuGround *[groundCount],
37 for (
auto *&obj : m_groundObjs) {
38 obj =
new ObjectChoropuGround(m_pos, m_rot, m_scale);
40 obj->resize(RADIUS, MAX_SPEED);
43 m_groundHeight = m_groundObjs.front()->height();
46 m_objHoll =
new ObjectChoropuHoll(params);
51ObjectChoropu::~ObjectChoropu() {
52 delete[] m_groundObjs.data();
56void ObjectChoropu::init() {
61 m_objHoll->setScale(
EGG::Vector3f(1.0f, m_objHoll->scale().y, 1.0f));
63 m_groundLength = 0.0f;
66 m_transMat = m_transform;
68 if (m_mapObj->pathId() == -1) {
72 m_railInterpolator->init(0.0f, 0);
73 m_railInterpolator->setPerPointVelocities(
true);
75 m_railMat = RailOrthonormalBasis(*m_railInterpolator);
76 m_pos = m_railMat.base(3);
77 m_flags.setBit(eFlags::Position);
80 m_objHoll->disableCollision();
87void ObjectChoropu::calc() {
88 constexpr u32 START_DELAY = 300;
91 u32 t = System::RaceManager::Instance()->timer();
92 if (t < m_startFrameOffset + START_DELAY) {
96 if (!m_isStationary) {
97 if (m_mapObj->pathId() == -1) {
101 m_railMat = RailOrthonormalBasis(*m_railInterpolator);
104 StateManager::calc();
106 m_objHoll->setScale(
EGG::Vector3f(1.0f, m_objHoll->scale().y, 1.0f));
111 Kart::Reaction reactionOnKart, Kart::Reaction ,
113 return m_currentStateId == 1 ? Kart::Reaction::SmallBump : reactionOnKart;
116void ObjectChoropu::enterStateStub() {}
119void ObjectChoropu::enterDigging() {
120 if (m_isStationary) {
123 for (
auto *&obj : m_groundObjs) {
124 obj->enableCollision();
128 m_objHoll->disableCollision();
129 m_groundLength = 0.0f;
134void ObjectChoropu::enterPeeking() {
135 if (m_isStationary) {
136 m_pos = m_transMat.base(3);
137 m_flags.setBit(eFlags::Position, eFlags::Rotation);
142 m_pos = m_railMat.base(3);
143 m_flags.setBit(eFlags::Position, eFlags::Rotation);
149 const auto &curTanDir = m_railInterpolator->curTangentDir();
150 s16 curPointIdx = m_railInterpolator->curPointIdx();
152 SetRotTangentHorizontal(mat, m_railInterpolator->floorNrm(curPointIdx), curTanDir);
153 mat.
setBase(3, m_railInterpolator->curPos());
155 m_objHoll->setTransform(mat);
156 m_objHoll->setPos(mat.
base(3));
157 m_objHoll->enableCollision();
162void ObjectChoropu::enterJumping() {
165 m_pos = m_isStationary ? m_transMat.base(3) : m_railMat.base(3);
166 m_flags.setBit(eFlags::Position, eFlags::Rotation);
170void ObjectChoropu::calcStateStub() {}
173void ObjectChoropu::calcDigging() {
174 if (m_isStationary) {
175 if (m_currentFrame > m_idleDuration) {
182 m_pos = m_railInterpolator->curPos();
183 m_flags.setBit(eFlags::Position);
185 if (m_railInterpolator->calc() == RailInterpolator::Status::SegmentEnd) {
186 if (m_railInterpolator->curPoint().setting[1] == 1) {
192 bool skipGroundCalc =
false;
194 if (m_railInterpolator->nextPoint().setting[1] == 1) {
195 f32 invT = 1.0f - m_railInterpolator->segmentT();
196 if (invT * m_railInterpolator->getCurrSegmentLength() < 250.0f) {
197 skipGroundCalc =
true;
201 if (!skipGroundCalc) {
208void ObjectChoropu::calcPeeking() {
209 constexpr s16 PEEK_DURATION = 40;
210 constexpr s16 STATE_DURATION = 100;
212 if (!m_isStationary) {
213 m_groundLength = std::max(0.0f, m_groundLength - m_railInterpolator->speed());
218 if (m_currentFrame > STATE_DURATION) {
222 if (m_currentFrame > PEEK_DURATION) {
228void ObjectChoropu::calcJumping() {
229 constexpr f32 JUMP_LINEAR_COEFFICIENT = 65.0f;
230 constexpr f32 JUMP_QUADRATIC_COEFFICIENT = 2.7f;
232 if (!m_isStationary) {
233 m_groundLength = std::max(0.0f, m_groundLength - m_railInterpolator->speed());
238 f32 pos = JUMP_LINEAR_COEFFICIENT *
static_cast<f32
>(m_currentFrame) -
239 static_cast<f32
>(m_currentFrame) * 0.5f * JUMP_QUADRATIC_COEFFICIENT *
240 static_cast<f32
>(m_currentFrame);
246 m_pos.y = pos + (m_isStationary ? m_transMat.base(3).y : m_railInterpolator->curPos().y);
247 m_flags.setBit(eFlags::Position);
251void ObjectChoropu::calcGround() {
252 m_groundLength += m_railInterpolator->getCurrVel();
253 if (m_groundLength > MAX_GROUND_LEN) {
254 m_groundLength = MAX_GROUND_LEN - 1.0f;
261void ObjectChoropu::calcGroundObjs() {
263 std::min(
static_cast<size_t>(m_groundLength / m_groundHeight) + 1, m_groundObjs.size());
265 for (
auto *&obj : m_groundObjs) {
266 obj->enableCollision();
269 for (
size_t i = idx; i < m_groundObjs.size(); ++i) {
270 m_groundObjs[i]->disableCollision();
273 if (m_groundLength > RADIUS) {
274 f32 height = std::min(m_groundHeight, m_groundLength) - RADIUS;
275 m_groundObjs[0]->calcPosAndMat(height, calcInterpolatedPose(RADIUS + 0.5f * height));
278 for (
size_t i = 1; i < idx - 1; ++i) {
279 f32 height = 0.5f * m_groundHeight + m_groundHeight *
static_cast<f32
>(i);
280 m_groundObjs[i]->calcPosAndMat(m_groundHeight, calcInterpolatedPose(height));
283 f32 height = m_groundLength - m_groundHeight *
static_cast<f32
>(idx - 1);
285 calcInterpolatedPose(0.5f * height + m_groundHeight *
static_cast<f32
>(idx - 1));
286 m_groundObjs[idx - 1]->calcPosAndMat(height, mat);
293 m_railInterpolator->evalCubicBezierOnPath(t, curDir, curTanDir);
302 : ObjectCollidable(
"choropu_ground", pos, rot, scale) {
303 const auto &flowTable = ObjectDirector::Instance()->flowTable();
304 const auto *collisionSet =
305 flowTable.set(flowTable.slot(flowTable.getIdFromName(
"choropu_ground")));
306 ASSERT(collisionSet);
308 s16 height = parse<s16>(collisionSet->params.cylinder.height);
309 m_height = 2.0f * EGG::Mathf::abs(
static_cast<f32
>(height));
313ObjectChoropuGround::~ObjectChoropuGround() =
default;
316void ObjectChoropuGround::calcPosAndMat(f32 height,
const EGG::Matrix34f &mat) {
318 SetRotTangentHorizontal(matTemp, mat.
base(2), EGG::Vector3f::ey);
319 matTemp.
setBase(1, matTemp.
base(1) * (height / m_height));
321 m_flags.setBit(eFlags::Matrix);
322 m_transform = matTemp;
323 m_pos = matTemp.
base(3);
328 : ObjectCollidable(params) {}
331ObjectChoropuHoll::~ObjectChoropuHoll() =
default;
void setBase(size_t col, const Vector3f &base)
Sets one column of a matrix.
Vector3f base(size_t col) const
Get a particular column from a matrix.
The highest level abstraction for a kart.