1#include "ObjectEscalator.hh"
3#include "game/field/CollisionDirector.hh"
4#include "game/field/ObjectDirector.hh"
6#include "game/system/RaceManager.hh"
13ObjectEscalator::ObjectEscalator(
const System::MapdataGeoObj ¶ms,
bool reverse )
14 :
ObjectKCL(params), m_initialPos(pos()), m_initialRot(rot()),
16 {
static_cast<s32
>(params.setting(2)) * 60,
static_cast<s32
>(params.setting(4)) * 60}),
17 m_speed({(reverse ? -1.0f : 1.0f) *
18 (0.15f *
static_cast<f32
>(
static_cast<s16
>(params.setting(1))) / 100.0f),
19 (reverse ? -1.0f : 1.0f) *
20 (0.15f *
static_cast<f32
>(
static_cast<s16
>(params.setting(3))) / 100.0f),
21 (reverse ? -1.0f : 1.0f) *
22 (0.15f *
static_cast<f32
>(
static_cast<s16
>(params.setting(5))) / 100.0f)}),
23 m_checkColYPosMax(m_initialPos.y + MAX_HEIGHT_OFFSET),
24 m_checkColYPosMin(m_initialPos.y + MIN_HEIGHT_OFFSET),
25 m_stopFrames({
static_cast<f32
>(m_stillFrames[0]) - REVERSE_FRAMES_F32,
26 static_cast<f32
>(m_stillFrames[1]) - REVERSE_FRAMES_F32}),
27 m_startFrames({
static_cast<f32
>(m_stillFrames[0]) + STANDSTILL_FRAMES,
28 static_cast<f32
>(m_stillFrames[1]) + STANDSTILL_FRAMES}),
30 {REVERSE_FRAMES_F32 + m_startFrames[0], REVERSE_FRAMES_F32 + m_startFrames[1]}),
31 m_midDuration(m_stopFrames[1] - m_fullSpeedFrames[0]) {
32 constexpr EGG::Vector3f STEP_DIMS = EGG::Vector3f(0.0f, STEP_HEIGHT, -30.0f);
37 mat.makeR(m_initialRot);
38 m_stepDims = mat.ps_multVector(STEP_DIMS);
42ObjectEscalator::~ObjectEscalator() =
default;
45void ObjectEscalator::calc() {
46 s32 t =
static_cast<s32
>(System::RaceManager::Instance()->timer());
47 setMovingObjVel(m_stepDims * calcSpeed(t));
49 m_stepFactor = calcStepFactor(t);
50 setPos(m_initialPos + m_stepDims * m_stepFactor);
54bool ObjectEscalator::checkPointPartial(
const EGG::Vector3f &pos,
const EGG::Vector3f &prevPos,
55 KCLTypeMask mask, CollisionInfoPartial *info, KCLTypeMask *maskOut) {
56 return checkPointImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkPointPartial,
57 pos, prevPos, mask, info, maskOut);
61bool ObjectEscalator::checkPointPartialPush(
const EGG::Vector3f &pos,
const EGG::Vector3f &prevPos,
62 KCLTypeMask mask, CollisionInfoPartial *info, KCLTypeMask *maskOut) {
63 return checkPointImpl(&ObjectEscalator::shouldCheckColPush, &ObjColMgr::checkPointPartialPush,
64 pos, prevPos, mask, info, maskOut);
68bool ObjectEscalator::checkPointFull(
const EGG::Vector3f &pos,
const EGG::Vector3f &prevPos,
69 KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) {
70 return checkPointImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkPointFull, pos,
71 prevPos, mask, info, maskOut);
75bool ObjectEscalator::checkPointFullPush(
const EGG::Vector3f &pos,
const EGG::Vector3f &prevPos,
76 KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) {
77 return checkPointImpl(&ObjectEscalator::shouldCheckColPush, &ObjColMgr::checkPointFullPush, pos,
78 prevPos, mask, info, maskOut);
82bool ObjectEscalator::checkSpherePartial(f32 radius,
const EGG::Vector3f &pos,
83 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
84 KCLTypeMask *maskOut, u32 timeOffset) {
85 return checkSphereImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkSpherePartial,
86 radius, pos, prevPos, mask, info, maskOut, timeOffset);
90bool ObjectEscalator::checkSpherePartialPush(f32 radius,
const EGG::Vector3f &pos,
91 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
92 KCLTypeMask *maskOut, u32 timeOffset) {
93 return checkSphereImpl(&ObjectEscalator::shouldCheckColPush, &ObjColMgr::checkSpherePartialPush,
94 radius, pos, prevPos, mask, info, maskOut, timeOffset);
98bool ObjectEscalator::checkSphereFull(f32 radius,
const EGG::Vector3f &pos,
99 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
101 return checkSphereImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkSphereFull,
102 radius, pos, prevPos, mask, info, maskOut, timeOffset);
106bool ObjectEscalator::checkSphereFullPush(f32 radius,
const EGG::Vector3f &pos,
107 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
109 return checkCollision(radius, pos, prevPos, mask, info, maskOut, timeOffset);
113void ObjectEscalator::narrScLocal(f32 radius,
const EGG::Vector3f &pos, KCLTypeMask mask,
115 m_objColMgr->narrScLocal(radius, pos, mask);
119bool ObjectEscalator::checkPointCachedPartial(
const EGG::Vector3f &pos,
120 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
121 KCLTypeMask *maskOut) {
122 return checkPointImpl(&ObjectEscalator::shouldCheckColNoPush,
123 &ObjColMgr::checkPointCachedPartial, pos, prevPos, mask, info, maskOut);
127bool ObjectEscalator::checkPointCachedPartialPush(
const EGG::Vector3f &pos,
128 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
129 KCLTypeMask *maskOut) {
130 return checkPointImpl(&ObjectEscalator::shouldCheckColPush,
131 &ObjColMgr::checkPointCachedPartialPush, pos, prevPos, mask, info, maskOut);
135bool ObjectEscalator::checkPointCachedFull(
const EGG::Vector3f &pos,
const EGG::Vector3f &prevPos,
136 KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) {
137 return checkPointImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkPointCachedFull,
138 pos, prevPos, mask, info, maskOut);
142bool ObjectEscalator::checkPointCachedFullPush(
const EGG::Vector3f &pos,
143 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) {
144 return checkPointImpl(&ObjectEscalator::shouldCheckColPush,
145 &ObjColMgr::checkPointCachedFullPush, pos, prevPos, mask, info, maskOut);
149bool ObjectEscalator::checkSphereCachedPartial(f32 radius,
const EGG::Vector3f &pos,
150 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
151 KCLTypeMask *maskOut, u32 timeOffset) {
152 return checkSphereImpl(&ObjectEscalator::shouldCheckColNoPush,
153 &ObjColMgr::checkSphereCachedPartial, radius, pos, prevPos, mask, info, maskOut,
158bool ObjectEscalator::checkSphereCachedPartialPush(f32 radius,
const EGG::Vector3f &pos,
159 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
160 KCLTypeMask *maskOut, u32 timeOffset) {
161 return checkSphereImpl(&ObjectEscalator::shouldCheckColPush,
162 &ObjColMgr::checkSphereCachedPartialPush, radius, pos, prevPos, mask, info, maskOut,
167bool ObjectEscalator::checkSphereCachedFull(f32 radius,
const EGG::Vector3f &pos,
168 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
170 return checkSphereImpl(&ObjectEscalator::shouldCheckColNoPush,
171 &ObjColMgr::checkSphereCachedFull, radius, pos, prevPos, mask, info, maskOut,
176bool ObjectEscalator::checkSphereCachedFullPush(f32 radius,
const EGG::Vector3f &pos,
177 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
179 return checkCollisionCached(radius, pos, prevPos, mask, info, maskOut, timeOffset);
183const EGG::Matrix34f &ObjectEscalator::getUpdatedMatrix(u32 timeOffset) {
184 u32 t = System::RaceManager::Instance()->timer() - timeOffset;
185 m_workMatrix.makeRT(rot(), m_initialPos + m_stepDims * calcStepFactor(t));
190bool ObjectEscalator::checkCollision(f32 radius,
const EGG::Vector3f &pos,
191 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
195 if (m_checkColYPosMin >= pos.y || pos.y >= m_checkColYPosMax) {
199 if (!m_objColMgr->checkSphereFullPush(radius, pos, prevPos, mask, info, maskOut)) {
207 auto *colDir = CollisionDirector::Instance();
212 auto *entry = colDir->closestCollisionEntry();
213 if (entry->dist > info->movingFloorDist) {
214 info->movingFloorDist = entry->dist;
216 u32 t = System::RaceManager::Instance()->timer() - timeOffset;
217 info->roadVelocity = m_stepDims * calcSpeed(t);
224bool ObjectEscalator::checkCollisionCached(f32 radius,
const EGG::Vector3f &pos,
225 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
229 if (m_checkColYPosMin >= pos.y || pos.y >= m_checkColYPosMax) {
233 if (!m_objColMgr->checkSphereCachedFullPush(radius, pos, prevPos, mask, info, maskOut)) {
241 auto *colDir = CollisionDirector::Instance();
246 auto *entry = colDir->closestCollisionEntry();
247 if (entry->dist > info->movingFloorDist) {
248 info->movingFloorDist = entry->dist;
250 u32 t = System::RaceManager::Instance()->timer() - timeOffset;
251 info->roadVelocity = m_stepDims * calcSpeed(t);
258 requires std::is_same_v<T, CollisionInfo> || std::is_same_v<T, CollisionInfoPartial>
259bool ObjectEscalator::checkPointImpl(ShouldCheckFunc shouldCheckFunc, CheckPointFunc<T> checkFunc,
260 const EGG::Vector3f &pos,
const EGG::Vector3f &prevPos, KCLTypeMask mask, T *info,
261 KCLTypeMask *maskOut) {
262 if (m_checkColYPosMin > pos.y || pos.y >= m_checkColYPosMax) {
266 if (!(this->*shouldCheckFunc)()) {
270 return (m_objColMgr->*checkFunc)(pos, prevPos, mask, info, maskOut);
274 requires std::is_same_v<T, CollisionInfo> || std::is_same_v<T, CollisionInfoPartial>
275bool ObjectEscalator::checkSphereImpl(ShouldCheckFunc shouldCheckFunc, CheckSphereFunc<T> checkFunc,
276 f32 radius,
const EGG::Vector3f &pos,
const EGG::Vector3f &prevPos, KCLTypeMask mask,
277 T *info, KCLTypeMask *maskOut, u32 timeOffset) {
278 if (m_checkColYPosMin > pos.y || pos.y >= m_checkColYPosMax) {
282 if (!(this->*shouldCheckFunc)()) {
286 calcScale(timeOffset);
289 return (m_objColMgr->*checkFunc)(radius, pos, prevPos, mask, info, maskOut);
293f32 ObjectEscalator::calcStepFactor(s32 t) {
294 constexpr s32 REVERSE_FRAMES_S32 =
static_cast<s32
>(REVERSE_FRAMES_F32);
295 constexpr s32 DISCRETE_STEP_OFFSETS = 200;
298 std::array<s32, 2> dtStop = {
static_cast<s32
>(
static_cast<f32
>(t) - m_stopFrames[0]),
299 static_cast<s32
>(
static_cast<f32
>(t) - m_stopFrames[1])};
302 std::array<s32, 2> dtStart = {
static_cast<s32
>(
static_cast<f32
>(t) - m_startFrames[0]),
303 static_cast<s32
>(
static_cast<f32
>(t) - m_startFrames[1])};
306 std::array<s32, 2> dtFullSpeed = {
static_cast<s32
>(
static_cast<f32
>(t) - m_fullSpeedFrames[0]),
307 static_cast<s32
>(
static_cast<f32
>(t) - m_fullSpeedFrames[1])};
312 auto dist0 = [
this](s32 t) -> f64 {
313 t = std::clamp<s32>(t, 0,
static_cast<s32
>(m_stopFrames[0]));
314 return static_cast<f64
>(
static_cast<f32
>(t) * m_speed[0]);
318 auto dist1 = [=,
this]() -> f64 {
319 f64 speed =
static_cast<f64
>(m_speed[0]);
320 f64 t =
static_cast<f64
>(std::clamp<s32>(dtStop[0], 0, REVERSE_FRAMES_S32));
321 return 0.5 * t * (speed + speed * (1.0 - t /
static_cast<f64
>(REVERSE_FRAMES_F32)));
325 auto dist2 = [=,
this]() -> f64 {
326 f64 t =
static_cast<f64
>(std::clamp<s32>(dtStart[0], 0, REVERSE_FRAMES_S32));
327 return t * (0.5 * t *
static_cast<f64
>(m_speed[1])) /
static_cast<f64
>(REVERSE_FRAMES_F32);
331 auto dist3 = [=,
this](s32 t) -> f64 {
332 t = std::clamp<s32>(dtFullSpeed[0], 0, m_midDuration);
333 return static_cast<f64
>(
static_cast<f32
>(t) * m_speed[1]);
337 auto dist4 = [=,
this]() -> f64 {
338 f64 speed =
static_cast<f64
>(m_speed[1]);
339 f64 t =
static_cast<f32
>(std::clamp<s32>(dtStop[1], 0, REVERSE_FRAMES_S32));
340 return 0.5 * t * (speed + speed * (1.0 - t /
static_cast<f64
>(REVERSE_FRAMES_F32)));
344 auto dist5 = [=,
this]() -> f64 {
345 f64 speed =
static_cast<f64
>(m_speed[2]);
346 f64 t =
static_cast<f64
>(std::clamp<s32>(dtStart[1], 0, REVERSE_FRAMES_S32));
347 return (t * (0.5 * t * speed) /
static_cast<f64
>(REVERSE_FRAMES_F32));
351 auto dist6 = [=,
this]() -> f64 {
352 f64 t =
static_cast<f64
>(std::max(dtFullSpeed[1], 0));
353 return t *
static_cast<f64
>(m_speed[2]);
356 f64 totalDist = dist6() + dist5() + dist4() + dist3(t) + dist2() + dist0(t) + dist1();
357 s32 result =
static_cast<s32
>(STEP_HEIGHT *
static_cast<f32
>(totalDist));
358 f32 fin =
static_cast<f32
>(result % DISCRETE_STEP_OFFSETS);
361 fin +=
static_cast<f32
>(DISCRETE_STEP_OFFSETS);
364 return fin / STEP_HEIGHT;
368f32 ObjectEscalator::calcSpeed(s32 t) {
370 if (
static_cast<f32
>(t) < m_stopFrames[0]) {
375 if (t < m_stillFrames[0]) {
376 return m_speed[0] *
static_cast<f32
>(m_stillFrames[0] - t) / REVERSE_FRAMES_F32;
380 if (
static_cast<f32
>(t) <= m_startFrames[0]) {
385 if (
static_cast<f32
>(t) < REVERSE_FRAMES_F32 + m_startFrames[0]) {
386 return m_speed[1] * (
static_cast<f32
>(t) - m_startFrames[0]) / REVERSE_FRAMES_F32;
390 if (
static_cast<f32
>(t) < m_stopFrames[1]) {
395 if (t < m_stillFrames[1]) {
396 return m_speed[1] *
static_cast<f32
>(m_stillFrames[1] - t) / REVERSE_FRAMES_F32;
400 if (
static_cast<f32
>(t) <= m_startFrames[1]) {
405 if (
static_cast<f32
>(t) < REVERSE_FRAMES_F32 + m_startFrames[1]) {
406 return m_speed[2] * (
static_cast<f32
>(t) - m_startFrames[1]) / REVERSE_FRAMES_F32;
@ COL_TYPE_MOVING_ROAD
TF conveyers and CM escalators.