A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
ObjectFlamePoleFoot.cc
1#include "ObjectFlamePoleFoot.hh"
2
3#include "game/field/CollisionDirector.hh"
4
5#include "game/system/RaceManager.hh"
6
7#include <algorithm>
8
9namespace Kinoko::Field {
10
12ObjectFlamePoleFoot::ObjectFlamePoleFoot(const System::MapdataGeoObj &params)
13 : ObjectKCL(params), StateManager(this, STATE_ENTRIES) {
14 m_extraCycleFrames = params.setting(0);
15 m_initDelay = params.setting(1);
16 m_poleScale = static_cast<f32>(params.setting(2));
17
18 ++s_flamePoleCount;
19
20 if (m_poleScale == 0.0f) {
21 m_poleScale = 3.0f + static_cast<f32>(s_flamePoleCount % 3);
22 }
23
24 m_pole = EGG::egg_new<ObjectFlamePole>(params, pos(), rot(), scale());
25 m_pole->load();
26}
27
29ObjectFlamePoleFoot::~ObjectFlamePoleFoot() {
30 s_flamePoleCount = 0;
31}
32
34void ObjectFlamePoleFoot::init() {
35 constexpr f32 NORMALIZATION = static_cast<f32>(CYCLE_FRAMES) * (7.0f - 1.0f);
36
37 m_nextStateId = 0;
38 m_cycleFrame = 0;
39 m_eruptUpDuration = static_cast<s32>(0.1f * NORMALIZATION / 7.0f);
40 m_eruptDownDuration = static_cast<s32>(0.2f * NORMALIZATION / 7.0f);
41
42 s32 state1 = static_cast<s32>(0.3f * NORMALIZATION / 7.0f);
43 s32 state2 = state1 + m_eruptUpDuration;
44 s32 state3 = state2 + static_cast<s32>(static_cast<f32>(CYCLE_FRAMES) * 1.0f / 7.0f);
45 s32 state4 = state3 + m_eruptDownDuration;
46 s32 state5 = state4 + static_cast<s32>(0.4f * NORMALIZATION / 7.0f);
47 m_stateStart = {{0, state1, state2, state3, state4, state5}};
48
49 m_eruptDownVel = (m_poleScale - 1.0f) / static_cast<f32>(state1);
50 m_initScaledHeight = ObjectFlamePole::HEIGHT * m_poleScale;
51 m_scaleDelta = (300.0f + m_initScaledHeight) / static_cast<f32>(m_eruptDownDuration);
52 m_pole->setActive(false);
53 m_pole->disableCollision();
54
55 EGG::Vector3f polePos = m_pole->pos();
56 polePos.y = pos().y - ObjectFlamePole::HEIGHT * m_poleScale;
57 m_pole->setPos(polePos);
58}
59
61void ObjectFlamePoleFoot::calc() {
62 if (System::RaceManager::Instance()->timer() < m_initDelay) {
63 return;
64 }
65
66 calcStates();
67
68 StateManager::calc();
69
70 f32 scale = getScaleY(0);
71 setScale(scale);
72
73 EGG::Vector3f polePos = m_pole->pos();
74 m_pole->setPos(
75 EGG::Vector3f(polePos.x, m_heightOffset + (pos().y - m_initScaledHeight), polePos.z));
76 m_pole->setScale(m_poleScale);
77}
78
80void ObjectFlamePoleFoot::calcStates() {
81 u32 frame = static_cast<s32>(System::RaceManager::Instance()->timer() - m_initDelay);
82 m_cycleFrame = frame % (m_extraCycleFrames + CYCLE_FRAMES);
83
84 // Access the array of state timers to see which state corresponds with the current frame.
85 auto it = std::ranges::upper_bound(m_stateStart.begin(), m_stateStart.end(), m_cycleFrame);
86 auto idx = it - m_stateStart.begin() - 1;
87
88 if (idx < 0) {
89 return;
90 }
91
92 u16 stateId = static_cast<u16>(idx);
93
94 if (m_currentStateId != stateId) {
95 m_nextStateId = stateId;
96 }
97}
98
99f32 ObjectFlamePoleFoot::getScaleY(u32 timeOffset) const {
100 u32 frame = System::RaceManager::Instance()->timer() - timeOffset;
101 if (frame < m_initDelay) {
102 return 1.0f;
103 }
104
105 s32 cycleFrame = frame - m_initDelay;
106 cycleFrame %= m_extraCycleFrames + CYCLE_FRAMES;
107
108 if (cycleFrame >= m_stateStart[5]) {
109 return 1.0f;
110 }
111
112 if (cycleFrame >= m_stateStart[4]) {
113 return std::max(1.0f,
114 m_poleScale - m_eruptDownVel * static_cast<f32>(m_eruptDownDuration / 2) -
115 m_eruptDownVel * static_cast<f32>(cycleFrame - m_stateStart[4]));
116 }
117
118 if (cycleFrame >= m_stateStart[3]) {
119 s32 framesSince194 = cycleFrame - m_stateStart[3];
120 s32 half17c = m_eruptDownDuration / 2;
121 if (framesSince194 > half17c) {
122 return m_poleScale - m_eruptDownVel * static_cast<f32>(framesSince194 - half17c);
123 } else {
124 return m_poleScale;
125 }
126 }
127
128 if (cycleFrame >= m_stateStart[2] || cycleFrame >= m_stateStart[1]) {
129 return m_poleScale;
130 }
131
132 if (cycleFrame >= 0) {
133 return std::min(m_poleScale, m_eruptDownVel * static_cast<f32>(cycleFrame) + 1.0f);
134 }
135
136 return 1.0f;
137}
138
140bool ObjectFlamePoleFoot::checkCollision(f32 radius, const EGG::Vector3f &pos,
141 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
142 u32 timeOffset) {
143 update(timeOffset);
144 calcScale(timeOffset);
145 f32 scale = getScaleY(timeOffset);
146
147 if (!m_objColMgr->checkSphereFullPush(radius, pos, prevPos, mask, info, maskOut)) {
148 return false;
149 }
150
151 if (2.0f < scale) {
152 CollisionDirector::Instance()->setCurrentCollisionTrickable(true);
153 }
154
155 return true;
156}
157
159bool ObjectFlamePoleFoot::checkCollisionCached(f32 radius, const EGG::Vector3f &pos,
160 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
161 u32 timeOffset) {
162 update(timeOffset);
163 calcScale(timeOffset);
164 f32 scale = getScaleY(timeOffset);
165
166 if (!m_objColMgr->checkSphereCachedFullPush(radius, pos, prevPos, mask, info, maskOut)) {
167 return false;
168 }
169
170 if (2.0f < scale) {
171 CollisionDirector::Instance()->setCurrentCollisionTrickable(true);
172 }
173
174 return true;
175}
176
178void ObjectFlamePoleFoot::enterEruptingUp() {
179 m_pole->setActive(true);
180 m_pole->enableCollision();
181 m_heightOffset = 0.0f;
182
183 f32 t1 = -1.0f;
184 f32 t2 = -1.0f;
185 f32 vel = m_initScaledHeight;
186 EGG::Mathf::FindRootsQuadratic(static_cast<f32>(m_eruptUpDuration * m_eruptUpDuration),
187 -4.0f * m_initScaledHeight * static_cast<f32>(m_eruptUpDuration),
188 4.0f * m_initScaledHeight * m_initScaledHeight, t1, t2);
189
190 if (t1 <= 0.0f) {
191 t1 = -1.0f;
192 }
193
194 if (t2 <= 0.0f) {
195 vel = t1;
196 }
197
198 m_initEruptVel = vel;
199 m_eruptAccel = vel * vel / (2.0f * m_initScaledHeight);
200}
201
203void ObjectFlamePoleFoot::calcEruptingUp() {
204 f32 frame = static_cast<f32>(m_cycleFrame - m_stateStart[1]);
205 m_heightOffset = std::min(m_initScaledHeight,
206 m_initEruptVel * frame - frame * 0.5f * m_eruptAccel * frame);
207}
208
210void ObjectFlamePoleFoot::calcEruptingStay() {
211 constexpr f32 AMPLITUDE = 50.0f;
212
213 f32 angle = 360.0f * static_cast<f32>(m_cycleFrame - m_stateStart[2]) / 30.0f;
214 m_heightOffset = m_scaledHeight + AMPLITUDE * EGG::Mathf::SinFIdx(DEG2FIDX * angle);
215}
216
217u32 ObjectFlamePoleFoot::s_flamePoleCount = 0;
218
219} // namespace Kinoko::Field
Base class that represents different "states" for an object.
Pertains to collision.