More CMorphBall implementations

This commit is contained in:
Jack Andersen 2017-09-17 17:02:48 -10:00
parent 2c4967ca4d
commit 41032d0a7c
11 changed files with 610 additions and 71 deletions

View File

@ -45,6 +45,7 @@ set(WORLD_SOURCES
CScriptActorKeyframe.hpp CScriptActorKeyframe.cpp CScriptActorKeyframe.hpp CScriptActorKeyframe.cpp
CScriptWater.hpp CScriptWater.cpp CScriptWater.hpp CScriptWater.cpp
CScriptGrapplePoint.hpp CScriptGrapplePoint.cpp CScriptGrapplePoint.hpp CScriptGrapplePoint.cpp
CScriptSpiderBallAttractionSurface.hpp CScriptSpiderBallAttractionSurface.cpp
CScriptPickupGenerator.hpp CScriptPickupGenerator.cpp CScriptPickupGenerator.hpp CScriptPickupGenerator.cpp
CScriptPointOfInterest.hpp CScriptPointOfInterest.cpp CScriptPointOfInterest.hpp CScriptPointOfInterest.cpp
CScriptAreaAttributes.hpp CScriptAreaAttributes.cpp CScriptAreaAttributes.hpp CScriptAreaAttributes.cpp

View File

@ -10,6 +10,8 @@
#include "TCastTo.hpp" #include "TCastTo.hpp"
#include "Camera/CGameCamera.hpp" #include "Camera/CGameCamera.hpp"
#include "Collision/CGameCollision.hpp" #include "Collision/CGameCollision.hpp"
#include "CScriptSpiderBallAttractionSurface.hpp"
#include "CScriptSpiderBallWaypoint.hpp"
namespace urde namespace urde
{ {
@ -386,68 +388,384 @@ bool CMorphBall::IsMovementAllowed() const
return x1e00_ <= 0.f; 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 * return mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTransform().basis *
zeus::CVector3f(forces.x, forces.y, 0.f); 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&, void CMorphBall::ApplySpiderBallRollForces(const CFinalInput& input, CStateManager& mgr, float dt)
const zeus::CTransform&)
{ {
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&, bool CMorphBall::CheckForSwitchToSpiderBallSwinging(CStateManager& mgr) const
zeus::CVector3f&, zeus::CVector3f&, float&, zeus::CVector3f&, bool&,
zeus::CTransform&) 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<TUniqueId, 1024> nearList;
mgr.BuildNearList(nearList, aabb, CMaterialFilter::skPassEverything, nullptr);
float minDist = 2.1f;
for (TUniqueId id : nearList)
{
if (TCastToConstPtr<CScriptSpiderBallAttractionSurface> 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<CScriptSpiderBallWaypoint> 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() 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 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&) void CMorphBall::CreateSpiderBallParticles(const zeus::CVector3f&, const zeus::CVector3f&)
@ -470,15 +788,16 @@ void CMorphBall::ComputeMarioMovement(const CFinalInput& input, CStateManager& m
if (!IsMovementAllowed()) if (!IsMovementAllowed())
return; 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) && 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) if (x187c_spiderBallState != ESpiderBallState::Active)
{ {
x18bd_ = false; x18bd_ = false;
x187c_spiderBallState = ESpiderBallState::Active; 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); 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}); zeus::CVector3f controlForce = controlXf.rotate({0.f, f28f, 0.f}) + controlXf.rotate({f27f, 0.f, 0.f});
x1c_ = controlForce; x1c_ = controlForce;
if (x1de4_24 && !GetIsInHalfPipeMode()) 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) 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); x191c_damageTimer = std::max(0.f, x191c_damageTimer);
if (x187c_spiderBallState == ESpiderBallState::Active) if (x187c_spiderBallState == ESpiderBallState::Active)
{ {
x1924_surfaceToWorld = CalculateSurfaceToWorld(x1880_spiderTrackNormal, x1924_surfaceToWorld = CalculateSurfaceToWorld(x1880_playerToSpiderNormal,
x1890_spiderTrackPoint, x189c_spiderBallDir); x1890_spiderTrackPoint, x189c_spiderInterpDistBetweenPoints);
x2c_tireLeanAngle = 0.f; x2c_tireLeanAngle = 0.f;
if (!x28_tireMode) if (!x28_tireMode)
SwitchToTire(); SwitchToTire();

View File

@ -64,25 +64,25 @@ private:
CCollisionInfoList x74_collisionInfos; CCollisionInfoList x74_collisionInfos;
u32 xc78_ = 0; u32 xc78_ = 0;
ESpiderBallState x187c_spiderBallState = ESpiderBallState::Inactive; ESpiderBallState x187c_spiderBallState = ESpiderBallState::Inactive;
zeus::CVector3f x1880_spiderTrackNormal; zeus::CVector3f x1880_playerToSpiderNormal;
float x188c_ = 1.f; float x188c_spiderPullMovement = 1.f;
zeus::CVector3f x1890_spiderTrackPoint; zeus::CVector3f x1890_spiderTrackPoint;
zeus::CVector3f x189c_spiderBallDir; zeus::CVector3f x189c_spiderInterpDistBetweenPoints;
zeus::CVector3f x18a8_initialSpiderBallUp; zeus::CVector3f x18a8_spiderDistBetweenPoints;
float x18b4_ = 0.f; float x18b4_ = 0.f;
float x18b8_ = 0.f; float x18b8_ = 0.f;
bool x18bc_ = false; bool x18bc_ = false;
bool x18bd_ = false; bool x18bd_ = false;
bool x18be_ = false; bool x18be_spiderBallSwinging = false;
bool x18bf_ = true; bool x18bf_ = true;
bool x18c0_ = false; bool x18c0_isSpiderSurface = false;
zeus::CTransform x18c4_; zeus::CTransform x18c4_spiderSurfaceTransform;
float x18f4_ = 0.f; float x18f4_ = 0.f;
float x18f8_ = 0.f; float x18f8_ = 0.f;
float x18fc_ = 0.f; float x18fc_refPullVel = 0.f;
float x1900_ = 0.f; float x1900_playerToSpiderTrackDist = 0.f;
float x1904_ = 0.f; float x1904_swingControlDir = 0.f;
float x1908_ = 0.f; float x1908_swingControlTime = 0.f;
zeus::CVector2f x190c_; zeus::CVector2f x190c_;
float x1914_ = 0.f; float x1914_ = 0.f;
float x1918_ = 0.f; float x1918_ = 0.f;
@ -171,7 +171,8 @@ private:
static std::unique_ptr<CModelData> GetMorphBallModel(const char* name, float radius); static std::unique_ptr<CModelData> GetMorphBallModel(const char* name, float radius);
void SelectMorphBallSounds(const CMaterialList& mat); void SelectMorphBallSounds(const CMaterialList& mat);
void UpdateMorphBallSounds(float dt); 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(); void ResetSpiderBallForces();
public: public:
CMorphBall(CPlayer& player, float radius); CMorphBall(CPlayer& player, float radius);
@ -188,19 +189,21 @@ public:
float BallTurnInput(const CFinalInput& input) const; float BallTurnInput(const CFinalInput& input) const;
void ComputeBallMovement(const CFinalInput& input, CStateManager& mgr, float dt); void ComputeBallMovement(const CFinalInput& input, CStateManager& mgr, float dt);
bool IsMovementAllowed() const; bool IsMovementAllowed() const;
void UpdateSpiderBall(const CFinalInput&, CStateManager&, float); void UpdateSpiderBall(const CFinalInput& input, CStateManager& mgr, float dt);
void ApplySpiderBallSwingingForces(const CFinalInput&, CStateManager&, float); void ApplySpiderBallSwingingForces(const CFinalInput& input, CStateManager& mgr, float dt);
void ApplySpiderBallRollForces(const CFinalInput&, CStateManager&, float); void ApplySpiderBallRollForces(const CFinalInput& input, CStateManager& mgr, float dt);
void CalculateSpiderBallAttractionSurfaceForces(const CFinalInput&, CStateManager&, zeus::CVector2f CalculateSpiderBallAttractionSurfaceForces(const CFinalInput& input) const;
const zeus::CTransform&); bool CheckForSwitchToSpiderBallSwinging(CStateManager& mgr) const;
void CheckForSwitchToSpiderBallSwinging(CStateManager&); bool FindClosestSpiderBallWaypoint(CStateManager& mgr, const zeus::CVector3f& ballCenter,
void FindClosestSpiderBallWaypoint(CStateManager&, const zeus::CVector3f&, zeus::CVector3f&, zeus::CVector3f& closestPoint,
zeus::CVector3f&, zeus::CVector3f&, float&, zeus::CVector3f&, bool&, zeus::CVector3f& interpDeltaBetweenPoints,
zeus::CTransform&) const; zeus::CVector3f& deltaBetweenPoints, float& distance,
void SetSpiderBallSwingingState(bool); zeus::CVector3f& normal, bool& isSurface,
void GetSpiderBallControllerMovement(const CFinalInput&, bool, bool); zeus::CTransform& surfaceTransform) const;
void SetSpiderBallSwingingState(bool active);
float GetSpiderBallControllerMovement(const CFinalInput& input) const;
void ResetSpiderBallSwingControllerMovementTimer(); void ResetSpiderBallSwingControllerMovementTimer();
void UpdateSpiderBallSwingControllerMovementTimer(float, float); void UpdateSpiderBallSwingControllerMovementTimer(float movement, float dt);
float GetSpiderBallSwingControllerMovementScalar() const; float GetSpiderBallSwingControllerMovementScalar() const;
void CreateSpiderBallParticles(const zeus::CVector3f&, const zeus::CVector3f&); void CreateSpiderBallParticles(const zeus::CVector3f&, const zeus::CVector3f&);
void ComputeMarioMovement(const CFinalInput& input, CStateManager& mgr, float dt); void ComputeMarioMovement(const CFinalInput& input, CStateManager& mgr, float dt);

View File

@ -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<zeus::CAABox> 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
}
}

