1#include "ObjectEscalator.hh"
3#include "game/field/CollisionDirector.hh"
4#include "game/field/ObjectDirector.hh"
6#include "game/system/RaceManager.hh"
14 : ObjectKCL(params), m_initialPos(m_pos), m_initialRot(m_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]) {
37 mat.
makeR(m_initialRot);
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 m_pos = m_initialPos + m_stepDims * m_stepFactor;
51 m_flags.setBit(eFlags::Position);
56 KCLTypeMask mask, CollisionInfoPartial *info, KCLTypeMask *maskOut) {
57 return checkPointImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkPointPartial,
58 pos, prevPos, mask, info, maskOut);
63 KCLTypeMask mask, CollisionInfoPartial *info, KCLTypeMask *maskOut) {
64 return checkPointImpl(&ObjectEscalator::shouldCheckColPush, &ObjColMgr::checkPointPartialPush,
65 pos, prevPos, mask, info, maskOut);
70 KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) {
71 return checkPointImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkPointFull, pos,
72 prevPos, mask, info, maskOut);
77 KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) {
78 return checkPointImpl(&ObjectEscalator::shouldCheckColPush, &ObjColMgr::checkPointFullPush, pos,
79 prevPos, mask, info, maskOut);
83bool ObjectEscalator::checkSpherePartial(f32 radius,
const EGG::Vector3f &pos,
84 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
85 KCLTypeMask *maskOut,
u32 timeOffset) {
86 return checkSphereImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkSpherePartial,
87 radius, pos, prevPos, mask, info, maskOut, timeOffset);
91bool ObjectEscalator::checkSpherePartialPush(f32 radius,
const EGG::Vector3f &pos,
92 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
93 KCLTypeMask *maskOut,
u32 timeOffset) {
94 return checkSphereImpl(&ObjectEscalator::shouldCheckColPush, &ObjColMgr::checkSpherePartialPush,
95 radius, pos, prevPos, mask, info, maskOut, timeOffset);
99bool ObjectEscalator::checkSphereFull(f32 radius,
const EGG::Vector3f &pos,
100 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
102 return checkSphereImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkSphereFull,
103 radius, pos, prevPos, mask, info, maskOut, timeOffset);
107bool ObjectEscalator::checkSphereFullPush(f32 radius,
const EGG::Vector3f &pos,
108 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
110 return checkCollision(radius, pos, prevPos, mask, info, maskOut, timeOffset);
114void ObjectEscalator::narrScLocal(f32 radius,
const EGG::Vector3f &pos, KCLTypeMask mask,
116 m_objColMgr->narrScLocal(radius, pos, mask);
120bool ObjectEscalator::checkPointCachedPartial(
const EGG::Vector3f &pos,
121 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
122 KCLTypeMask *maskOut) {
123 return checkPointImpl(&ObjectEscalator::shouldCheckColNoPush,
124 &ObjColMgr::checkPointCachedPartial, pos, prevPos, mask, info, maskOut);
128bool ObjectEscalator::checkPointCachedPartialPush(
const EGG::Vector3f &pos,
129 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
130 KCLTypeMask *maskOut) {
131 return checkPointImpl(&ObjectEscalator::shouldCheckColPush,
132 &ObjColMgr::checkPointCachedPartialPush, pos, prevPos, mask, info, maskOut);
137 KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) {
138 return checkPointImpl(&ObjectEscalator::shouldCheckColNoPush, &ObjColMgr::checkPointCachedFull,
139 pos, prevPos, mask, info, maskOut);
143bool ObjectEscalator::checkPointCachedFullPush(
const EGG::Vector3f &pos,
144 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut) {
145 return checkPointImpl(&ObjectEscalator::shouldCheckColPush,
146 &ObjColMgr::checkPointCachedFullPush, pos, prevPos, mask, info, maskOut);
150bool ObjectEscalator::checkSphereCachedPartial(f32 radius,
const EGG::Vector3f &pos,
151 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
152 KCLTypeMask *maskOut,
u32 timeOffset) {
153 return checkSphereImpl(&ObjectEscalator::shouldCheckColNoPush,
154 &ObjColMgr::checkSphereCachedPartial, radius, pos, prevPos, mask, info, maskOut,
159bool ObjectEscalator::checkSphereCachedPartialPush(f32 radius,
const EGG::Vector3f &pos,
160 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfoPartial *info,
161 KCLTypeMask *maskOut,
u32 timeOffset) {
162 return checkSphereImpl(&ObjectEscalator::shouldCheckColPush,
163 &ObjColMgr::checkSphereCachedPartialPush, radius, pos, prevPos, mask, info, maskOut,
168bool ObjectEscalator::checkSphereCachedFull(f32 radius,
const EGG::Vector3f &pos,
169 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
171 return checkSphereImpl(&ObjectEscalator::shouldCheckColNoPush,
172 &ObjColMgr::checkSphereCachedFull, radius, pos, prevPos, mask, info, maskOut,
177bool ObjectEscalator::checkSphereCachedFullPush(f32 radius,
const EGG::Vector3f &pos,
178 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
180 return checkCollisionCached(radius, pos, prevPos, mask, info, maskOut, timeOffset);
185 u32 t = System::RaceManager::Instance()->timer() - timeOffset;
186 m_workMatrix.makeRT(m_rot, m_initialPos + m_stepDims * calcStepFactor(t));
191bool ObjectEscalator::checkCollision(f32 radius,
const EGG::Vector3f &pos,
192 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
196 if (m_checkColYPosMin >= pos.y || pos.y >= m_checkColYPosMax) {
200 if (!m_objColMgr->checkSphereFullPush(radius, pos, prevPos, mask, info, maskOut)) {
208 auto *colDir = CollisionDirector::Instance();
213 auto *entry = colDir->closestCollisionEntry();
214 if (entry->dist > info->movingFloorDist) {
215 info->movingFloorDist = entry->dist;
217 u32 t = System::RaceManager::Instance()->timer() - timeOffset;
218 info->roadVelocity = m_stepDims * calcSpeed(t);
225bool ObjectEscalator::checkCollisionCached(f32 radius,
const EGG::Vector3f &pos,
226 const EGG::Vector3f &prevPos, KCLTypeMask mask, CollisionInfo *info, KCLTypeMask *maskOut,
230 if (m_checkColYPosMin >= pos.y || pos.y >= m_checkColYPosMax) {
234 if (!m_objColMgr->checkSphereCachedFullPush(radius, pos, prevPos, mask, info, maskOut)) {
242 auto *colDir = CollisionDirector::Instance();
247 auto *entry = colDir->closestCollisionEntry();
248 if (entry->dist > info->movingFloorDist) {
249 info->movingFloorDist = entry->dist;
251 u32 t = System::RaceManager::Instance()->timer() - timeOffset;
252 info->roadVelocity = m_stepDims * calcSpeed(t);
259 requires std::is_same_v<T, CollisionInfo> || std::is_same_v<T, CollisionInfoPartial>
260bool ObjectEscalator::checkPointImpl(ShouldCheckFunc shouldCheckFunc, CheckPointFunc<T> checkFunc,
262 KCLTypeMask *maskOut) {
263 if (m_checkColYPosMin > pos.y || pos.y >= m_checkColYPosMax) {
267 if (!(this->*shouldCheckFunc)()) {
271 return (m_objColMgr->*checkFunc)(pos, prevPos, mask, info, maskOut);
275 requires std::is_same_v<T, CollisionInfo> || std::is_same_v<T, CollisionInfoPartial>
276bool ObjectEscalator::checkSphereImpl(ShouldCheckFunc shouldCheckFunc, CheckSphereFunc<T> checkFunc,
278 T *info, KCLTypeMask *maskOut,
u32 timeOffset) {
279 if (m_checkColYPosMin > pos.y || pos.y >= m_checkColYPosMax) {
283 if (!(this->*shouldCheckFunc)()) {
287 calcScale(timeOffset);
290 return (m_objColMgr->*checkFunc)(radius, pos, prevPos, mask, info, maskOut);
294f32 ObjectEscalator::calcStepFactor(s32 t) {
295 constexpr s32 REVERSE_FRAMES_S32 =
static_cast<s32
>(REVERSE_FRAMES_F32);
296 constexpr s32 DISCRETE_STEP_OFFSETS = 200;
299 std::array<s32, 2> dtStop = {
static_cast<s32
>(
static_cast<f32
>(t) - m_stopFrames[0]),
300 static_cast<s32
>(
static_cast<f32
>(t) - m_stopFrames[1])};
303 std::array<s32, 2> dtStart = {
static_cast<s32
>(
static_cast<f32
>(t) - m_startFrames[0]),
304 static_cast<s32
>(
static_cast<f32
>(t) - m_startFrames[1])};
307 std::array<s32, 2> dtFullSpeed = {
static_cast<s32
>(
static_cast<f32
>(t) - m_fullSpeedFrames[0]),
308 static_cast<s32
>(
static_cast<f32
>(t) - m_fullSpeedFrames[1])};
313 auto dist0 = [
this](s32 t) -> f64 {
314 t = std::clamp<s32>(t, 0,
static_cast<s32
>(m_stopFrames[0]));
315 return static_cast<f64
>(
static_cast<f32
>(t) * m_speed[0]);
319 auto dist1 = [=,
this]() -> f64 {
320 f64 speed =
static_cast<f64
>(m_speed[0]);
321 f64 t =
static_cast<f64
>(std::clamp<s32>(dtStop[0], 0, REVERSE_FRAMES_S32));
322 return 0.5 * t * (speed + speed * (1.0 - t /
static_cast<f64
>(REVERSE_FRAMES_F32)));
326 auto dist2 = [=,
this]() -> f64 {
327 f64 t =
static_cast<f64
>(std::clamp<s32>(dtStart[0], 0, REVERSE_FRAMES_S32));
328 return t * (0.5 * t *
static_cast<f64
>(m_speed[1])) /
static_cast<f64
>(REVERSE_FRAMES_F32);
332 auto dist3 = [=,
this](s32 t) -> f64 {
333 t = std::clamp<s32>(dtFullSpeed[0], 0, m_midDuration);
334 return static_cast<f64
>(
static_cast<f32
>(t) * m_speed[1]);
338 auto dist4 = [=,
this]() -> f64 {
339 f64 speed =
static_cast<f64
>(m_speed[1]);
340 f64 t =
static_cast<f32
>(std::clamp<s32>(dtStop[1], 0, REVERSE_FRAMES_S32));
341 return 0.5 * t * (speed + speed * (1.0 - t /
static_cast<f64
>(REVERSE_FRAMES_F32)));
345 auto dist5 = [=,
this]() -> f64 {
346 f64 speed =
static_cast<f64
>(m_speed[2]);
347 f64 t =
static_cast<f64
>(std::clamp<s32>(dtStart[1], 0, REVERSE_FRAMES_S32));
348 return (t * (0.5 * t * speed) /
static_cast<f64
>(REVERSE_FRAMES_F32));
352 auto dist6 = [=,
this]() -> f64 {
353 f64 t =
static_cast<f64
>(std::max(dtFullSpeed[1], 0));
354 return t *
static_cast<f64
>(m_speed[2]);
357 f64 totalDist = dist6() + dist5() + dist4() + dist3(t) + dist2() + dist0(t) + dist1();
358 s32 result =
static_cast<s32
>(STEP_HEIGHT *
static_cast<f32
>(totalDist));
359 f32 fin =
static_cast<f32
>(result % DISCRETE_STEP_OFFSETS);
362 fin +=
static_cast<f32
>(DISCRETE_STEP_OFFSETS);
365 return fin / STEP_HEIGHT;
369f32 ObjectEscalator::calcSpeed(s32 t) {
371 if (
static_cast<f32
>(t) < m_stopFrames[0]) {
376 if (t < m_stillFrames[0]) {
377 return m_speed[0] *
static_cast<f32
>(m_stillFrames[0] - t) / REVERSE_FRAMES_F32;
381 if (
static_cast<f32
>(t) <= m_startFrames[0]) {
386 if (
static_cast<f32
>(t) < REVERSE_FRAMES_F32 + m_startFrames[0]) {
387 return m_speed[1] * (
static_cast<f32
>(t) - m_startFrames[0]) / REVERSE_FRAMES_F32;
391 if (
static_cast<f32
>(t) < m_stopFrames[1]) {
396 if (t < m_stillFrames[1]) {
397 return m_speed[1] *
static_cast<f32
>(m_stillFrames[1] - t) / REVERSE_FRAMES_F32;
401 if (
static_cast<f32
>(t) <= m_startFrames[1]) {
406 if (
static_cast<f32
>(t) < REVERSE_FRAMES_F32 + m_startFrames[1]) {
407 return m_speed[2] * (
static_cast<f32
>(t) - m_startFrames[1]) / REVERSE_FRAMES_F32;
@ COL_TYPE_MOVING_ROAD
TF conveyers and CM escalators.
void makeR(const Vector3f &r)
Sets 3x3 rotation matrix from a vector of Euler angles.
Vector3f ps_multVector(const Vector3f &vec) const
Paired-singles impl. of multVector.