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
17namespace {
18NERVE_IMPL(CoinCirclePlacement, Move);
19
20NERVES_MAKE_STRUCT(CoinCirclePlacement, Move);
21} // namespace
22
23CoinCirclePlacement::CoinCirclePlacement(const char* name) : al::LiveActor(name) {}
24
25void 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
86void CoinCirclePlacement::listenAppear() {
87 for (s32 i = 0; i < mCoinNum; i++)
88 mCoinArray[i]->makeActorAlive();
89 makeActorAlive();
90}
91
92inline f32 modDegree(f32 value) {
93 return al::modf(a: value + 360.0f, b: 360.0f) + 0.0f;
94}
95
96void 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