Library/Movement: Implement ClockMovement (#1053)

This commit is contained in:
Narr the Reg 2026-04-22 12:18:01 -06:00 committed by GitHub
parent e815a23f5f
commit b847fd4117
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 183 additions and 45 deletions

View file

@ -264305,60 +264305,60 @@ Library/Movement/ClockMovement.o:
label:
- _ZN2al13ClockMovementC1ERKNS_13ActorInitInfoE
- _ZN2al13ClockMovementC2ERKNS_13ActorInitInfoE
status: NotDecompiled
status: Matching
- offset: 0x952a1c
size: 100
label: _ZN2al13ClockMovement8exeDelayEv
status: NotDecompiled
status: Matching
- offset: 0x952a80
size: 204
label: _ZN2al13ClockMovement13exeRotateSignEv
status: NotDecompiled
status: Matching
- offset: 0x952b4c
size: 156
label: _ZN2al13ClockMovement9exeRotateEv
status: NotDecompiled
status: Matching
- offset: 0x952be8
size: 96
label: _ZN2al13ClockMovement7exeWaitEv
status: NotDecompiled
status: Matching
- offset: 0x952c48
size: 64
label: _ZNK2al13ClockMovement16isFirstStepDelayEv
status: NotDecompiled
status: Matching
- offset: 0x952c88
size: 68
label: _ZNK2al13ClockMovement21isFirstStepRotateSignEv
status: NotDecompiled
status: Matching
- offset: 0x952ccc
size: 68
label: _ZNK2al13ClockMovement17isFirstStepRotateEv
status: NotDecompiled
status: Matching
- offset: 0x952d10
size: 64
label: _ZNK2al13ClockMovement15isFirstStepWaitEv
status: NotDecompiled
status: Matching
- offset: 0x952d50
size: 36
label: _ZN2al13ClockMovementD0Ev
status: NotDecompiled
status: Matching
lazy: true
- offset: 0x952d74
size: 104
label: ''
status: NotDecompiled
label: _ZNK12_GLOBAL__N_121ClockMovementNrvDelay7executeEPN2al11NerveKeeperE
status: Matching
- offset: 0x952ddc
size: 8
label: ''
status: NotDecompiled
label: _ZNK12_GLOBAL__N_126ClockMovementNrvRotateSign7executeEPN2al11NerveKeeperE
status: Matching
- offset: 0x952de4
size: 8
label: ''
status: NotDecompiled
label: _ZNK12_GLOBAL__N_122ClockMovementNrvRotate7executeEPN2al11NerveKeeperE
status: Matching
- offset: 0x952dec
size: 100
label: ''
status: NotDecompiled
label: _ZNK12_GLOBAL__N_120ClockMovementNrvWait7executeEPN2al11NerveKeeperE
status: Matching
Library/Movement/EnemyStateBlowDown.o:
'.text':
- offset: 0x952e50

View file

@ -250,7 +250,7 @@ void ClockMapParts::exeRotate() {
mTimer++;
if (mTimer >= mRotateTimer) {
mCurrentStep = modi(mCurrentStep + mTurnStepCount + 1, mTurnStepCount);
mCurrentStep = wrapValue(mCurrentStep + 1, mTurnStepCount);
startNerveAction(this, "Wait");
tryStartSe(this, "RotateEnd");
}

View file

@ -205,6 +205,10 @@ void makeBoxMullerRandomGauss(sead::Vector2f* outBox, f32 randA, f32 randB);
f32 modf(f32 a, f32 b);
s32 modi(s32 a, s32 b);
inline s32 wrapValue(s32 value, s32 maxRange) {
return modi(value + maxRange, maxRange);
}
inline f32 wrapValue(f32 value, f32 maxRange) {
return modf(value + maxRange, maxRange) + 0.0f;
}

View file

@ -0,0 +1,101 @@
#include "Library/Movement/ClockMovement.h"
#include "Library/Math/MathUtil.h"
#include "Library/Nerve/NerveSetupUtil.h"
#include "Library/Nerve/NerveUtil.h"
#include "Library/Placement/PlacementFunction.h"
namespace {
using namespace al;
NERVE_IMPL(ClockMovement, Delay);
NERVE_IMPL(ClockMovement, RotateSign);
NERVE_IMPL(ClockMovement, Rotate);
NERVE_IMPL(ClockMovement, Wait);
NERVES_MAKE_STRUCT(ClockMovement, Delay, RotateSign, Rotate);
NERVES_MAKE_NOSTRUCT(ClockMovement, Wait);
} // namespace
namespace al {
ClockMovement::ClockMovement(const ActorInitInfo& info) : NerveExecutor("クロックパーツ動作") {
getQuat(&mInitialQuat, info);
mCurrentQuat = mInitialQuat;
tryGetArg(&mClockAngleDegree, info, "ClockAngleDegree");
tryGetArg(&mRotateAxis, info, "RotateAxis");
tryGetArg(&mDelayTime, info, "DelayTime");
tryGetArg(&mRotateSignTime, info, "RotateSignTime");
tryGetArg(&mRotateTime, info, "RotateTime");
tryGetArg(&mWaitTime, info, "WaitTime");
if (mDelayTime == 0)
initNerve(&NrvClockMovement.RotateSign, 0);
else
initNerve(&NrvClockMovement.Delay, 0);
s32 stepsPerCycle = 1;
if (mClockAngleDegree != 0) {
stepsPerCycle = sead::Mathi::lcm(sead::Mathi::abs(mClockAngleDegree), 360) /
sead::Mathi::abs(mClockAngleDegree);
}
mMaxStepIndex = stepsPerCycle;
}
void ClockMovement::exeDelay() {
if (isGreaterEqualStep(this, mDelayTime - 1)) {
if (mRotateSignTime > 0)
setNerve(this, &NrvClockMovement.RotateSign);
else
setNerve(this, &NrvClockMovement.Rotate);
}
}
void ClockMovement::exeRotateSign() {
f32 rotateAngle = wrapValue(static_cast<f32>(mCurrentStepIndex * mClockAngleDegree), 360.0f);
rotateQuatLocalDirDegree(&mCurrentQuat, mInitialQuat, mRotateAxis,
rotateAngle +
sead::Mathf::sin(getNerveStep(this) * sead::Mathf::pi2() / 18.0f));
if (isGreaterEqualStep(this, mRotateSignTime - 1))
setNerve(this, &NrvClockMovement.Rotate);
}
void ClockMovement::exeRotate() {
f32 rotateAngle = wrapValue(
(calcNerveRate(this, mRotateTime) + mCurrentStepIndex) * mClockAngleDegree, 360.0f);
rotateQuatLocalDirDegree(&mCurrentQuat, mInitialQuat, mRotateAxis, rotateAngle);
if (isGreaterEqualStep(this, mRotateTime)) {
mCurrentStepIndex = wrapValue(mCurrentStepIndex + 1, mMaxStepIndex);
setNerve(this, &Wait);
}
}
void ClockMovement::exeWait() {
if (isGreaterEqualStep(this, mWaitTime)) {
if (mRotateSignTime > 0)
setNerve(this, &NrvClockMovement.RotateSign);
else
setNerve(this, &NrvClockMovement.Rotate);
}
}
bool ClockMovement::isFirstStepDelay() const {
return isNerve(this, &NrvClockMovement.Delay) && isFirstStep(this);
}
bool ClockMovement::isFirstStepRotateSign() const {
return isNerve(this, &NrvClockMovement.RotateSign) && isFirstStep(this);
}
bool ClockMovement::isFirstStepRotate() const {
return isNerve(this, &NrvClockMovement.Rotate) && isFirstStep(this);
}
bool ClockMovement::isFirstStepWait() const {
return isNerve(this, &Wait) && isFirstStep(this);
}
} // namespace al

View file

@ -0,0 +1,36 @@
#pragma once
#include <math/seadQuat.h>
#include "Library/Nerve/NerveExecutor.h"
namespace al {
struct ActorInitInfo;
class ClockMovement : public NerveExecutor {
public:
ClockMovement(const ActorInitInfo& info);
void exeDelay();
void exeRotateSign();
void exeRotate();
void exeWait();
bool isFirstStepDelay() const;
bool isFirstStepRotateSign() const;
bool isFirstStepRotate() const;
bool isFirstStepWait() const;
private:
sead::Quatf mCurrentQuat = sead::Quatf::unit;
sead::Quatf mInitialQuat = sead::Quatf::unit;
s32 mRotateAxis = 0;
s32 mClockAngleDegree = 90;
s32 mCurrentStepIndex = 0;
s32 mMaxStepIndex = 4;
s32 mDelayTime = 0;
s32 mRotateSignTime = 36;
s32 mRotateTime = 60;
s32 mWaitTime = 0;
};
static_assert(sizeof(ClockMovement) == 0x50);
} // namespace al

View file

@ -59,7 +59,7 @@ void SwingMovement::exeMove() {
if (updateRotate())
setNerve(this, &Stop);
mFrameInCycle = modi((mFrameInCycle + 1) + mSwingCycle, mSwingCycle);
mFrameInCycle = wrapValue(mFrameInCycle + 1, mSwingCycle);
}
void SwingMovement::exeStop() {

View file

@ -323,11 +323,8 @@ s32 getNextRailPointNo(const IUseRail* railHolder) {
s32 newIndex = getRailPointNo(railHolder) + modifier;
s32 railPointNum = getRailPointNum(railHolder);
if (isLoop) {
s32 sum = railPointNum + newIndex;
s32 railPointNumAgain = getRailPointNum(railHolder);
return modi(sum + railPointNumAgain, railPointNumAgain);
}
if (isLoop)
return wrapValue(railPointNum + newIndex, getRailPointNum(railHolder));
return sead::Mathi::clamp2(0, newIndex, railPointNum - 1);
}

View file

@ -17,8 +17,7 @@ void FlowMapCtrl::update() {
flowParameters.y =
calcRate01(halfInterval - sead::Mathi::abs(halfInterval - mFlowStep), 0.0f, halfInterval);
flowParameters.z = calcRate01(mFlowStep, 0.0f, mInterval);
flowParameters.w =
calcRate01(modi(mFlowStep + halfInterval + mInterval, mInterval), 0.0f, mInterval);
flowParameters.w = calcRate01(wrapValue(mFlowStep + halfInterval, mInterval), 0.0f, mInterval);
s32 materialCount = getMaterialCount(mParent);
for (s32 i = 0; i < materialCount; i++) {
@ -27,7 +26,7 @@ void FlowMapCtrl::update() {
}
mFlowStep++;
mFlowStep = modi(mFlowStep + mInterval, mInterval);
mFlowStep = wrapValue(mFlowStep, mInterval);
}
} // namespace al

View file

@ -65,8 +65,8 @@ void KoopaLandPointHolder::decidePointEitherFarSide(const sead::Vector3f& pos) {
}
mInvalidPoints[mCurrentLandPoint] = false;
s32 prevPoint = al::modi(mCurrentLandPoint - 1 + mLandPoints, mLandPoints);
s32 nextPoint = al::modi(mCurrentLandPoint + 1 + mLandPoints, mLandPoints);
s32 prevPoint = al::wrapValue(mCurrentLandPoint - 1, mLandPoints);
s32 nextPoint = al::wrapValue(mCurrentLandPoint + 1, mLandPoints);
f32 prevDist = getKoopaLandPointDistance(mPointsTrans[prevPoint], pos);
f32 nextDist = getKoopaLandPointDistance(mPointsTrans[nextPoint], pos);

View file

@ -638,7 +638,8 @@ void Bubble::control() {
if (!al::isNerve(this, &NrvBubble.StandBy) && !al::isNerve(this, &NrvBubble.Delay) &&
(!isHack() || !rs::isActiveHackStartDemo(mPlayerHack)) &&
!al::isClipped(mClippingProbeActor) && !mIsClipped) {
mReviveDelayCount = al::modi(mReviveDelayCount + 1 + mReviveDelayTime, mReviveDelayTime);
mReviveDelayCount =
al::wrapValue(static_cast<s32>(mReviveDelayCount + 1), mReviveDelayTime);
}
mIsClipped = al::isClipped(mClippingProbeActor);

View file

@ -505,7 +505,8 @@ void Gamane::exeHack() {
mCoinsLeft--;
}
mHackCoinAppearCounter = al::modi((mHackCoinAppearCounter++ + 1) + 6, 6);
// NOTE: this is only one increment, as post-incrementing is used
mHackCoinAppearCounter = al::wrapValue(mHackCoinAppearCounter++ + 1, 6);
}
void Gamane::exeTrampled() {

View file

@ -25,7 +25,7 @@ HosuiTrailKeeper::HosuiTrailKeeper(const al::ActorInitInfo& initInfo) {
void HosuiTrailKeeper::appearTrail(const sead::Vector3f& pos, const sead::Vector3f& dir) {
s32 count = mTrails.size();
s32 prevIdx = al::modi(mIndex + count - 1 + count, count);
s32 prevIdx = al::wrapValue(mIndex + count - 1, count);
HosuiTrail* prevTrail = mTrails[prevIdx];
if (al::isAlive(prevTrail) && (pos - al::getTrans(prevTrail)).length() < 120.0f)
@ -56,12 +56,12 @@ void HosuiTrailKeeper::appearTrail(const sead::Vector3f& pos, const sead::Vector
trail->setFollowCollisionParts(triangle.getCollisionParts());
}
s32 disappearIdx = al::modi(mIndex + 5 + count, count);
s32 disappearIdx = al::wrapValue(mIndex + 5, count);
HosuiTrail* disappearTrail = mTrails[disappearIdx];
if (al::isAlive(disappearTrail))
disappearTrail->disappear();
mIndex = al::modi(mIndex + 1 + count, count);
mIndex = al::wrapValue(mIndex + 1, count);
}
void HosuiTrailKeeper::forceKillAll() {

View file

@ -243,8 +243,7 @@ void MenuSelectParts::exeSelect() {
s32 direction = mKeyRepeatCtrl->isUp() ? -1 : 1;
al::startAction(mLayoutArray[calcPartsIndex(mCursorItemIndex)], "Wait");
mCursorItemIndex =
al::modi(mCursorItemIndex + direction + mMenuItemAmount, mMenuItemAmount);
mCursorItemIndex = al::wrapValue(mCursorItemIndex + direction, mMenuItemAmount);
f32 pitch = ((1.0f - (f32)mCursorItemIndex / (mMenuItemAmount - 1)) * 0.375f) + 1.0f;
al::PadRumbleParam param;

View file

@ -161,15 +161,15 @@ void WindowConfirmData::exeWait() {
if (rs::isRepeatUiDown(mWindowConfirmLayout)) {
if (mSelectionCooldown == 0)
changeSelectingIdx(al::modi((mSelectionIndex + 1) + 2, 2));
mSelectionCooldown = al::modi((mSelectionCooldown + 1) + 10, 10);
changeSelectingIdx(al::wrapValue(mSelectionIndex + 1, 2));
mSelectionCooldown = al::wrapValue(mSelectionCooldown + 1, 10);
return;
}
if (rs::isRepeatUiUp(mWindowConfirmLayout)) {
if (mSelectionCooldown == 0)
changeSelectingIdx(al::modi((mSelectionIndex - 1) + 2, 2));
mSelectionCooldown = al::modi((mSelectionCooldown + 1) + 10, 10);
changeSelectingIdx(al::wrapValue(mSelectionIndex - 1, 2));
mSelectionCooldown = al::wrapValue(mSelectionCooldown + 1, 10);
return;
}

View file

@ -82,18 +82,18 @@ void SmallBirdStateFlyAway::exeFlyAway() {
mIsColliding = false;
startActionAtRandomFrameIfNotPlaying(mActor, "Fly");
if (rs::isModeE3MovieRom()) {
gVerticalAccelIndex = al::modi(gVerticalAccelIndex + 7, 6);
gVerticalAccelIndex = al::wrapValue(gVerticalAccelIndex + 1, 6);
mVerticalAccel = gE3MovieVerticalAccel[gVerticalAccelIndex];
gHorizontalAccelIndex = al::modi(gHorizontalAccelIndex + 5, 4);
gHorizontalAccelIndex = al::wrapValue(gHorizontalAccelIndex + 1, 4);
mHorizontalAccel = gE3MovieHorizontalAccel[gHorizontalAccelIndex];
} else {
gVerticalAccelIndex = al::modi(gVerticalAccelIndex + 5, 4);
gVerticalAccelIndex = al::wrapValue(gVerticalAccelIndex + 1, 4);
mVerticalAccel = gVerticalAccel[gVerticalAccelIndex];
mHorizontalAccel = gHorizontalAccel;
}
mTargetAccelDir = {0, mVerticalAccel, mHorizontalAccel};
al::normalize(&mTargetAccelDir);
gCollisionCheckOffsetStep = al::modi(gCollisionCheckOffsetStep + 11, 10);
gCollisionCheckOffsetStep = al::wrapValue(gCollisionCheckOffsetStep + 1, 10);
mCollisionCheckOffsetStep = gCollisionCheckOffsetStep;
}