From 7b1ca8924df5e755500c8c3327659670c0d90fbd Mon Sep 17 00:00:00 2001 From: malleoz Date: Mon, 9 Dec 2024 15:38:08 -0500 Subject: [PATCH] Sync ObjectAurora (RR wavy road) --- STATUS.md | 4 +- source/game/field/CollisionDirector.hh | 18 ++ source/game/field/ObjectDirector.cc | 2 + source/game/field/obj/ObjectAurora.cc | 314 ++++++++++++++++++++++++ source/game/field/obj/ObjectAurora.hh | 87 +++++++ source/game/field/obj/ObjectId.hh | 1 + source/game/field/obj/ObjectRegistry.hh | 1 + source/game/system/RaceManager.hh | 4 + 8 files changed, 429 insertions(+), 2 deletions(-) create mode 100644 source/game/field/obj/ObjectAurora.cc create mode 100644 source/game/field/obj/ObjectAurora.hh diff --git a/STATUS.md b/STATUS.md index ca8316c4..c039db7c 100644 --- a/STATUS.md +++ b/STATUS.md @@ -27,8 +27,8 @@ Test Case | Frames | | [`mh-rta-1-42-872`](https://youtu.be/CellUlOYgnc) | 6578 / 6578 | ✔️ | [`bc-rta-2-08-697`](https://youtu.be/1DEReKemoeI) | 808 / 8126 | ❌ | KMP [`bc-ng-rta-2-20-001`](https://youtu.be/028nClzy7B4) | 808 / 8803 | ❌ | KMP -[`rr-rta-1-24-751`](https://youtu.be/dgNMHyFda14) | 3194 / 5491 | ❌ | KMP -[`rr-ng-rta-2-24-281`](https://youtu.be/O-BtWWsq82o) | 1207 / 9060 | ❌ | KMP +[`rr-rta-1-24-751`](https://youtu.be/dgNMHyFda14) | 5491 / 5491 | ✔️ | +[`rr-ng-rta-2-24-281`](https://youtu.be/O-BtWWsq82o) | 2217 / 9060 | ❌ | Cannon drop? [`rpb-rta-0-59-978`](https://youtu.be/Z-lVl-7B-So) | 1078 / 4007 | ❌ | Moving water [`rpb-ng-rta-1-12-656`](https://youtu.be/LujU0kJx-hU) | 2491 / 4767 | ❌ | Moving water [`ryf-rta-0-58-648`](https://youtu.be/3IKzbmawUbk) | 583 / 3927 | ❌ | Water diff --git a/source/game/field/CollisionDirector.hh b/source/game/field/CollisionDirector.hh index 49c0076d..94c06871 100644 --- a/source/game/field/CollisionDirector.hh +++ b/source/game/field/CollisionDirector.hh @@ -42,6 +42,24 @@ public: void resetCollisionEntries(KCLTypeMask *ptr); void pushCollisionEntry(f32 dist, KCLTypeMask *typeMask, KCLTypeMask kclTypeBit, u16 attribute); + /// @addr{0x807BDB5C} + void setCurrentCollisionVariant(u16 attribute) { + ASSERT(m_collisionEntryCount > 0); + u16 &entryAttr = m_entries[m_collisionEntryCount - 1].attribute; + entryAttr = (entryAttr & 0xff1f) | (attribute << 5); + } + + /// @addr{0x807BDBC4} + void setCurrentCollisionTrickable(bool trickable) { + ASSERT(m_collisionEntryCount > 0); + u16 &entryAttr = m_entries[m_collisionEntryCount - 1].attribute; + entryAttr &= 0xdfff; + + if (trickable) { + entryAttr |= (1 << 0xd); + } + } + bool findClosestCollisionEntry(KCLTypeMask *typeMask, KCLTypeMask type); /// @beginGetters diff --git a/source/game/field/ObjectDirector.cc b/source/game/field/ObjectDirector.cc index 57322eac..6d97d622 100644 --- a/source/game/field/ObjectDirector.cc +++ b/source/game/field/ObjectDirector.cc @@ -182,6 +182,8 @@ ObjectBase *ObjectDirector::createObject(const System::MapdataGeoObj ¶ms) { return new ObjectParasolR(params); case ObjectId::PuchiPakkun: return new ObjectPuchiPakkun(params); + case ObjectId::Aurora: + return new ObjectAurora(params); // Non-specified objects are stock collidable objects by default // However, we need to specify an impl, so we don't use default case ObjectId::DummyPole: diff --git a/source/game/field/obj/ObjectAurora.cc b/source/game/field/obj/ObjectAurora.cc new file mode 100644 index 00000000..f6a5686a --- /dev/null +++ b/source/game/field/obj/ObjectAurora.cc @@ -0,0 +1,314 @@ +#include "ObjectAurora.hh" + +#include "game/field/CollisionDirector.hh" + +#include "game/system/RaceManager.hh" + +namespace Field { + +/// @addr{0x807FAB58} +ObjectAurora::ObjectAurora(const System::MapdataGeoObj ¶ms) : ObjectDrivable(params) {} + +/// @addr{0x807FB690} +ObjectAurora::~ObjectAurora() = default; + +/// @addr{0x807FABC4} +void ObjectAurora::init() {} + +/// @addr{0x807FB688} +u32 ObjectAurora::loadFlags() const { + return 1; +} + +/// @addr{0x807FB684} +void ObjectAurora::createCollision() {} + +/// @addr{0x807FB680} +void ObjectAurora::calcCollisionTransform() {} + +/// @addr{0x807FB5DC} +f32 ObjectAurora::getCollisionRadius() const { + return COLLISION_SIZE.z + 100.0f; +} + +/// @addr{0x807FB59C} +bool ObjectAurora::checkPointPartial(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) { + return checkSpherePartialImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0); +} + +/// @addr{0x807FB5AC} +bool ObjectAurora::checkPointPartialPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) { + return checkSpherePartialPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0); +} + +/// @addr{0x807FB5BC} +bool ObjectAurora::checkPointFull(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) { + return checkSphereFullImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0); +} + +/// @addr{0x807FB5CC} +bool ObjectAurora::checkPointFullPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) { + return checkSphereFullPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0); +} + +/// @addr{0x807FB58C} +bool ObjectAurora::checkSpherePartial(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) { + return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset); +} + +/// @addr{0x807FB590} +bool ObjectAurora::checkSpherePartialPush(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) { + return checkSpherePartialPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset); +} + +/// @addr{0x807FB594} +bool ObjectAurora::checkSphereFull(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) { + return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset); +} + +/// @addr{0x807FB598} +bool ObjectAurora::checkSphereFullPush(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) { + return checkSphereFullPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset); +} + +/// @addr{0x807FB54C} +bool ObjectAurora::checkPointCachedPartial(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) { + return checkSpherePartialImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0); +} + +/// @addr{0x807FB55C} +bool ObjectAurora::checkPointCachedPartialPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) { + return checkSpherePartialPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0); +} + +/// @addr{0x807FB56C} +bool ObjectAurora::checkPointCachedFull(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) { + return checkSphereFullImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0); +} + +/// @addr{0x807FB57C} +bool ObjectAurora::checkPointCachedFullPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) { + return checkSphereFullPushImpl(0.0f, v0, v1, flags, pInfo, pFlagsOut, 0); +} + +/// @addr{0x807FB53C} +bool ObjectAurora::checkSphereCachedPartial(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) { + return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset); +} + +/// @addr{0x807FB540} +bool ObjectAurora::checkSphereCachedPartialPush(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) { + return checkSpherePartialPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset); +} + +/// @addr{0x807FB544} +bool ObjectAurora::checkSphereCachedFull(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, + u32 timeOffset) { + return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset); +} + +/// @addr{0x807FB548} +bool ObjectAurora::checkSphereCachedFullPush(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, + u32 timeOffset) { + return checkSphereFullPushImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset); +} + +/// @addr{0x807FB6D0} +bool ObjectAurora::checkSpherePartialImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) { + return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, false); +} + +/// @addr{0x807FB8B0} +bool ObjectAurora::checkSpherePartialPushImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) { + return checkSpherePartialImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, true); +} + +/// @addr{0x807FBAC0} +bool ObjectAurora::checkSphereFullImpl(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, u32 timeOffset) { + return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, false); +} + +/// @addr{0x807FBE6C} +bool ObjectAurora::checkSphereFullPushImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, + u32 timeOffset) { + return checkSphereFullImpl(radius, v0, v1, flags, pInfo, pFlagsOut, timeOffset, true); +} + +/// @brief Helper function which contains frequently re-used code. Behavior branches depending on +/// whether it is a push (push entry in the CollisionDirector). +/// @param push Whether to push a collision entry +bool ObjectAurora::checkSpherePartialImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f & /*v1*/, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset, bool push) { + EGG::Vector3f vel = v0 - m_pos; + + if (vel.z < 0.0f || vel.z > COLLISION_SIZE.z || EGG::Mathf::abs(vel.x) > COLLISION_SIZE.x) { + return false; + } + + if (!(flags & KCL_TYPE_FLOOR)) { + return false; + } + + u32 t = timeOffset + System::RaceManager::Instance()->timer(); + EGG::Vector3f bbox; + EGG::Vector3f fnrm; + f32 dist; + + if (!calcCollision(radius, vel, t, bbox, fnrm, dist)) { + return false; + } + + if (pInfo) { + pInfo->bbox.min = pInfo->bbox.min.minimize(bbox); + pInfo->bbox.max = pInfo->bbox.max.maximize(bbox); + } + + if (pFlagsOut) { + auto *colDirector = CollisionDirector::Instance(); + + if (push) { + colDirector->pushCollisionEntry(dist, pFlagsOut, KCL_TYPE_BIT(COL_TYPE_ROAD2), + COL_TYPE_ROAD2); + colDirector->setCurrentCollisionVariant(7); + colDirector->setCurrentCollisionTrickable(true); + } else { + *pFlagsOut |= KCL_TYPE_BIT(COL_TYPE_ROTATING_ROAD); + } + + if (vel.z > COLLISION_SIZE.z - 600.0f * 4.0f) { + if (push) { + colDirector->pushCollisionEntry(dist, pFlagsOut, KCL_TYPE_BIT(COL_TYPE_BOOST_RAMP), + COL_TYPE_BOOST_RAMP); + } else { + *pFlagsOut |= KCL_TYPE_BIT(COL_TYPE_ROAD2) | KCL_TYPE_BIT(COL_TYPE_BOOST_RAMP); + } + } + } + + return true; +} + +/// @brief Helper function which contains frequently re-used code. Behavior branches depending on +/// whether it is a push (push entry in the CollisionDirector). +/// @param push Whether to push a collision entry +bool ObjectAurora::checkSphereFullImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f & /*v1*/, KCLTypeMask flags, CollisionInfo *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset, bool push) { + EGG::Vector3f vel = v0 - m_pos; + + if (vel.z < 0.0f || vel.z > COLLISION_SIZE.z || EGG::Mathf::abs(vel.x) > COLLISION_SIZE.x) { + return false; + } + + if (!(flags & KCL_TYPE_FLOOR)) { + return false; + } + + u32 t = timeOffset + System::RaceManager::Instance()->timer(); + EGG::Vector3f bbox; + EGG::Vector3f fnrm; + f32 dist; + + if (!calcCollision(radius, vel, t, bbox, fnrm, dist)) { + return false; + } + + if (pInfo) { + pInfo->bbox.min = pInfo->bbox.min.minimize(bbox); + pInfo->bbox.max = pInfo->bbox.max.maximize(bbox); + + pInfo->updateFloor(dist, fnrm); + } + + if (pFlagsOut) { + auto *colDirector = CollisionDirector::Instance(); + + if (push) { + colDirector->pushCollisionEntry(dist, pFlagsOut, KCL_TYPE_BIT(COL_TYPE_ROAD2), + COL_TYPE_ROAD2); + colDirector->setCurrentCollisionVariant(7); + colDirector->setCurrentCollisionTrickable(true); + } else { + *pFlagsOut |= KCL_TYPE_BIT(COL_TYPE_ROTATING_ROAD); + } + + if (vel.z > COLLISION_SIZE.z - 600.0f * 4.0f) { + if (push) { + colDirector->pushCollisionEntry(dist, pFlagsOut, KCL_TYPE_BIT(COL_TYPE_BOOST_RAMP), + COL_TYPE_BOOST_RAMP); + } else { + *pFlagsOut |= KCL_TYPE_BIT(COL_TYPE_ROAD2) | KCL_TYPE_BIT(COL_TYPE_BOOST_RAMP); + } + } + } + + return true; +} + +/// @addr{0x807FB060} +/// @brief Calculates the sin-like collision of the wavy road. +/// @details It seems to be modeled as a quadratic chirp with a starting frequency of 1 and a max +/// frequency of 4. The minimum frequency of 1 occurs 30s into the race, and the maximum frequency +/// occurs 2min 13s into the race. The "observed" frequency is dependent on the player's velocity +/// towards the wavy road as well. +bool ObjectAurora::calcCollision(f32 radius, const EGG::Vector3f &vel, u32 time, EGG::Vector3f &v0, + EGG::Vector3f &fnrm, f32 &dist) { + constexpr float INITIAL_FREQUENCY = 1.0f; + constexpr float MAX_FREQUENCY = 4.0f; + constexpr float PHASE_SHIFT_SECONDS = 30.0f; + constexpr float COLLISION_DISTANCE_THRESHOLD = 600.0f; + constexpr float UPWARP_THRESHOLD = 300.0f; + constexpr float UPWARP_DIST_SCALAR = 0.2f; + + f32 minsNormalized = (static_cast(time) / 60.0f - PHASE_SHIFT_SECONDS) / 60.0f; + f32 frequency = std::min(INITIAL_FREQUENCY + minsNormalized * minsNormalized, MAX_FREQUENCY); + f32 velPeriod = (F_PI * (2.0f * vel.z)) / COLLISION_SIZE.z; + + f32 result = EGG::Mathf::SinFIdx( + RAD2FIDX * (velPeriod * frequency + (F_PI * static_cast(time)) / 50.0f)); + result = radius - (vel.y - velPeriod * 80.0f * result); + + // We're not colliding if we're 600 units away or if the road is now behind us. + if (result <= 0.0f || result >= COLLISION_DISTANCE_THRESHOLD) { + return false; + } + + // Responsible for the sudden upwards snap that can occur when falling off. + if (result > UPWARP_THRESHOLD) { + result *= UPWARP_DIST_SCALAR; + } + + fnrm = EGG::Vector3f::ey; + v0 = fnrm * result; + dist = result; + + return true; +} + +} // namespace Field diff --git a/source/game/field/obj/ObjectAurora.hh b/source/game/field/obj/ObjectAurora.hh new file mode 100644 index 00000000..607e57dd --- /dev/null +++ b/source/game/field/obj/ObjectAurora.hh @@ -0,0 +1,87 @@ +#pragma once + +#include "game/field/obj/ObjectDrivable.hh" + +namespace Field { + +class ObjectAurora : public ObjectDrivable { +public: + ObjectAurora(const System::MapdataGeoObj ¶ms); + ~ObjectAurora() override; + + void init() override; + [[nodiscard]] u32 loadFlags() const override; + void createCollision() override; + void calcCollisionTransform() override; + f32 getCollisionRadius() const override; + + [[nodiscard]] bool checkPointPartial(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) override; + [[nodiscard]] bool checkPointPartialPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) override; + [[nodiscard]] bool checkPointFull(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) override; + [[nodiscard]] bool checkPointFullPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) override; + [[nodiscard]] bool checkSpherePartial(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) override; + [[nodiscard]] bool checkSpherePartialPush(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) override; + [[nodiscard]] bool checkSphereFull(f32 radius, const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut, + u32 timeOffset) override; + [[nodiscard]] bool checkSphereFullPush(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) override; + [[nodiscard]] bool checkPointCachedPartial(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) override; + [[nodiscard]] bool checkPointCachedPartialPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfoPartial *pInfo, KCLTypeMask *pFlagsOut) override; + [[nodiscard]] bool checkPointCachedFull(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) override; + [[nodiscard]] bool checkPointCachedFullPush(const EGG::Vector3f &v0, const EGG::Vector3f &v1, + KCLTypeMask flags, CollisionInfo *pInfo, KCLTypeMask *pFlagsOut) override; + [[nodiscard]] bool checkSphereCachedPartial(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) override; + [[nodiscard]] bool checkSphereCachedPartialPush(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) override; + [[nodiscard]] bool checkSphereCachedFull(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) override; + [[nodiscard]] bool checkSphereCachedFullPush(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset) override; + +private: + [[nodiscard]] bool checkSpherePartialImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset); + [[nodiscard]] bool checkSpherePartialPushImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset); + [[nodiscard]] bool checkSphereFullImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset); + [[nodiscard]] bool checkSphereFullPushImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset); + + [[nodiscard]] bool checkSpherePartialImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfoPartial *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset, bool push); + + [[nodiscard]] bool checkSphereFullImpl(f32 radius, const EGG::Vector3f &v0, + const EGG::Vector3f &v1, KCLTypeMask flags, CollisionInfo *pInfo, + KCLTypeMask *pFlagsOut, u32 timeOffset, bool push); + + [[nodiscard]] bool calcCollision(f32 radius, const EGG::Vector3f &vel, u32 time, + EGG::Vector3f &v0, EGG::Vector3f &fnrm, f32 &dist); + + static constexpr EGG::Vector3f COLLISION_SIZE = EGG::Vector3f(2000.0f, 2000.0f, 15000.0f); +}; + +} // namespace Field diff --git a/source/game/field/obj/ObjectId.hh b/source/game/field/obj/ObjectId.hh index 87d57c00..a50df690 100644 --- a/source/game/field/obj/ObjectId.hh +++ b/source/game/field/obj/ObjectId.hh @@ -13,6 +13,7 @@ enum class ObjectId { OilSFC = 0x15d, ParasolR = 0x16e, PuchiPakkun = 0x1aa, + Aurora = 0x204, }; enum class BlacklistedObjectId { diff --git a/source/game/field/obj/ObjectRegistry.hh b/source/game/field/obj/ObjectRegistry.hh index a7642aa6..ec6a52d6 100644 --- a/source/game/field/obj/ObjectRegistry.hh +++ b/source/game/field/obj/ObjectRegistry.hh @@ -1,5 +1,6 @@ #pragma once +#include "game/field/obj/ObjectAurora.hh" #include "game/field/obj/ObjectDokan.hh" #include "game/field/obj/ObjectNoImpl.hh" #include "game/field/obj/ObjectOilSFC.hh" diff --git a/source/game/system/RaceManager.hh b/source/game/system/RaceManager.hh index 0e8eb56a..0d5967af 100644 --- a/source/game/system/RaceManager.hh +++ b/source/game/system/RaceManager.hh @@ -121,6 +121,10 @@ public: [[nodiscard]] Stage stage() const { return m_stage; } + + [[nodiscard]] u32 timer() const { + return m_timer; + } /// @endGetters static RaceManager *CreateInstance();