1#include "Item/CoinRail.h"
2
3#include "Library/LiveActor/ActorActionFunction.h"
4#include "Library/LiveActor/ActorClippingFunction.h"
5#include "Library/LiveActor/ActorInitFunction.h"
6#include "Library/LiveActor/ActorInitUtil.h"
7#include "Library/LiveActor/ActorModelFunction.h"
8#include "Library/LiveActor/ActorPoseUtil.h"
9#include "Library/LiveActor/ActorSensorFunction.h"
10#include "Library/LiveActor/ActorSensorUtil.h"
11#include "Library/Math/MathUtil.h"
12#include "Library/Nerve/NerveSetupUtil.h"
13#include "Library/Nerve/NerveUtil.h"
14#include "Library/Placement/PlacementFunction.h"
15#include "Library/Rail/RailUtil.h"
16
17#include "Item/Coin.h"
18
19namespace {
20NERVE_IMPL(CoinRail, Move)
21NERVE_IMPL(CoinRail, CloseMove)
22
23NERVES_MAKE_STRUCT(CoinRail, CloseMove, Move)
24} // namespace
25
26CoinRail::CoinRail(const char* name) : al::LiveActor(name) {}
27
28__attribute__((always_inline)) void addStaticCoinToRail(CoinRail* rail,
29 const al::ActorInitInfo& initInfo,
30 Coin** coins, f32* railPos, s32 coinNum,
31 bool isLoop) {
32 f32 posOnRail = 0.0f;
33 f32 railDist = al::getRailTotalLength(railHolder: rail) / (coinNum - (isLoop ? 0 : 1));
34 for (s32 i = 0; i < coinNum; i++) {
35 sead::Vector3f pos;
36 al::calcRailPosAtCoord(&pos, railHolder: rail, posOnRail);
37 Coin* coin = new Coin("コイン", false);
38 al::initCreateActorWithPlacementInfo(actor: coin, initInfo);
39 coins[i] = coin;
40 coin->makeActorDead();
41 al::setTrans(actor: coins[i], trans: pos);
42 railPos[i] = posOnRail;
43 al::tryAddDisplayOffset(actor: coins[i], initInfo);
44 posOnRail += railDist;
45 }
46}
47
48__attribute__((always_inline)) void addCoinToRail(CoinRail* rail, const al::ActorInitInfo& initInfo,
49 Coin** coins, f32* railPos, s32 coinNum) {
50 f32 posOnRail = 0.0f;
51 for (s32 i = 0; i < coinNum; i++) {
52 sead::Vector3f pos = sead::Vector3f::zero;
53 al::calcRailPosAtCoord(&pos, railHolder: rail, posOnRail);
54 Coin* coin = new Coin("コイン", false);
55 al::initCreateActorWithPlacementInfo(actor: coin, initInfo);
56 coins[i] = coin;
57 coin->makeActorDead();
58 railPos[i] = posOnRail;
59 al::setTrans(actor: coins[i], trans: pos);
60 posOnRail += 150.0f;
61 al::tryAddDisplayOffset(actor: coins[i], initInfo);
62 }
63 al::getRailTotalLength(railHolder: rail);
64}
65
66void CoinRail::init(const al::ActorInitInfo& initInfo) {
67 al::initActor(actor: this, initInfo);
68
69 if (!al::isExistRail(railHolder: this)) {
70 kill();
71 return;
72 }
73
74 al::getArg(arg: &mCoinNum, initInfo, key: "CoinNum");
75 if (mCoinNum <= 1) {
76 kill();
77 return;
78 }
79
80 bool isLoop = al::isLoopRail(railHolder: this);
81 if (al::getRailPointNum(railHolder: this) <= 1) {
82 kill();
83 return;
84 }
85
86 al::tryGetArg(arg: &mMoveVelocity, initInfo, key: "MoveVelocity");
87 if (mMoveVelocity < 0.0f) {
88 kill();
89 return;
90 }
91
92 al::tryGetDisplayOffset(offset: &mDisplayOffset, initInfo);
93
94 mCoins = new Coin*[mCoinNum];
95 mRailPos = new f32[mCoinNum];
96
97 if (al::isNearZero(value: mMoveVelocity))
98 addStaticCoinToRail(rail: this, initInfo, coins: mCoins, railPos: mRailPos, coinNum: mCoinNum, isLoop);
99 else
100 addCoinToRail(rail: this, initInfo, coins: mCoins, railPos: mRailPos, coinNum: mCoinNum);
101
102 f32 shadowLength = 1500.0f;
103 al::tryGetArg(arg: &shadowLength, initInfo, key: "ShadowLength");
104 for (s32 i = 0; i < mCoinNum; i++)
105 mCoins[i]->setShadowDropLength(shadowLength);
106
107 mLastCoinIndex = mCoinNum - 1;
108 mFirstCoinIndex = 0;
109
110 f32 clipInfo = 0.0f;
111 al::calcRailClippingInfo(&mClippingInfo, &clipInfo, railHolder: this, 100.0f, 100.0f);
112 al::setClippingInfo(actor: this, clipInfo, &mClippingInfo);
113 al::initSubActorKeeperNoFile(this, initInfo, mCoinNum);
114
115 for (s32 i = 0; i < mCoinNum; i++) {
116 al::invalidateClipping(actor: mCoins[i]);
117 al::registerSubActorSyncClipping(this, mCoins[i]);
118 }
119
120 if (isLoop)
121 al::initNerve(actor: this, nerve: &NrvCoinRail.CloseMove, maxStates: 0);
122 else
123 al::initNerve(actor: this, nerve: &NrvCoinRail.Move, maxStates: 0);
124
125 al::LiveActor::makeActorDead();
126 if (!al::trySyncStageSwitchAppear(actor: this)) {
127 al::LiveActor::appear();
128 for (s32 i = 0; i < mCoinNum; i++)
129 mCoins[i]->appearCoinRail();
130 }
131 al::invalidateHitSensors(this);
132}
133
134void CoinRail::appear() {
135 al::LiveActor::appear();
136 al::startHitReaction(actor: this, name: "出現");
137 for (s32 i = 0; i < mCoinNum; i++)
138 mCoins[i]->appearCoinRail();
139}
140
141void CoinRail::kill() {
142 al::LiveActor::kill();
143 for (s32 i = 0; i < mCoinNum; i++)
144 mCoins[i]->kill();
145}
146
147void CoinRail::makeActorDead() {
148 al::LiveActor::makeActorDead();
149 for (s32 i = 0; i < mCoinNum; i++)
150 mCoins[i]->makeActorDead();
151}
152
153bool CoinRail::receiveMsg(const al::SensorMsg* message, al::HitSensor* other, al::HitSensor* self) {
154 if (al::isMsgShowModel(msg: message)) {
155 for (s32 i = 0; i < mCoinNum; i++)
156 if (!mCoins[i]->isGot())
157 al::showModelIfHide(actor: mCoins[i]);
158 return true;
159 }
160
161 if (al::isMsgHideModel(msg: message)) {
162 for (s32 i = 0; i < mCoinNum; i++)
163 al::hideModelIfShow(actor: mCoins[i]);
164 return true;
165 }
166
167 return false;
168}
169
170bool CoinRail::isGot() const {
171 for (s32 i = 0; i < mCoinNum; i++)
172 if (!mCoins[i]->isGot())
173 return false;
174 return true;
175}
176
177void CoinRail::exeMove() {
178 if (al::isNearZero(value: mMoveVelocity))
179 return;
180
181 if (mMoveVelocity > 0.0f) {
182 f32 railLength = al::getRailTotalLength(railHolder: this);
183 mRailPos[mLastCoinIndex] += mMoveVelocity;
184 f32 lastCoinPos = mRailPos[mLastCoinIndex];
185 if (lastCoinPos > railLength) {
186 lastCoinPos = railLength;
187 mMoveVelocity = -mMoveVelocity;
188 }
189
190 sead::Vector3f pos = sead::Vector3f::zero;
191 for (s32 i = mLastCoinIndex; i >= mFirstCoinIndex; i--) {
192 al::calcRailPosAtCoord(&pos, railHolder: this, lastCoinPos);
193 mRailPos[i] = lastCoinPos;
194 lastCoinPos -= 150.0f;
195 al::setTrans(actor: mCoins[i], trans: pos + mDisplayOffset);
196 }
197 } else {
198 mRailPos[mFirstCoinIndex] += mMoveVelocity;
199 f32 firstCoinPos = mRailPos[mFirstCoinIndex];
200 if (firstCoinPos < 0.0f) {
201 firstCoinPos = 0.0f;
202 mMoveVelocity = -mMoveVelocity;
203 }
204
205 sead::Vector3f pos = sead::Vector3f::zero;
206 for (s32 i = mFirstCoinIndex; i <= mLastCoinIndex; i++) {
207 al::calcRailPosAtCoord(&pos, railHolder: this, firstCoinPos);
208 mRailPos[i] = firstCoinPos;
209 firstCoinPos += 150.0f;
210 al::setTrans(actor: mCoins[i], trans: pos + mDisplayOffset);
211 }
212 }
213
214 for (s32 i = mFirstCoinIndex; i <= mLastCoinIndex; i++) {
215 if (!mCoins[i]->isGot()) {
216 mFirstCoinIndex = i;
217 break;
218 }
219 }
220
221 for (s32 i = mLastCoinIndex; i >= mFirstCoinIndex; i--) {
222 if (!mCoins[i]->isGot()) {
223 mLastCoinIndex = i;
224 break;
225 }
226 }
227}
228
229void CoinRail::exeCloseMove() {
230 sead::Vector3f postion = sead::Vector3f::zero;
231 for (s32 i = 0; i < mCoinNum; i++) {
232 if (!mCoins[i]->isGot()) {
233 mRailPos[i] += mMoveVelocity;
234 al::calcRailPosAtCoord(&postion, railHolder: this, mRailPos[i]);
235 al::setTrans(actor: mCoins[i], trans: postion);
236 }
237 }
238}
239