diff --git a/Runtime/World/CMakeLists.txt b/Runtime/World/CMakeLists.txt index 467864175..87be6f832 100644 --- a/Runtime/World/CMakeLists.txt +++ b/Runtime/World/CMakeLists.txt @@ -45,6 +45,7 @@ set(WORLD_SOURCES CScriptActorKeyframe.hpp CScriptActorKeyframe.cpp CScriptWater.hpp CScriptWater.cpp CScriptGrapplePoint.hpp CScriptGrapplePoint.cpp + CScriptSpiderBallAttractionSurface.hpp CScriptSpiderBallAttractionSurface.cpp CScriptPickupGenerator.hpp CScriptPickupGenerator.cpp CScriptPointOfInterest.hpp CScriptPointOfInterest.cpp CScriptAreaAttributes.hpp CScriptAreaAttributes.cpp diff --git a/Runtime/World/CMorphBall.cpp b/Runtime/World/CMorphBall.cpp index 0fca99a47..33b6dff35 100644 --- a/Runtime/World/CMorphBall.cpp +++ b/Runtime/World/CMorphBall.cpp @@ -10,6 +10,8 @@ #include "TCastTo.hpp" #include "Camera/CGameCamera.hpp" #include "Collision/CGameCollision.hpp" +#include "CScriptSpiderBallAttractionSurface.hpp" +#include "CScriptSpiderBallWaypoint.hpp" namespace urde { @@ -386,68 +388,384 @@ bool CMorphBall::IsMovementAllowed() const return x1e00_ <= 0.f; } -void CMorphBall::UpdateSpiderBall(const CFinalInput&, CStateManager&, float) +void CMorphBall::UpdateSpiderBall(const CFinalInput& input, CStateManager& mgr, float dt) { - + SetSpiderBallSwingingState(CheckForSwitchToSpiderBallSwinging(mgr)); + if (x18be_spiderBallSwinging) + ApplySpiderBallSwingingForces(input, mgr, dt); + else + ApplySpiderBallRollForces(input, mgr, dt); } -void CMorphBall::ApplySpiderBallSwingingForces(const CFinalInput&, CStateManager&, float) +void CMorphBall::ApplySpiderBallSwingingForces(const CFinalInput& input, CStateManager& mgr, float dt) { - + x18b4_ = 0.04f; + x18b8_ = 0.99f; + x1880_playerToSpiderNormal = x1890_spiderTrackPoint - x0_player.GetTranslation(); + float playerToSpiderDist = x1880_playerToSpiderNormal.magnitude(); + x1880_playerToSpiderNormal = x1880_playerToSpiderNormal * (-1.f / playerToSpiderDist); + float movement = GetSpiderBallControllerMovement(input); + UpdateSpiderBallSwingControllerMovementTimer(movement, dt); + float swingMovement = movement * GetSpiderBallSwingControllerMovementScalar(); + float f29 = playerToSpiderDist * 110000.f / 3.7f; + x0_player.ApplyForceWR( + x1880_playerToSpiderNormal.cross(x18a8_spiderDistBetweenPoints).cross(x1880_playerToSpiderNormal).normalized() * + f29 * swingMovement * 0.06f, zeus::CAxisAngle::sIdentity); + x0_player.SetMomentumWR({0.f, 0.f, x0_player.GetMass() * g_tweakBall->GetBallGravity()}); + x18fc_refPullVel = (1.f - x188c_spiderPullMovement) * 3.7f + 1.4f; + x1900_playerToSpiderTrackDist = playerToSpiderDist; + zeus::CVector3f playerVel = x0_player.GetVelocity(); + float playerSpeed = playerVel.magnitude(); + playerVel -= x1880_playerToSpiderNormal * playerSpeed * x1880_playerToSpiderNormal.dot(playerVel.normalized()); + float maxPullVel = 0.04f; + if (x188c_spiderPullMovement == 1.f && std::fabs(x1880_playerToSpiderNormal.z) > 0.8f) + maxPullVel = 0.3f; + playerVel += x1880_playerToSpiderNormal * + zeus::clamp(-maxPullVel, x18fc_refPullVel - playerToSpiderDist, maxPullVel) / dt; + x0_player.SetVelocityWR(playerVel); } -zeus::CVector3f CMorphBall::TransformSpiderBallForcesToView(const zeus::CVector2f& forces, CStateManager& mgr) +zeus::CVector3f CMorphBall::TransformSpiderBallForcesXY(const zeus::CVector2f& forces, CStateManager& mgr) { return mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTransform().basis * zeus::CVector3f(forces.x, forces.y, 0.f); } -void CMorphBall::ApplySpiderBallRollForces(const CFinalInput&, CStateManager&, float) +zeus::CVector3f CMorphBall::TransformSpiderBallForcesXZ(const zeus::CVector2f& forces, CStateManager& mgr) { - + return mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTransform().basis * + zeus::CVector3f(forces.x, 0.f, forces.y); } -void CMorphBall::CalculateSpiderBallAttractionSurfaceForces(const CFinalInput&, CStateManager&, - const zeus::CTransform&) +void CMorphBall::ApplySpiderBallRollForces(const CFinalInput& input, CStateManager& mgr, float dt) { + zeus::CVector2f surfaceForces = CalculateSpiderBallAttractionSurfaceForces(input); + zeus::CVector3f viewSurfaceForces = TransformSpiderBallForcesXZ(surfaceForces, mgr); + zeus::CTransform camXf = mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTransform(); + zeus::CVector3f spiderDirNorm = x189c_spiderInterpDistBetweenPoints.normalized(); + float upDot = std::fabs(spiderDirNorm.dot(camXf.basis[2])); + float foreDot = std::fabs(spiderDirNorm.dot(camXf.basis[1])); + if (x0_player.x9c4_29_ && upDot < 0.25f && foreDot > 0.25f) + viewSurfaceForces = TransformSpiderBallForcesXY(surfaceForces, mgr); + float forceMag = surfaceForces.magnitude(); + zeus::CVector2f x1d0; + float f26 = x18c0_isSpiderSurface ? forceMag : viewSurfaceForces.dot(spiderDirNorm); + bool r27 = true; + bool r30 = false; + if (std::fabs(forceMag) > 0.05f) + { + x1d0 = surfaceForces.normalized(); + if (!x18c0_isSpiderSurface && x1d0.dot(x190c_) > 0.9f) + { + f26 = x1914_ >= 0.f ? forceMag : -forceMag; + r30 = true; + } + else + { + if (std::fabs(f26) > 0.05f) + f26 = f26 >= 0.f ? forceMag : -forceMag; + else + r27 = false; + } + } + else + { + r27 = false; + } + if (!r30) + { + x190c_ = x1d0; + x1914_ = f26; + x1920_ = true; + } + + if (!r27) + { + f26 = 0.f; + ResetSpiderBallForces(); + } + + bool r31 = true; + if (!r27 && x0_player.GetVelocity().magnitude() <= 6.5f) + r31 = false; + + zeus::CVector3f f27; + if (x18bd_ && r27) + { + if (x18c0_isSpiderSurface) + f27 = viewSurfaceForces * 0.1f; + else + f27 = x18a8_spiderDistBetweenPoints.normalized() * 0.1f * (f26 >= 0.f ? 1.f : -1.f); + } + + zeus::CVector3f ballPos = GetBallToWorld().origin + f27; + float distance = 0.f; + if (!(!r31 && x18bd_ && x188c_spiderPullMovement == 1.f && !x18bf_)) + { + if (FindClosestSpiderBallWaypoint(mgr, ballPos, x1890_spiderTrackPoint, x189c_spiderInterpDistBetweenPoints, + x18a8_spiderDistBetweenPoints, distance, x1880_playerToSpiderNormal, + x18c0_isSpiderSurface, x18c4_spiderSurfaceTransform)) + { + x18bc_ = true; + x18bf_ = false; + } + } + else + { + x1880_playerToSpiderNormal = x1890_spiderTrackPoint - ballPos; + distance = x1880_playerToSpiderNormal.magnitude(); + x1880_playerToSpiderNormal = x1880_playerToSpiderNormal * (-1.f / distance); + x18bc_ = true; + } + + if (x18bc_) + { + if (distance < kSpiderBallCollisionRadius) + x18bd_ = true; + if (x18bd_) + { + if (r31) + { + if (!x18c0_isSpiderSurface) + { + x18b4_ = 0.4f; + x18b8_ = 0.2f; + float f2 = viewSurfaceForces.dot(x189c_spiderInterpDistBetweenPoints.normalized()); + if (r30 && x1920_) + { + f2 = x1918_; + } + else + { + x1918_ = f2; + x1920_ = false; + } + float f25; + if (std::fabs(f2) > 0.1f) + { + f25 = std::copysign(zeus::clamp(-1.f, forceMag, 1.f), f2); + } + else + { + f25 = 0.f; + ResetSpiderBallForces(); + } + if (distance > 1.05f) + f25 *= (1.05f - (distance - 1.05f)) / 1.05f; + x0_player.ApplyForceWR(x18a8_spiderDistBetweenPoints.normalized() * 90000.f * f25, + zeus::CAxisAngle::sIdentity); + } + else + { + x18b4_ = 0.3f; + x18b8_ = 0.2f; + float f31 = x18c4_spiderSurfaceTransform.basis[0].dot(viewSurfaceForces); + float f30 = x18c4_spiderSurfaceTransform.basis[2].dot(viewSurfaceForces); + zeus::CVector3f forceVec = (f31 * x18c4_spiderSurfaceTransform.basis[0] + + f30 * x18c4_spiderSurfaceTransform.basis[2]) * 45000.f; + x0_player.ApplyForceWR(forceVec, zeus::CAxisAngle::sIdentity); + if (forceVec.magSquared() > 0.f) + { + float angle = std::atan2(45000.f * f31, 45000.f * f30); + if (angle - x18f4_ > M_PIF / 2.f) + angle = angle - M_PIF; + else if (x18f4_ - angle > M_PIF / 2.f) + angle = angle + M_PIF; + x18f8_ = angle; + } + x18f4_ += std::copysign(std::min(std::fabs(x18f8_ - x18f4_), 0.2f), x18f8_ - x18f4_); + x189c_spiderInterpDistBetweenPoints = + x18c4_spiderSurfaceTransform.rotate(zeus::CTransform::RotateY(x18f4_).basis[2]); + } + } + x0_player.ApplyForceWR({0.f, 0.f, + g_tweakBall->GetBallGravity() * x0_player.GetMass() * 8.f * (1.f - x188c_spiderPullMovement)}, + zeus::CAxisAngle::sIdentity); + } + else + { + x18b4_ = 0.2f; + x18b8_ = 0.2f; + } + x0_player.SetMomentumWR(4.f * x0_player.GetMass() * g_tweakBall->GetBallGravity() * x1880_playerToSpiderNormal); + } } -void CMorphBall::CheckForSwitchToSpiderBallSwinging(CStateManager&) +zeus::CVector2f CMorphBall::CalculateSpiderBallAttractionSurfaceForces(const CFinalInput& input) const { + if (!IsMovementAllowed()) + return zeus::CVector2f(); + return {ControlMapper::GetAnalogInput(ControlMapper::ECommands::TurnRight, input) - + ControlMapper::GetAnalogInput(ControlMapper::ECommands::TurnLeft, input), + ControlMapper::GetAnalogInput(ControlMapper::ECommands::Forward, input) - + ControlMapper::GetAnalogInput(ControlMapper::ECommands::Backward, input)}; } -void CMorphBall::FindClosestSpiderBallWaypoint(CStateManager&, const zeus::CVector3f&, zeus::CVector3f&, - zeus::CVector3f&, zeus::CVector3f&, float&, zeus::CVector3f&, bool&, - zeus::CTransform&) const +bool CMorphBall::CheckForSwitchToSpiderBallSwinging(CStateManager& mgr) const { + if (!x18bd_) + return false; + if (x188c_spiderPullMovement == 1.f) + { + if (x18be_spiderBallSwinging) + { + zeus::CTransform ballToWorld = GetBallToWorld(); + zeus::CVector3f closestPoint, interpDeltaBetweenPoints, deltaBetweenPoints, normal; + float distance = 0.f; + bool isSurface; + zeus::CTransform surfaceTransform; + return !(FindClosestSpiderBallWaypoint(mgr, ballToWorld.origin, closestPoint, interpDeltaBetweenPoints, + deltaBetweenPoints, distance, normal, isSurface, surfaceTransform) + && distance < 2.1f); + } + return false; + } + + if (x18be_spiderBallSwinging) + return true; + + return std::fabs(x1880_playerToSpiderNormal.z) > 0.9f; } -void CMorphBall::SetSpiderBallSwingingState(bool) +bool CMorphBall::FindClosestSpiderBallWaypoint(CStateManager& mgr, const zeus::CVector3f& ballCenter, + zeus::CVector3f& closestPoint, + zeus::CVector3f& interpDeltaBetweenPoints, + zeus::CVector3f& deltaBetweenPoints, float& distance, + zeus::CVector3f& normal, bool& isSurface, + zeus::CTransform& surfaceTransform) const { + bool ret = false; + zeus::CAABox aabb(ballCenter - 2.1f, ballCenter + 2.1f); + rstl::reserved_vector nearList; + mgr.BuildNearList(nearList, aabb, CMaterialFilter::skPassEverything, nullptr); + float minDist = 2.1f; + for (TUniqueId id : nearList) + { + if (TCastToConstPtr surface = mgr.GetObjectById(id)) + { + zeus::CUnitVector3f surfaceNorm(surface->GetTransform().basis[1]); + zeus::CPlane plane(surfaceNorm, surface->GetTranslation().dot(surfaceNorm)); + zeus::CVector3f intersectPoint; + if (plane.rayPlaneIntersection(ballCenter + surfaceNorm * 2.1f, + ballCenter - surfaceNorm * 2.1f, intersectPoint)) + { + zeus::CVector3f halfScale = surface->GetScale() * 0.5f; + zeus::CVector3f localPoint = zeus::CTransform::Scale(1.f / halfScale) * + surface->GetTransform().inverse() * intersectPoint; + localPoint.x = zeus::clamp(-1.f, localPoint.x, 1.f); + localPoint.z = zeus::clamp(-1.f, localPoint.z, 1.f); + zeus::CVector3f worldPoint = surface->GetTransform() * zeus::CTransform::Scale(halfScale) * localPoint; + zeus::CVector3f finalDelta = worldPoint - ballCenter; + float finalMag = finalDelta.magnitude(); + if (finalMag < minDist) + { + minDist = finalMag; + closestPoint = worldPoint; + distance = finalMag; + normal = finalDelta * (-1.f / finalMag); + isSurface = true; + surfaceTransform = surface->GetTransform(); + ret = true; + } + } + } + } + + for (TUniqueId id : nearList) + { + if (TCastToConstPtr wp = mgr.GetObjectById(id)) + { + const CScriptSpiderBallWaypoint* closestWp = nullptr; + zeus::CVector3f worldPoint; + zeus::CVector3f useDeltaBetweenPoints = deltaBetweenPoints; + zeus::CVector3f useInterpDeltaBetweenPoints = interpDeltaBetweenPoints; + wp->GetClosestPointAlongWaypoints(mgr, ballCenter, 2.1f, closestWp, worldPoint, useDeltaBetweenPoints, + 0.8f, useInterpDeltaBetweenPoints); + if (closestWp) + { + zeus::CVector3f ballToPoint = worldPoint - ballCenter; + float ballToPointMag = ballToPoint.magnitude(); + if (ballToPointMag < minDist) + { + minDist = ballToPointMag; + closestPoint = worldPoint; + interpDeltaBetweenPoints = useInterpDeltaBetweenPoints; + deltaBetweenPoints = useDeltaBetweenPoints; + distance = ballToPointMag; + normal = ballToPoint * (-1.f / ballToPointMag); + isSurface = false; + ret = true; + } + } + } + } + + return ret; } -void CMorphBall::GetSpiderBallControllerMovement(const CFinalInput&, bool, bool) +void CMorphBall::SetSpiderBallSwingingState(bool active) { + if (x18be_spiderBallSwinging != active) + { + ResetSpiderBallSwingControllerMovementTimer(); + x18bf_ = true; + } + x18be_spiderBallSwinging = active; +} +float CMorphBall::GetSpiderBallControllerMovement(const CFinalInput& input) const +{ + if (!IsMovementAllowed()) + return 0.f; + + float forward = ControlMapper::GetAnalogInput(ControlMapper::ECommands::Forward, input) - + ControlMapper::GetAnalogInput(ControlMapper::ECommands::Backward, input); + float turn = ControlMapper::GetAnalogInput(ControlMapper::ECommands::TurnRight, input) - + ControlMapper::GetAnalogInput(ControlMapper::ECommands::TurnLeft, input); + float angle = zeus::radToDeg(std::atan2(forward, turn)); + float hyp = std::sqrt(forward * forward + turn * turn); + if (angle > -35.f && angle < 125.f) + return hyp; + if (angle < -55.f || angle > 145.f) + return -hyp; + return 0.f; } void CMorphBall::ResetSpiderBallSwingControllerMovementTimer() { - + x1904_swingControlDir = 0.f; + x1908_swingControlTime = 0.f; } -void CMorphBall::UpdateSpiderBallSwingControllerMovementTimer(float, float) +void CMorphBall::UpdateSpiderBallSwingControllerMovementTimer(float movement, float dt) { - + if (std::fabs(movement) < 0.05f) + { + ResetSpiderBallSwingControllerMovementTimer(); + } + else + { + if ((movement >= 0.f ? 1.f : -1.f) != x1904_swingControlDir) + { + ResetSpiderBallSwingControllerMovementTimer(); + x1904_swingControlDir = (movement >= 0.f ? 1.f : -1.f); + } + else + { + x1908_swingControlTime += dt; + } + } } float CMorphBall::GetSpiderBallSwingControllerMovementScalar() const { - return 0.f; + if (x1908_swingControlTime < 1.2f) + return 1.f; + return std::max(0.f, (2.4f - x1908_swingControlTime) / 1.2f); } void CMorphBall::CreateSpiderBallParticles(const zeus::CVector3f&, const zeus::CVector3f&) @@ -470,15 +788,16 @@ void CMorphBall::ComputeMarioMovement(const CFinalInput& input, CStateManager& m if (!IsMovementAllowed()) return; - x188c_ = (ControlMapper::GetAnalogInput(ControlMapper::ECommands::SpiderBall, input) >= 0.5f / 100.f) ? 1.f : 0.f; + x188c_spiderPullMovement = + (ControlMapper::GetAnalogInput(ControlMapper::ECommands::SpiderBall, input) >= 0.5f / 100.f) ? 1.f : 0.f; if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::EItemType::SpiderBall) && - x188c_ != 0.f && x191c_damageTimer == 0.f) + x188c_spiderPullMovement != 0.f && x191c_damageTimer == 0.f) { if (x187c_spiderBallState != ESpiderBallState::Active) { x18bd_ = false; x187c_spiderBallState = ESpiderBallState::Active; - x18a8_initialSpiderBallUp = x189c_spiderBallDir = x0_player.GetTransform().basis[2]; + x18a8_spiderDistBetweenPoints = x189c_spiderInterpDistBetweenPoints = x0_player.GetTransform().basis[2]; } UpdateSpiderBall(input, mgr, dt); @@ -540,7 +859,8 @@ void CMorphBall::ComputeMarioMovement(const CFinalInput& input, CStateManager& m zeus::CVector3f controlForce = controlXf.rotate({0.f, f28f, 0.f}) + controlXf.rotate({f27f, 0.f, 0.f}); x1c_ = controlForce; if (x1de4_24 && !GetIsInHalfPipeMode()) - controlForce = x1924_surfaceToWorld.rotate({x1924_surfaceToWorld.transposeRotate(controlForce).x, 0.f, 0.f}); + controlForce = + x1924_surfaceToWorld.rotate({x1924_surfaceToWorld.transposeRotate(controlForce).x, 0.f, 0.f}); if (GetIsInHalfPipeMode() && controlForce.magnitude() > FLT_EPSILON) { @@ -642,8 +962,8 @@ void CMorphBall::UpdateBallDynamics(CStateManager& mgr, float dt) x191c_damageTimer = std::max(0.f, x191c_damageTimer); if (x187c_spiderBallState == ESpiderBallState::Active) { - x1924_surfaceToWorld = CalculateSurfaceToWorld(x1880_spiderTrackNormal, - x1890_spiderTrackPoint, x189c_spiderBallDir); + x1924_surfaceToWorld = CalculateSurfaceToWorld(x1880_playerToSpiderNormal, + x1890_spiderTrackPoint, x189c_spiderInterpDistBetweenPoints); x2c_tireLeanAngle = 0.f; if (!x28_tireMode) SwitchToTire(); diff --git a/Runtime/World/CMorphBall.hpp b/Runtime/World/CMorphBall.hpp index 87e236d22..bd6d9166e 100644 --- a/Runtime/World/CMorphBall.hpp +++ b/Runtime/World/CMorphBall.hpp @@ -64,25 +64,25 @@ private: CCollisionInfoList x74_collisionInfos; u32 xc78_ = 0; ESpiderBallState x187c_spiderBallState = ESpiderBallState::Inactive; - zeus::CVector3f x1880_spiderTrackNormal; - float x188c_ = 1.f; + zeus::CVector3f x1880_playerToSpiderNormal; + float x188c_spiderPullMovement = 1.f; zeus::CVector3f x1890_spiderTrackPoint; - zeus::CVector3f x189c_spiderBallDir; - zeus::CVector3f x18a8_initialSpiderBallUp; + zeus::CVector3f x189c_spiderInterpDistBetweenPoints; + zeus::CVector3f x18a8_spiderDistBetweenPoints; float x18b4_ = 0.f; float x18b8_ = 0.f; bool x18bc_ = false; bool x18bd_ = false; - bool x18be_ = false; + bool x18be_spiderBallSwinging = false; bool x18bf_ = true; - bool x18c0_ = false; - zeus::CTransform x18c4_; + bool x18c0_isSpiderSurface = false; + zeus::CTransform x18c4_spiderSurfaceTransform; float x18f4_ = 0.f; float x18f8_ = 0.f; - float x18fc_ = 0.f; - float x1900_ = 0.f; - float x1904_ = 0.f; - float x1908_ = 0.f; + float x18fc_refPullVel = 0.f; + float x1900_playerToSpiderTrackDist = 0.f; + float x1904_swingControlDir = 0.f; + float x1908_swingControlTime = 0.f; zeus::CVector2f x190c_; float x1914_ = 0.f; float x1918_ = 0.f; @@ -171,7 +171,8 @@ private: static std::unique_ptr GetMorphBallModel(const char* name, float radius); void SelectMorphBallSounds(const CMaterialList& mat); void UpdateMorphBallSounds(float dt); - static zeus::CVector3f TransformSpiderBallForcesToView(const zeus::CVector2f& forces, CStateManager& mgr); + static zeus::CVector3f TransformSpiderBallForcesXY(const zeus::CVector2f& forces, CStateManager& mgr); + static zeus::CVector3f TransformSpiderBallForcesXZ(const zeus::CVector2f& forces, CStateManager& mgr); void ResetSpiderBallForces(); public: CMorphBall(CPlayer& player, float radius); @@ -188,19 +189,21 @@ public: float BallTurnInput(const CFinalInput& input) const; void ComputeBallMovement(const CFinalInput& input, CStateManager& mgr, float dt); bool IsMovementAllowed() const; - void UpdateSpiderBall(const CFinalInput&, CStateManager&, float); - void ApplySpiderBallSwingingForces(const CFinalInput&, CStateManager&, float); - void ApplySpiderBallRollForces(const CFinalInput&, CStateManager&, float); - void CalculateSpiderBallAttractionSurfaceForces(const CFinalInput&, CStateManager&, - const zeus::CTransform&); - void CheckForSwitchToSpiderBallSwinging(CStateManager&); - void FindClosestSpiderBallWaypoint(CStateManager&, const zeus::CVector3f&, zeus::CVector3f&, - zeus::CVector3f&, zeus::CVector3f&, float&, zeus::CVector3f&, bool&, - zeus::CTransform&) const; - void SetSpiderBallSwingingState(bool); - void GetSpiderBallControllerMovement(const CFinalInput&, bool, bool); + void UpdateSpiderBall(const CFinalInput& input, CStateManager& mgr, float dt); + void ApplySpiderBallSwingingForces(const CFinalInput& input, CStateManager& mgr, float dt); + void ApplySpiderBallRollForces(const CFinalInput& input, CStateManager& mgr, float dt); + zeus::CVector2f CalculateSpiderBallAttractionSurfaceForces(const CFinalInput& input) const; + bool CheckForSwitchToSpiderBallSwinging(CStateManager& mgr) const; + bool FindClosestSpiderBallWaypoint(CStateManager& mgr, const zeus::CVector3f& ballCenter, + zeus::CVector3f& closestPoint, + zeus::CVector3f& interpDeltaBetweenPoints, + zeus::CVector3f& deltaBetweenPoints, float& distance, + zeus::CVector3f& normal, bool& isSurface, + zeus::CTransform& surfaceTransform) const; + void SetSpiderBallSwingingState(bool active); + float GetSpiderBallControllerMovement(const CFinalInput& input) const; void ResetSpiderBallSwingControllerMovementTimer(); - void UpdateSpiderBallSwingControllerMovementTimer(float, float); + void UpdateSpiderBallSwingControllerMovementTimer(float movement, float dt); float GetSpiderBallSwingControllerMovementScalar() const; void CreateSpiderBallParticles(const zeus::CVector3f&, const zeus::CVector3f&); void ComputeMarioMovement(const CFinalInput& input, CStateManager& mgr, float dt); diff --git a/Runtime/World/CScriptSpiderBallAttractionSurface.cpp b/Runtime/World/CScriptSpiderBallAttractionSurface.cpp index e69de29bb..40fd3eb22 100644 --- a/Runtime/World/CScriptSpiderBallAttractionSurface.cpp +++ b/Runtime/World/CScriptSpiderBallAttractionSurface.cpp @@ -0,0 +1,44 @@ +#include "CScriptSpiderBallAttractionSurface.hpp" +#include "CActorParameters.hpp" +#include "TCastTo.hpp" + +namespace urde +{ + +CScriptSpiderBallAttractionSurface::CScriptSpiderBallAttractionSurface( + TUniqueId uid, const std::string& name, const CEntityInfo& info, + const zeus::CTransform& xf, const zeus::CVector3f& scale, bool active) +: CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), {EMaterialTypes::Unknown}, + CActorParameters::None(), kInvalidUniqueId), xe8_scale(scale), + xf4_aabb(zeus::CAABox(scale * -0.5f, scale * 0.5f).getTransformedAABox(xf.getRotation())) +{ +} + +void CScriptSpiderBallAttractionSurface::Accept(IVisitor& visitor) +{ + visitor.Visit(this); +} + +void CScriptSpiderBallAttractionSurface::Think(float dt, CStateManager& mgr) +{ + // Empty +} + +void CScriptSpiderBallAttractionSurface::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) +{ + CActor::AcceptScriptMsg(msg, sender, mgr); +} + +rstl::optional_object CScriptSpiderBallAttractionSurface::GetTouchBounds() const +{ + if (GetActive()) + return {zeus::CAABox(xf4_aabb.min + GetTranslation(), xf4_aabb.max + GetTranslation())}; + return {}; +} + +void CScriptSpiderBallAttractionSurface::Touch(CActor& actor, CStateManager& mgr) +{ + // Empty +} + +} diff --git a/Runtime/World/CScriptSpiderBallAttractionSurface.hpp b/Runtime/World/CScriptSpiderBallAttractionSurface.hpp index e69de29bb..177383af1 100644 --- a/Runtime/World/CScriptSpiderBallAttractionSurface.hpp +++ b/Runtime/World/CScriptSpiderBallAttractionSurface.hpp @@ -0,0 +1,26 @@ +#ifndef __URDE_CSCRIPTSPIDERBALLATTRACTIONSURFACE_HPP__ +#define __URDE_CSCRIPTSPIDERBALLATTRACTIONSURFACE_HPP__ + +#include "CActor.hpp" + +namespace urde +{ + +class CScriptSpiderBallAttractionSurface : public CActor +{ + zeus::CVector3f xe8_scale; + zeus::CAABox xf4_aabb; +public: + CScriptSpiderBallAttractionSurface(TUniqueId uid, const std::string& name, const CEntityInfo& info, + const zeus::CTransform& xf, const zeus::CVector3f& scale, bool active); + void Accept(IVisitor& visitor); + void Think(float dt, CStateManager& mgr); + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr); + rstl::optional_object GetTouchBounds() const; + void Touch(CActor& actor, CStateManager& mgr); + const zeus::CVector3f& GetScale() const { return xe8_scale; } +}; + +} + +#endif // __URDE_CSCRIPTSPIDERBALLATTRACTIONSURFACE_HPP__ diff --git a/Runtime/World/CScriptSpiderBallWaypoint.cpp b/Runtime/World/CScriptSpiderBallWaypoint.cpp index 0b80d17c5..31e2bb83b 100644 --- a/Runtime/World/CScriptSpiderBallWaypoint.cpp +++ b/Runtime/World/CScriptSpiderBallWaypoint.cpp @@ -57,11 +57,11 @@ void CScriptSpiderBallWaypoint::BuildWaypointListAndBounds(CStateManager& mgr) else { CScriptSpiderBallWaypoint* curWaypoint = this; - TUniqueId uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::Yes); + TUniqueId uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::SkipCheck); while (uid != kInvalidUniqueId) { curWaypoint = static_cast(mgr.ObjectById(uid)); - uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::Yes); + uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::SkipCheck); } curWaypoint->AccumulateBounds(x34_transform.origin); @@ -73,7 +73,23 @@ void CScriptSpiderBallWaypoint::AddPreviousWaypoint(TUniqueId uid) xec_waypoints.push_back(uid); } -TUniqueId CScriptSpiderBallWaypoint::NextWaypoint(const CStateManager& mgr, ECheckActiveWaypoint checkActive) +TUniqueId CScriptSpiderBallWaypoint::PreviousWaypoint(const CStateManager& mgr, ECheckActiveWaypoint checkActive) const +{ + for (TUniqueId id : xec_waypoints) + { + if (const CEntity* ent = mgr.GetObjectById(id)) + { + if (checkActive == ECheckActiveWaypoint::SkipCheck) + return id; + else if (ent->GetActive()) + return id; + } + } + + return kInvalidUniqueId; +} + +TUniqueId CScriptSpiderBallWaypoint::NextWaypoint(const CStateManager& mgr, ECheckActiveWaypoint checkActive) const { for (const SConnection& conn : x20_conns) { @@ -82,13 +98,131 @@ TUniqueId CScriptSpiderBallWaypoint::NextWaypoint(const CStateManager& mgr, EChe TUniqueId uid = mgr.GetIdForScript(conn.x8_objId); if (uid != kInvalidUniqueId) { - const CEntity* ent = mgr.GetObjectById(uid); - if (ent && checkActive == ECheckActiveWaypoint::Yes && ent->GetActive()) - return ent->GetUniqueId(); + if (const CEntity* ent = mgr.GetObjectById(uid)) + { + if (checkActive == ECheckActiveWaypoint::SkipCheck) + return ent->GetUniqueId(); + else if (ent->GetActive()) + return ent->GetUniqueId(); + } } } } return kInvalidUniqueId; } + +void CScriptSpiderBallWaypoint::GetClosestPointAlongWaypoints(CStateManager& mgr, const zeus::CVector3f& ballPos, + float maxPointToBallDist, const CScriptSpiderBallWaypoint*& closestWaypoint, zeus::CVector3f& closestPoint, + zeus::CVector3f& deltaBetweenPoints, float deltaBetweenInterpDist, zeus::CVector3f& interpDeltaBetweenPoints) const +{ + const CScriptSpiderBallWaypoint* wp = this; + while (wp->PreviousWaypoint(mgr, ECheckActiveWaypoint::SkipCheck) != kInvalidUniqueId) + wp = static_cast( + mgr.GetObjectById(wp->PreviousWaypoint(mgr, ECheckActiveWaypoint::SkipCheck))); + float minPointToBallDistSq = maxPointToBallDist * maxPointToBallDist; + float deltaBetweenInterpDistSq = deltaBetweenInterpDist * deltaBetweenInterpDist; + zeus::CVector3f lastPoint = wp->GetTranslation(); + zeus::CVector3f lastDelta; + bool computeDelta = wp->GetActive(); + while (true) + { + if (wp->NextWaypoint(mgr, ECheckActiveWaypoint::Check) != kInvalidUniqueId) + { + if (computeDelta) + { + const CScriptSpiderBallWaypoint* prevWp = wp; + wp = static_cast( + mgr.GetObjectById(wp->NextWaypoint(mgr, ECheckActiveWaypoint::Check))); + zeus::CVector3f thisDelta = wp->GetTranslation() - lastPoint; + zeus::CVector3f lastPointToBall = ballPos - lastPoint; + if (prevWp->PreviousWaypoint(mgr, ECheckActiveWaypoint::Check) == kInvalidUniqueId) + lastDelta = thisDelta; + float pointToBallDistSq = lastPointToBall.magSquared(); + if (pointToBallDistSq < minPointToBallDistSq) + { + minPointToBallDistSq = pointToBallDistSq; + closestPoint = lastPoint; + deltaBetweenPoints = thisDelta; + interpDeltaBetweenPoints = (thisDelta.normalized() + lastDelta.normalized()) * 0.5f; + closestWaypoint = wp; + } + float projectedT = lastPointToBall.dot(thisDelta); + if (projectedT >= 0.f) + { + float normT = projectedT / thisDelta.magSquared(); + if (normT < 1.f) + { + zeus::CVector3f projectedPoint = zeus::CVector3f::lerp(lastPoint, wp->GetTranslation(), normT); + float projToBallDistSq = (ballPos - projectedPoint).magSquared(); + if (projToBallDistSq < minPointToBallDistSq) + { + minPointToBallDistSq = projToBallDistSq; + closestPoint = projectedPoint; + deltaBetweenPoints = thisDelta; + interpDeltaBetweenPoints = deltaBetweenPoints; + closestWaypoint = wp; + float lastToProjDist = (lastPoint - projectedPoint).magnitude(); + if (lastToProjDist < deltaBetweenInterpDistSq) + { + interpDeltaBetweenPoints = + zeus::CVector3f::lerp(0.5f * (thisDelta.normalized() + lastDelta.normalized()), + thisDelta.normalized(), lastToProjDist / deltaBetweenInterpDist); + } + else if (wp->NextWaypoint(mgr, ECheckActiveWaypoint::Check) != kInvalidUniqueId) + { + lastToProjDist = (projectedPoint - wp->GetTranslation()).magnitude(); + if (lastToProjDist < deltaBetweenInterpDist) + { + float t = lastToProjDist / deltaBetweenInterpDist; + interpDeltaBetweenPoints = + zeus::CVector3f::lerp(((static_cast( + mgr.GetObjectById(wp->NextWaypoint(mgr, ECheckActiveWaypoint::Check)))-> + GetTranslation() - wp->GetTranslation()).normalized() + + thisDelta.normalized()) * 0.5f, thisDelta.normalized(), t); + } + } + } + } + } + lastDelta = thisDelta; + lastPoint = wp->GetTranslation(); + computeDelta = true; + } + else + { + wp = static_cast( + mgr.GetObjectById(wp->NextWaypoint(mgr, ECheckActiveWaypoint::Check))); + lastPoint = wp->GetTranslation(); + computeDelta = true; + } + } + else + { + if (wp->NextWaypoint(mgr, ECheckActiveWaypoint::SkipCheck) != kInvalidUniqueId) + { + wp = static_cast( + mgr.GetObjectById(wp->NextWaypoint(mgr, ECheckActiveWaypoint::SkipCheck))); + computeDelta = false; + } + else + { + break; + } + } + } + + if ((ballPos - lastPoint).magSquared() < minPointToBallDistSq) + { + closestPoint = lastPoint; + if (wp->PreviousWaypoint(mgr, ECheckActiveWaypoint::Check) != kInvalidUniqueId) + { + wp = static_cast( + mgr.GetObjectById(wp->PreviousWaypoint(mgr, ECheckActiveWaypoint::SkipCheck))); + deltaBetweenPoints = lastPoint - wp->GetTranslation(); + interpDeltaBetweenPoints = deltaBetweenPoints; + } + closestWaypoint = wp; + } +} } diff --git a/Runtime/World/CScriptSpiderBallWaypoint.hpp b/Runtime/World/CScriptSpiderBallWaypoint.hpp index de49a15bf..98db0e0cb 100644 --- a/Runtime/World/CScriptSpiderBallWaypoint.hpp +++ b/Runtime/World/CScriptSpiderBallWaypoint.hpp @@ -9,8 +9,8 @@ class CScriptSpiderBallWaypoint : public CActor { enum class ECheckActiveWaypoint { - No, - Yes + Check, + SkipCheck }; u32 xe8_; std::vector xec_waypoints; @@ -22,10 +22,15 @@ public: void Render(const CStateManager& mgr) const { CActor::Render(mgr); } void AddToRenderer(const zeus::CFrustum&, const CStateManager&) {} std::experimental::optional GetTouchBounds() const { return xfc_aabox; } - void AccumulateBounds(const zeus::CVector3f&); - void BuildWaypointListAndBounds(CStateManager&); - void AddPreviousWaypoint(TUniqueId); - TUniqueId NextWaypoint(const CStateManager&, ECheckActiveWaypoint); + void AccumulateBounds(const zeus::CVector3f& v); + void BuildWaypointListAndBounds(CStateManager& mgr); + void AddPreviousWaypoint(TUniqueId uid); + TUniqueId PreviousWaypoint(const CStateManager& mgr, ECheckActiveWaypoint checkActive) const; + TUniqueId NextWaypoint(const CStateManager& mgr, ECheckActiveWaypoint checkActive) const; + void GetClosestPointAlongWaypoints(CStateManager& mgr, const zeus::CVector3f& ballPos, + float maxPointToBallDist, const CScriptSpiderBallWaypoint*& closestWaypoint, + zeus::CVector3f& closestPoint, zeus::CVector3f& deltaBetweenPoints, + float deltaBetweenInterpDist, zeus::CVector3f& interpDeltaBetweenPoints) const; }; } diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index df938fbd7..ee4e68e16 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -61,6 +61,7 @@ #include "CScriptWater.hpp" #include "CScriptWaypoint.hpp" #include "CScriptWorldTeleporter.hpp" +#include "CScriptSpiderBallAttractionSurface.hpp" #include "CSimplePool.hpp" #include "CStateManager.hpp" #include "CVisorParameters.hpp" @@ -1450,7 +1451,12 @@ CEntity* ScriptLoader::LoadDebugCameraWaypoint(CStateManager& mgr, CInputStream& CEntity* ScriptLoader::LoadSpiderBallAttractionSurface(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (!EnsurePropertyCount(propCount, 5, "SpiderBallAttractionSurface")) + return nullptr; + SScaledActorHead aHead = LoadScaledActorHead(in, mgr); + bool active = in.readBool(); + return new CScriptSpiderBallAttractionSurface(mgr.AllocateUniqueId(), aHead.x0_name, info, aHead.x10_transform, + aHead.x40_scale, active); } CEntity* ScriptLoader::LoadPuddleToadGamma(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) diff --git a/Runtime/rstl.hpp b/Runtime/rstl.hpp index 35cf5fbe6..296e9a6b0 100644 --- a/Runtime/rstl.hpp +++ b/Runtime/rstl.hpp @@ -183,7 +183,7 @@ public: ~reserved_vector() { for (size_t i=0 ; i()(std::addressof(base::_value(i))); + base::_value(i).~T(); } void push_back(const T& d) @@ -224,7 +224,7 @@ public: Log.report(logvisor::Fatal, "pop_back() called on empty rstl::reserved_vector."); #endif --base::x0_size; - std::default_delete()(std::addressof(base::_value(base::x0_size))); + base::_value(base::x0_size).~T(); } iterator insert(const_iterator pos, const T& value) @@ -288,7 +288,7 @@ public: else if (size < base::x0_size) { for (size_t i = size; i < base::x0_size; ++i) - std::default_delete()(std::addressof(base::_value(i))); + base::_value(i).~T(); base::x0_size = size; } } @@ -308,7 +308,7 @@ public: else if (size < base::x0_size) { for (size_t i = size; i < base::x0_size; ++i) - std::default_delete()(std::addressof(base::_value(i))); + base::_value(i).~T(); base::x0_size = size; } } @@ -322,14 +322,14 @@ public: for (auto it = base::_const_cast_iterator(pos) + 1; it != base::end(); ++it) *(it - 1) = std::forward(*it); --base::x0_size; - std::default_delete()(std::addressof(base::_value(base::x0_size))); + base::_value(base::x0_size).~T(); return base::_const_cast_iterator(pos); } void clear() { for (auto it = base::begin(); it != base::end(); ++it) - std::default_delete()(std::addressof(*it)); + it->~T(); base::x0_size = 0; } }; @@ -348,7 +348,7 @@ class prereserved_vector : public _reserved_vector_base void _deinit() { for (auto& i : base::x4_data) - std::default_delete()(reinterpret_cast(std::addressof(i))); + reinterpret_cast(std::addressof(i))->~T(); } public: using base = _reserved_vector_base; diff --git a/hecl b/hecl index 4dbfba0cd..53a34e2bb 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit 4dbfba0cd9d2e13b61da4e99404c9f48a3599afe +Subproject commit 53a34e2bba8ff2dcf2aafdbd0e64e18b5fa50ffd diff --git a/specter b/specter index 81afe9b52..6a89d8c22 160000 --- a/specter +++ b/specter @@ -1 +1 @@ -Subproject commit 81afe9b52644b13ecac849082d51098a2cfdea20 +Subproject commit 6a89d8c22b9dfc83b93baee1344096fca7008af9