View File

@ -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<zeus::CAABox> GetTouchBounds() const;
void Touch(CActor& actor, CStateManager& mgr);
const zeus::CVector3f& GetScale() const { return xe8_scale; }
};
}
#endif // __URDE_CSCRIPTSPIDERBALLATTRACTIONSURFACE_HPP__

View File

@ -57,11 +57,11 @@ void CScriptSpiderBallWaypoint::BuildWaypointListAndBounds(CStateManager& mgr)
else else
{ {
CScriptSpiderBallWaypoint* curWaypoint = this; CScriptSpiderBallWaypoint* curWaypoint = this;
TUniqueId uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::Yes); TUniqueId uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::SkipCheck);
while (uid != kInvalidUniqueId) while (uid != kInvalidUniqueId)
{ {
curWaypoint = static_cast<CScriptSpiderBallWaypoint*>(mgr.ObjectById(uid)); curWaypoint = static_cast<CScriptSpiderBallWaypoint*>(mgr.ObjectById(uid));
uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::Yes); uid = curWaypoint->NextWaypoint(mgr, ECheckActiveWaypoint::SkipCheck);
} }
curWaypoint->AccumulateBounds(x34_transform.origin); curWaypoint->AccumulateBounds(x34_transform.origin);
@ -73,7 +73,23 @@ void CScriptSpiderBallWaypoint::AddPreviousWaypoint(TUniqueId uid)
xec_waypoints.push_back(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) for (const SConnection& conn : x20_conns)
{ {
@ -82,13 +98,131 @@ TUniqueId CScriptSpiderBallWaypoint::NextWaypoint(const CStateManager& mgr, EChe
TUniqueId uid = mgr.GetIdForScript(conn.x8_objId); TUniqueId uid = mgr.GetIdForScript(conn.x8_objId);
if (uid != kInvalidUniqueId) if (uid != kInvalidUniqueId)
{ {
const CEntity* ent = mgr.GetObjectById(uid); if (const CEntity* ent = mgr.GetObjectById(uid))
if (ent && checkActive == ECheckActiveWaypoint::Yes && ent->GetActive()) {
return ent->GetUniqueId(); if (checkActive == ECheckActiveWaypoint::SkipCheck)
return ent->GetUniqueId();
else if (ent->GetActive())
return ent->GetUniqueId();
}
} }
} }
} }
return kInvalidUniqueId; 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<const CScriptSpiderBallWaypoint*>(
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<const CScriptSpiderBallWaypoint*>(
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<const CScriptSpiderBallWaypoint*>(
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<const CScriptSpiderBallWaypoint*>(
mgr.GetObjectById(wp->NextWaypoint(mgr, ECheckActiveWaypoint::Check)));
lastPoint = wp->GetTranslation();
computeDelta = true;
}
}
else
{
if (wp->NextWaypoint(mgr, ECheckActiveWaypoint::SkipCheck) != kInvalidUniqueId)
{
wp = static_cast<const CScriptSpiderBallWaypoint*>(
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<const CScriptSpiderBallWaypoint*>(
mgr.GetObjectById(wp->PreviousWaypoint(mgr, ECheckActiveWaypoint::SkipCheck)));
deltaBetweenPoints = lastPoint - wp->GetTranslation();
interpDeltaBetweenPoints = deltaBetweenPoints;
}
closestWaypoint = wp;
}
}
} }

