| 1 | #include "Item/CoinCirclePlacement.h" |
| 2 | |
| 3 | #include "Library/LiveActor/ActorClippingFunction.h" |
| 4 | #include "Library/LiveActor/ActorFlagFunction.h" |
| 5 | #include "Library/LiveActor/ActorInitUtil.h" |
| 6 | #include "Library/LiveActor/ActorPoseUtil.h" |
| 7 | #include "Library/Math/MathUtil.h" |
| 8 | #include "Library/Nerve/NerveSetupUtil.h" |
| 9 | #include "Library/Nerve/NerveUtil.h" |
| 10 | #include "Library/Placement/PlacementFunction.h" |
| 11 | #include "Library/Stage/StageSwitchUtil.h" |
| 12 | #include "Library/Thread/FunctorV0M.h" |
| 13 | |
| 14 | #include "Item/Coin.h" |
| 15 | #include "Util/ShadowUtil.h" |
| 16 | |
| 17 | namespace { |
| 18 | NERVE_IMPL(CoinCirclePlacement, Move); |
| 19 | |
| 20 | NERVES_MAKE_STRUCT(CoinCirclePlacement, Move); |
| 21 | } // namespace |
| 22 | |
| 23 | CoinCirclePlacement::CoinCirclePlacement(const char* name) : al::LiveActor(name) {} |
| 24 | |
| 25 | void CoinCirclePlacement::init(const al::ActorInitInfo& initInfo) { |
| 26 | using CoinCirclePlacementFunctor = |
| 27 | al::FunctorV0M<CoinCirclePlacement*, void (CoinCirclePlacement::*)()>; |
| 28 | |
| 29 | al::initActor(actor: this, initInfo); |
| 30 | al::initNerve(actor: this, nerve: &NrvCoinCirclePlacement.Move, maxStates: 0); |
| 31 | al::getArg(arg: &mCoinNum, initInfo, key: "CoinNum" ); |
| 32 | |
| 33 | if (mCoinNum <= 0) { |
| 34 | kill(); |
| 35 | return; |
| 36 | } |
| 37 | |
| 38 | al::getArg(arg: &mRotateVelocity, initInfo, key: "RotateVelocity" ); |
| 39 | al::tryGetArg(arg: &mCircleXWidth, initInfo, key: "CircleXWidth" ); |
| 40 | al::tryGetArg(arg: &mCircleZWidth, initInfo, key: "CircleZWidth" ); |
| 41 | al::tryGetSide(side: &mSide, initInfo); |
| 42 | al::tryGetUp(up: &mUp, initInfo); |
| 43 | al::tryGetFront(front: &mFront, initInfo); |
| 44 | |
| 45 | s32 coinNum = mCoinNum; |
| 46 | mCoinArray = new Coin*[mCoinNum]; |
| 47 | for (s32 i = 0; i < mCoinNum; i++) { |
| 48 | Coin* coin = new Coin("コイン" , false); |
| 49 | al::initCreateActorWithPlacementInfo(actor: coin, initInfo); |
| 50 | mCoinArray[i] = coin; |
| 51 | |
| 52 | f32 coinAngle = sead::Mathf::deg2rad(deg: (360.0f / coinNum) * i); |
| 53 | f32 xWidth = mCircleXWidth * sead::Mathf::cos(t: coinAngle) * 100.0f; |
| 54 | f32 zWidth = mCircleZWidth * sead::Mathf::sin(t: coinAngle) * 100.0f; |
| 55 | |
| 56 | const sead::Vector3f& centerPos = al::getTrans(actor: this); |
| 57 | sead::Vector3f coinPos = centerPos + xWidth * mSide + zWidth * mFront; |
| 58 | |
| 59 | al::setTrans(actor: mCoinArray[i], trans: coinPos); |
| 60 | al::setScale(actor: mCoinArray[i], scale: {1.0f, 1.0f, 1.0f}); |
| 61 | al::tryAddDisplayOffset(actor: mCoinArray[i], initInfo); |
| 62 | al::expandClippingRadiusByShadowLength( |
| 63 | actor: this, &_154, radius: rs::setShadowDropLength(mCoinArray[i], initInfo, "本体" )); |
| 64 | mCoinArray[i]->appearCirclePlacement(); |
| 65 | } |
| 66 | |
| 67 | f32 clippingRadius = 0.0f; |
| 68 | const sead::Vector3f& centerPosition = al::getTrans(actor: this); |
| 69 | for (s32 i = 0; i < mCoinNum; i++) { |
| 70 | sead::Vector3f distanceToCenter = al::getTrans(actor: mCoinArray[i]) - centerPosition; |
| 71 | f32 coinRadius = distanceToCenter.length() + al::getClippingRadius(actor: mCoinArray[i]); |
| 72 | clippingRadius = sead::Mathf::max(a: coinRadius, b: clippingRadius); |
| 73 | } |
| 74 | al::setClippingInfo(actor: this, clippingRadius, al::getTransPtr(actor: this)); |
| 75 | |
| 76 | if (!al::listenStageSwitchOnAppear( |
| 77 | user: this, action: CoinCirclePlacementFunctor(this, &CoinCirclePlacement::listenAppear))) { |
| 78 | makeActorAlive(); |
| 79 | } else { |
| 80 | makeActorDead(); |
| 81 | for (s32 i = 0; i < mCoinNum; i++) |
| 82 | mCoinArray[i]->makeActorDead(); |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | void CoinCirclePlacement::listenAppear() { |
| 87 | for (s32 i = 0; i < mCoinNum; i++) |
| 88 | mCoinArray[i]->makeActorAlive(); |
| 89 | makeActorAlive(); |
| 90 | } |
| 91 | |
| 92 | inline f32 modDegree(f32 value) { |
| 93 | return al::modf(a: value + 360.0f, b: 360.0f) + 0.0f; |
| 94 | } |
| 95 | |
| 96 | void CoinCirclePlacement::exeMove() { |
| 97 | if (al::isNearZero(value: mRotateVelocity)) |
| 98 | return; |
| 99 | |
| 100 | mCurrentAngle = modDegree(value: mCurrentAngle + mRotateVelocity); |
| 101 | |
| 102 | s32 coinNum = mCoinNum; |
| 103 | bool isNoCoinAlive = true; |
| 104 | for (s32 i = 0; i < mCoinNum; i++) { |
| 105 | if (al::isDead(actor: mCoinArray[i]) || !mCoinArray[i]->isWait()) |
| 106 | continue; |
| 107 | f32 prevY = al::getTrans(actor: mCoinArray[i]).y; |
| 108 | f32 coinAngle = sead::Mathf::deg2rad(deg: modDegree(value: mCurrentAngle + (360.0f / coinNum) * i)); |
| 109 | f32 xWidth = mCircleXWidth * sead::Mathf::cos(t: coinAngle) * 100.0f; |
| 110 | f32 zWidth = mCircleZWidth * sead::Mathf::sin(t: coinAngle) * 100.0f; |
| 111 | |
| 112 | const sead::Vector3f& centerPos = al::getTrans(actor: this); |
| 113 | // The coin's new position is inverted on the X axis from the spawn point. |
| 114 | // This is likely a game bug with no adverse effects. |
| 115 | sead::Vector3f newCoinPos = -xWidth * mSide + centerPos + zWidth * mFront; |
| 116 | newCoinPos.y = prevY; |
| 117 | |
| 118 | al::setTrans(actor: mCoinArray[i], trans: newCoinPos); |
| 119 | isNoCoinAlive = false; |
| 120 | } |
| 121 | |
| 122 | if (isNoCoinAlive) |
| 123 | kill(); |
| 124 | } |
| 125 | |