View File

@ -9,8 +9,8 @@ class CScriptSpiderBallWaypoint : public CActor
{ {
enum class ECheckActiveWaypoint enum class ECheckActiveWaypoint
{ {
No, Check,
Yes SkipCheck
}; };
u32 xe8_; u32 xe8_;
std::vector<TUniqueId> xec_waypoints; std::vector<TUniqueId> xec_waypoints;
@ -22,10 +22,15 @@ public:
void Render(const CStateManager& mgr) const { CActor::Render(mgr); } void Render(const CStateManager& mgr) const { CActor::Render(mgr); }
void AddToRenderer(const zeus::CFrustum&, const CStateManager&) {} void AddToRenderer(const zeus::CFrustum&, const CStateManager&) {}
std::experimental::optional<zeus::CAABox> GetTouchBounds() const { return xfc_aabox; } std::experimental::optional<zeus::CAABox> GetTouchBounds() const { return xfc_aabox; }
void AccumulateBounds(const zeus::CVector3f&); void AccumulateBounds(const zeus::CVector3f& v);
void BuildWaypointListAndBounds(CStateManager&); void BuildWaypointListAndBounds(CStateManager& mgr);
void AddPreviousWaypoint(TUniqueId); void AddPreviousWaypoint(TUniqueId uid);
TUniqueId NextWaypoint(const CStateManager&, ECheckActiveWaypoint); 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;
}; };
} }

View File

@ -61,6 +61,7 @@
#include "CScriptWater.hpp" #include "CScriptWater.hpp"
#include "CScriptWaypoint.hpp" #include "CScriptWaypoint.hpp"
#include "CScriptWorldTeleporter.hpp" #include "CScriptWorldTeleporter.hpp"
#include "CScriptSpiderBallAttractionSurface.hpp"
#include "CSimplePool.hpp" #include "CSimplePool.hpp"
#include "CStateManager.hpp" #include "CStateManager.hpp"
#include "CVisorParameters.hpp" #include "CVisorParameters.hpp"
@ -1450,7 +1451,12 @@ CEntity* ScriptLoader::LoadDebugCameraWaypoint(CStateManager& mgr, CInputStream&
CEntity* ScriptLoader::LoadSpiderBallAttractionSurface(CStateManager& mgr, CInputStream& in, int propCount, CEntity* ScriptLoader::LoadSpiderBallAttractionSurface(CStateManager& mgr, CInputStream& in, int propCount,
const CEntityInfo& info) 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) CEntity* ScriptLoader::LoadPuddleToadGamma(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)

View File

@ -183,7 +183,7 @@ public:
~reserved_vector() ~reserved_vector()
{ {
for (size_t i=0 ; i<base::x0_size ; ++i) for (size_t i=0 ; i<base::x0_size ; ++i)
std::default_delete<T>()(std::addressof(base::_value(i))); base::_value(i).~T();
} }
void push_back(const T& d) void push_back(const T& d)
@ -224,7 +224,7 @@ public:
Log.report(logvisor::Fatal, "pop_back() called on empty rstl::reserved_vector."); Log.report(logvisor::Fatal, "pop_back() called on empty rstl::reserved_vector.");
#endif #endif
--base::x0_size; --base::x0_size;
std::default_delete<T>()(std::addressof(base::_value(base::x0_size))); base::_value(base::x0_size).~T();
} }
iterator insert(const_iterator pos, const T& value) iterator insert(const_iterator pos, const T& value)
@ -288,7 +288,7 @@ public:
else if (size < base::x0_size) else if (size < base::x0_size)
{ {
for (size_t i = size; i < base::x0_size; ++i) for (size_t i = size; i < base::x0_size; ++i)
std::default_delete<T>()(std::addressof(base::_value(i))); base::_value(i).~T();
base::x0_size = size; base::x0_size = size;
} }
} }
@ -308,7 +308,7 @@ public:
else if (size < base::x0_size) else if (size < base::x0_size)
{ {
for (size_t i = size; i < base::x0_size; ++i) for (size_t i = size; i < base::x0_size; ++i)
std::default_delete<T>()(std::addressof(base::_value(i))); base::_value(i).~T();
base::x0_size = size; base::x0_size = size;
} }
} }
@ -322,14 +322,14 @@ public:
for (auto it = base::_const_cast_iterator(pos) + 1; it != base::end(); ++it) for (auto it = base::_const_cast_iterator(pos) + 1; it != base::end(); ++it)
*(it - 1) = std::forward<T>(*it); *(it - 1) = std::forward<T>(*it);
--base::x0_size; --base::x0_size;
std::default_delete<T>()(std::addressof(base::_value(base::x0_size))); base::_value(base::x0_size).~T();
return base::_const_cast_iterator(pos); return base::_const_cast_iterator(pos);
} }
void clear() void clear()
{ {
for (auto it = base::begin(); it != base::end(); ++it) for (auto it = base::begin(); it != base::end(); ++it)
std::default_delete<T>()(std::addressof(*it)); it->~T();
base::x0_size = 0; base::x0_size = 0;
} }
}; };
@ -348,7 +348,7 @@ class prereserved_vector : public _reserved_vector_base<T, N>
void _deinit() void _deinit()
{ {
for (auto& i : base::x4_data) for (auto& i : base::x4_data)
std::default_delete<T>()(reinterpret_cast<T*>(std::addressof(i))); reinterpret_cast<T*>(std::addressof(i))->~T();
} }
public: public:
using base = _reserved_vector_base<T, N>; using base = _reserved_vector_base<T, N>;

2
hecl

@ -1 +1 @@
Subproject commit 4dbfba0cd9d2e13b61da4e99404c9f48a3599afe Subproject commit 53a34e2bba8ff2dcf2aafdbd0e64e18b5fa50ffd

@ -1 +1 @@
Subproject commit 81afe9b52644b13ecac849082d51098a2cfdea20 Subproject commit 6a89d8c22b9dfc83b93baee1344096fca7008af9