1#include "Util/ItemUtil.h"
2
3#include <math/seadMatrix.h>
4
5#include "Library/Base/StringUtil.h"
6#include "Library/Item/ItemUtil.h"
7#include "Library/LiveActor/ActorActionFunction.h"
8#include "Library/LiveActor/ActorAnimFunction.h"
9#include "Library/LiveActor/ActorFlagFunction.h"
10#include "Library/LiveActor/ActorInitInfo.h"
11#include "Library/LiveActor/ActorInitUtil.h"
12#include "Library/LiveActor/ActorModelFunction.h"
13#include "Library/LiveActor/ActorMovementFunction.h"
14#include "Library/LiveActor/ActorPoseUtil.h"
15#include "Library/LiveActor/LiveActor.h"
16#include "Library/Math/MathUtil.h"
17#include "Library/Matrix/MatrixUtil.h"
18#include "Library/Model/ModelShapeUtil.h"
19#include "Library/Placement/PlacementFunction.h"
20#include "Library/Scene/SceneObjUtil.h"
21#include "Library/Stage/StageRhythm.h"
22
23#include "Item/Shine.h"
24#include "System/GameDataFunction.h"
25#include "System/GameDataHolder.h"
26#include "System/WorldList.h"
27#include "Util/SensorMsgFunction.h"
28
29const char* sItem2DNames[] = {
30 "コイン2D[自動取得]",
31 "コイン2D[自動取得]",
32 "コイン2D[自動取得]",
33 "コイン2D[自動取得]",
34 "コイン2D[飛出し出現]",
35 "コイン2D[自動取得]",
36 "コイン2D[自動取得]",
37 "コイン2D[自動取得]",
38 "コイン2D[自動取得]",
39 "コイン2D[自動取得]",
40 "コイン2D[自動取得]",
41 "コイン2D[自動取得]",
42 "ライフアップアイテム[飛出し出現]",
43 "ライフアップアイテム[逆向き飛出し出現]",
44 "ライフアップアイテム2D[飛出し出現]",
45 "コイン2D[自動取得]",
46 "最大ライフアップアイテム2D[飛出し出現]",
47};
48
49namespace rs {
50
51ItemType::ValueType getItemType(const al::ActorInitInfo& info) {
52 const char* name = nullptr;
53 if (!al::tryGetStringArg(arg: &name, initInfo: info, key: "ItemType") &&
54 !al::tryGetStringArg(arg: &name, initInfo: info, key: "ItemTypeNoShine") &&
55 !al::tryGetStringArg(arg: &name, initInfo: info, key: "ItemType2D3D"))
56 return ItemType::None;
57 if (al::isEqualString(str1: name, str2: "None"))
58 return ItemType::None;
59 return getItemType(name);
60}
61
62ItemType::ValueType getItemTypeFromName(const char* name) {
63 if (al::isEqualString(str1: name, str2: "Coin"))
64 return ItemType::Coin;
65 if (al::isEqualString(str1: name, str2: "Coin2D"))
66 return ItemType::Coin2D;
67 if (al::isEqualString(str1: name, str2: "CoinBlow"))
68 return ItemType::CoinBlow;
69 if (al::isEqualString(str1: name, str2: "CoinBlowVeryLittle"))
70 return ItemType::CoinBlowVeryLittle;
71 if (al::isEqualString(str1: name, str2: "CoinPopUp"))
72 return ItemType::CoinPopUp;
73 if (al::isEqualString(str1: name, str2: "CoinPopUpWithoutHitReaction"))
74 return ItemType::CoinPopUpWithoutHitReaction;
75 if (al::isEqualString(str1: name, str2: "Coin3"))
76 return ItemType::Coin3;
77 if (al::isEqualString(str1: name, str2: "Coin5"))
78 return ItemType::Coin5;
79 if (al::isEqualString(str1: name, str2: "Coin10"))
80 return ItemType::Coin10;
81 if (al::isEqualString(str1: name, str2: "Coin10Auto"))
82 return ItemType::Coin10Auto;
83 if (al::isEqualString(str1: name, str2: "Coin100"))
84 return ItemType::Coin100;
85 if (al::isEqualString(str1: name, str2: "Coin5Count"))
86 return ItemType::Coin5Count;
87 if (al::isEqualString(str1: name, str2: "LifeUpItem"))
88 return ItemType::LifeUpItem;
89 if (al::isEqualString(str1: name, str2: "LifeUpItemBack"))
90 return ItemType::LifeUpItemBack;
91 if (al::isEqualString(str1: name, str2: "LifeUpItem2D"))
92 return ItemType::LifeUpItem2D;
93 if (al::isEqualString(str1: name, str2: "LifeMaxUpItem"))
94 return ItemType::LifeMaxUpItem;
95 if (al::isEqualString(str1: name, str2: "LifeMaxUpItem2D"))
96 return ItemType::LifeMaxUpItem2D;
97 if (al::isEqualString(str1: name, str2: "Shine"))
98 return ItemType::Shine;
99 if (al::isEqualString(str1: name, str2: "AirBubble"))
100 return ItemType::AirBubble;
101 if (al::isEqualString(str1: name, str2: "DotMarioCat"))
102 return ItemType::DotMarioCat;
103 if (al::isEqualString(str1: name, str2: "KuriboMini3"))
104 return ItemType::KuriboMini3;
105 if (al::isEqualString(str1: name, str2: "KuriboMini8"))
106 return ItemType::KuriboMini8;
107 if (al::isEqualString(str1: name, str2: "CoinStackBound"))
108 return ItemType::CoinStackBound;
109 if (al::isEqualString(str1: name, str2: "Random"))
110 return ItemType::Random;
111 return ItemType::None;
112}
113
114ItemType::ValueType getItemType(const char* name) {
115 return getItemTypeFromName(name);
116}
117
118bool isItemTypeKuriboMini(s32* out, s32 type) {
119 if (type == ItemType::KuriboMini3) {
120 *out = ItemType::CoinBlowVeryLittle;
121 return true;
122 } else if (type == ItemType::KuriboMini8) {
123 *out = ItemType::Coin10;
124 return true;
125 }
126 return false;
127}
128
129bool tryInitItemAndAddToKeeper(al::LiveActor* actor, s32 itemType, const al::ActorInitInfo& info,
130 bool isAppearAbove) {
131 if (itemType == ItemType::Random) {
132 actor->initItemKeeper(itemAmount: 2);
133 al::addItem(actor, info, "ライフアップアイテム[飛出し出現]", "ライフアップ", nullptr, -1,
134 false);
135 al::addItem(actor, info, "コイン[自動取得]", "コイン", nullptr, -1, false);
136 return true;
137 }
138
139 actor->initItemKeeper(itemAmount: 1);
140
141 const char* name;
142 switch (itemType) {
143 case ItemType::Coin:
144 case ItemType::Coin10:
145 case ItemType::Coin100:
146 name = "コイン[自動取得]";
147 break;
148 case ItemType::CoinBlow:
149 name = "コイン[放出]";
150 break;
151 case ItemType::CoinBlowVeryLittle:
152 name = "コイン[放出・極小]";
153 break;
154 case ItemType::CoinPopUp:
155 name = "コイン[飛出し出現]";
156 break;
157 case ItemType::CoinPopUpWithoutHitReaction:
158 name = "コイン[飛出し出現・出現音無し]";
159 break;
160 case ItemType::Coin3:
161 name = "コインx3[自動取得]";
162 break;
163 case ItemType::Coin5:
164 name = "コインx5[自動取得]";
165 break;
166 case ItemType::Coin10Auto:
167 name = "コインx10[自動取得]";
168 break;
169 case ItemType::Coin5Count:
170 name = "コイン[自動取得5枚]";
171 break;
172 case ItemType::LifeUpItem:
173 name =
174 isAppearAbove ? "ライフアップアイテム[真上出現]" : "ライフアップアイテム[飛出し出現]";
175 break;
176 case ItemType::LifeUpItemBack:
177 name = "ライフアップアイテム[逆向き飛出し出現]";
178 break;
179 case ItemType::LifeMaxUpItem:
180 name = isAppearAbove ? "最大ライフアップアイテム[真上出現]" :
181 "最大ライフアップアイテム[飛出し出現]";
182 break;
183 case ItemType::AirBubble:
184 name = "空気泡";
185 break;
186 case ItemType::DotMarioCat:
187 name = al::isPercentProbability(10.0f) ? "ドットキャラクター(レア)" : "コイン[自動取得]";
188 break;
189 case ItemType::CoinStackBound:
190 name = "跳ねる積みコイン";
191 break;
192 default:
193 return false;
194 }
195
196 al::addItem(actor, info, name, 0);
197 return true;
198}
199
200void initItemByPlacementInfo(al::LiveActor* actor, const al::ActorInitInfo& info,
201 bool isAppearAbove) {
202 tryInitItemByPlacementInfo(actor, info, isAppearAbove);
203}
204
205bool tryInitItemByPlacementInfo(al::LiveActor* actor, const al::ActorInitInfo& info,
206 bool isAppearAbove) {
207 const char* itemType = nullptr;
208 if ((!al::tryGetStringArg(arg: &itemType, initInfo: info, key: "ItemType") &&
209 !al::tryGetStringArg(arg: &itemType, initInfo: info, key: "ItemTypeNoShine") &&
210 !al::tryGetStringArg(arg: &itemType, initInfo: info, key: "ItemType2D3D")) ||
211 al::isEqualString(str1: itemType, str2: "None"))
212 return false;
213
214 s32 type = getItemType(name: itemType);
215 if (type == ItemType::None || type == ItemType::Shine)
216 return false;
217
218 return tryInitItemAndAddToKeeper(actor, itemType: type, info, isAppearAbove);
219}
220
221void initItem2DByPlacementInfo(al::LiveActor* actor, const al::ActorInitInfo& info) {
222 tryInitItem2DByPlacementInfo(actor, info);
223}
224
225// https://decomp.me/scratch/QRKyC
226// NON_MATCHING: Extra comparison and the default return is placed in a different spot
227bool tryInitItem2DByPlacementInfo(al::LiveActor* actor, const al::ActorInitInfo& info) {
228 const char* itemType = nullptr;
229 if ((!al::tryGetStringArg(arg: &itemType, initInfo: info, key: "ItemType") &&
230 !al::tryGetStringArg(arg: &itemType, initInfo: info, key: "ItemTypeNoShine") &&
231 !al::tryGetStringArg(arg: &itemType, initInfo: info, key: "ItemType2D3D")) ||
232 al::isEqualString(str1: itemType, str2: "None"))
233 return false;
234
235 s32 type = getItemType(name: itemType);
236 if (type == ItemType::None || type == ItemType::Shine)
237 return false;
238
239 if (type == ItemType::Random) {
240 actor->initItemKeeper(itemAmount: 2);
241 al::addItem(actor, info, "ライフアップアイテム[飛出し出現]", "ライフアップ", nullptr, -1,
242 false);
243 al::addItem(actor, info, "コイン2D[自動取得]", "コイン", nullptr, -1, false);
244 return true;
245 }
246
247 actor->initItemKeeper(itemAmount: 1);
248 if (type <= ItemType::LifeMaxUpItem2D && type != ItemType::Coin &&
249 type != ItemType::CoinPopUp && type != ItemType::Coin10 && type != ItemType::LifeUpItem &&
250 type != ItemType::LifeUpItemBack && type != ItemType::LifeUpItem2D &&
251 type != ItemType::LifeMaxUpItem2D) {
252 al::addItem(actor, info, sItem2DNames[type], 0);
253 return true;
254 }
255 return false;
256}
257
258bool tryInitItem(al::LiveActor* actor, s32 itemType, const al::ActorInitInfo& info,
259 bool isAppearAbove) {
260 if (itemType == ItemType::None || itemType == ItemType::Shine)
261 return false;
262
263 return tryInitItemAndAddToKeeper(actor, itemType, info, isAppearAbove);
264}
265
266Shine* tryInitShineByPlacementInfoWithItemMenu(const al::ActorInitInfo& info) {
267 const char* itemType = nullptr;
268 if (!al::tryGetStringArg(arg: &itemType, initInfo: info, key: "ItemType") &&
269 !al::tryGetStringArg(arg: &itemType, initInfo: info, key: "ItemTypeNoShine") &&
270 !al::tryGetStringArg(arg: &itemType, initInfo: info, key: "ItemType2D3D"))
271 return nullptr;
272
273 if (al::isEqualString(str1: itemType, str2: "None") || getItemType(name: itemType) != ItemType::Shine)
274 return nullptr;
275
276 return initShineByPlacementInfo(info);
277}
278
279Shine* initShineByPlacementInfo(const al::ActorInitInfo& info) {
280 Shine* shine = new Shine("シャイン");
281 al::initCreateActorWithPlacementInfo(actor: shine, initInfo: info);
282 shine->makeActorDead();
283
284 return shine;
285}
286
287Shine* tryInitLinkShine(const al::ActorInitInfo& info, const char* name, s32 linkIndex) {
288 if (!al::isExistLinkChild(initInfo: info, linkName: name, index: linkIndex))
289 return nullptr;
290
291 Shine* shine = new Shine("シャイン");
292 al::initLinksActor(actor: shine, initInfo: info, suffix: name, linkIndex);
293 if (al::isEqualString(str1: name, str2: ShineFunction::getMovePointLinkName()))
294 shine->initAppearDemoFromHost(info, al::getTrans(actor: shine));
295 shine->makeActorDead();
296 return shine;
297}
298
299Shine* tryInitLinkShineHintPhoto(const al::ActorInitInfo& info, const char* name, s32 linkIndex) {
300 if (!al::isExistLinkChild(initInfo: info, linkName: name, index: linkIndex))
301 return nullptr;
302
303 Shine* shine = new Shine("シャイン");
304 shine->setHintPhotoShine(info);
305 al::initLinksActor(actor: shine, initInfo: info, suffix: name, linkIndex);
306 shine->makeActorDead();
307 return shine;
308}
309
310Shine* initLinkShine(const al::ActorInitInfo& info, const char* name, s32 linkIndex) {
311 return tryInitLinkShine(info, name, linkIndex);
312}
313
314Shine* initLinkShopShine(const al::ActorInitInfo& info, const char* name) {
315 if (!al::isExistLinkChild(initInfo: info, linkName: name, index: 0))
316 return nullptr;
317
318 Shine* shine = new Shine("シャイン");
319 shine->setShopShine();
320 al::initLinksActor(actor: shine, initInfo: info, suffix: name, linkIndex: 0);
321 if (al::isEqualString(str1: name, str2: ShineFunction::getMovePointLinkName()))
322 shine->initAppearDemoFromHost(info, al::getTrans(actor: shine));
323 shine->makeActorDead();
324 return shine;
325}
326
327Shine* initLinkShineChipShine(const al::ActorInitInfo& info) {
328 const char* str;
329 if (al::isExistLinkChild(initInfo: info, linkName: "ShineActor", index: 0))
330 str = "ShineActor";
331 else if (al::isExistLinkChild(initInfo: info, linkName: "ShineDotActor", index: 0))
332 str = "ShineDotActor";
333 else if (al::isExistLinkChild(initInfo: info, linkName: "ShineActorWithCamera", index: 0))
334 str = "ShineActorWithCamera";
335 else
336 return nullptr;
337
338 Shine* shine = new Shine("シャイン(シャインチップ)");
339 al::initLinksActor(actor: shine, initInfo: info, suffix: str, linkIndex: 0);
340 shine->makeActorDead();
341 return shine;
342}
343
344Shine* initLinkBossShine(const al::ActorInitInfo& info) {
345 return tryInitLinkShine(info, name: "ShineActor", linkIndex: 0);
346}
347
348void createShineEffectInsideObject(Shine* shine, const al::LiveActor* actor,
349 const al::ActorInitInfo& info) {
350 const char* str = actor->getName();
351 al::getObjectName(name: &str, initInfo: info);
352
353 if (al::isExistModel(actor))
354 str = al::getModelName(actor);
355
356 shine->createShineEffectInsideObject(info, al::getTrans(actor), str);
357}
358
359void appearPopupShine(Shine* shine) {
360 shine->appearPopup();
361}
362
363void appearPopupShine(Shine* shine, const al::LiveActor* actor) {
364 sead::Vector3f trans = al::getTrans(actor);
365 appearPopupShine(shine, trans);
366}
367
368void appearPopupShine(Shine* shine, const sead::Vector3f& trans) {
369 shine->appearPopup(trans);
370}
371
372void appearPopupShineWithoutDemo(Shine* shine) {
373 shine->appearPopupWithoutDemo();
374}
375
376void appearPopupShineWithoutDemo(Shine* shine, const al::LiveActor* actor) {
377 sead::Vector3f trans = al::getTrans(actor);
378 trans.y += 100.0f;
379 appearPopupShineWithoutDemo(shine, trans);
380}
381
382void appearPopupShineWithoutDemo(Shine* shine, const sead::Vector3f& trans) {
383 al::resetPosition(actor: shine, trans);
384 appearPopupShineWithoutDemo(shine);
385}
386
387void appearPopupShineWithoutWarp(Shine* shine) {
388 shine->appearPopupWithoutWarp();
389}
390
391// TODO rename a2 here and in header
392void appearPopupShineGrandByBoss(Shine* shine, s32 a2) {
393 shine->appearPopupGrandByBoss(a2);
394}
395
396void appearWaitShine(Shine* shine) {
397 shine->appearWait();
398}
399
400void appearWaitShine(Shine* shine, const sead::Vector3f& trans) {
401 shine->appearWait(trans);
402}
403
404bool isEndAppearShine(const Shine* shine) {
405 return shine->isEndAppear();
406}
407
408bool isGotShine(const Shine* shine) {
409 return shine->isGot();
410}
411
412bool isAliveShine(const Shine* shine) {
413 return al::isAlive(actor: shine);
414}
415
416bool isMainShine(const Shine* shine) {
417 return shine->isMainShine();
418}
419
420void updateHintTrans(const Shine* shine, const sead::Vector3f& trans) {
421 shine->updateHintTrans(trans);
422}
423
424void appearShineAndJoinBossDemo(Shine* shine, const char* name, const sead::Quatf& quat,
425 const sead::Vector3f& trans) {
426 shine->appearAndJoinBossDemo(name, quat, trans);
427}
428
429void endShineBossDemo(Shine* shine) {
430 shine->endBossDemo();
431}
432
433// TODO rename a2 here and in header
434void endShineBossDemoAndStartFall(Shine* shine, f32 a2) {
435 shine->endBossDemoAndStartFall(a2);
436}
437
438void setAppearItemFactorByMsg(const al::LiveActor* actor, const al::SensorMsg* msg,
439 const al::HitSensor* sensor) {
440 if (isMsgAttackDirect(msg))
441 al::setAppearItemFactor(actor, "直接攻撃", sensor);
442 else
443 al::setAppearItemFactor(actor, "間接攻撃", sensor);
444}
445
446const sead::Vector3f sItemOffset = {0.0f, 120.0f, 0.0f};
447
448void setAppearItemFactorAndOffsetByMsg(const al::LiveActor* actor, const al::SensorMsg* msg,
449 const al::HitSensor* sensor) {
450 setAppearItemFactorByMsg(actor, msg, sensor);
451
452 sead::Quatf quat = sead::Quatf::unit;
453 al::calcQuat(quat: &quat, actor);
454
455 sead::Vector3f offset = sItemOffset;
456 al::rotateVectorQuat(&offset, quat);
457
458 al::setAppearItemOffset(actor, offset);
459}
460
461void setAppearItemFactorAndOffsetForCombo(const al::LiveActor* actor, const al::SensorMsg* msg,
462 const al::HitSensor* sensor, bool isSuperCombo) {
463 if (isSuperCombo)
464 al::setAppearItemFactor(actor, "スーパーコンボ", sensor);
465 else
466 al::setAppearItemFactor(actor, "コンボ", sensor);
467
468 sead::Quatf quat = sead::Quatf::unit;
469 al::calcQuat(quat: &quat, actor);
470
471 sead::Vector3f offset = sItemOffset;
472 al::rotateVectorQuat(&offset, quat);
473
474 al::setAppearItemOffset(actor, offset);
475}
476
477void appearItemFromObj(al::LiveActor* actor, const sead::Vector3f& trans, const sead::Quatf& quat,
478 f32 offset) {
479 sead::Vector3f upDir = sead::Vector3f(0.0f, 0.0f, 0.0f);
480 al::calcUpDir(up: &upDir, actor);
481 al::setAppearItemOffset(actor, offset: upDir * offset);
482 al::appearItem(actor, trans, quat, sensor: nullptr);
483}
484
485void appearItemFromObj(al::LiveActor* actor, al::HitSensor* sensor, f32 offset) {
486 sead::Vector3f upDir = sead::Vector3f(0.0f, 0.0f, 0.0f);
487 al::calcUpDir(up: &upDir, actor);
488 al::setAppearItemOffset(actor, offset: upDir * offset);
489 al::setAppearItemAttackerSensor(actor, sensor);
490 al::appearItem(actor);
491}
492
493void appearItemFromObj(al::LiveActor* actor, al::HitSensor* sensor, const sead::Vector3f& offset) {
494 sead::Vector3f localOffset;
495 al::calcTransLocalOffset(transOut: &localOffset, actor, transIn: offset);
496 al::setAppearItemOffset(actor, offset: localOffset - al::getTrans(actor));
497 al::setAppearItemAttackerSensor(actor, sensor);
498 al::appearItem(actor);
499}
500
501void appearItemFromObjGravity(al::LiveActor* actor, al::HitSensor* sensor,
502 const sead::Vector3f& offset) {
503 sead::Vector3f localOffset;
504 al::calcTransLocalOffset(transOut: &localOffset, actor, transIn: offset);
505 al::setAppearItemOffset(actor, offset: localOffset - al::getTrans(actor));
506 al::setAppearItemAttackerSensor(actor, sensor);
507
508 sead::Vector3f frontDir;
509 al::calcFrontDir(front: &frontDir, actor);
510
511 sead::Quatf quat;
512 if (al::isParallelDirection(a: frontDir, b: -al::getGravity(actor), tolerance: 0.01f))
513 al::makeQuatUpFront(outQuat: &quat, up: -al::getGravity(actor), front: sead::Vector3f::ez);
514 else
515 al::makeQuatUpFront(outQuat: &quat, up: -al::getGravity(actor), front: frontDir);
516
517 al::appearItem(actor, al::getTrans(actor), quat, sensor: nullptr);
518}
519
520// TODO: Requires RandomItemSelector
521// void appearRandomItemFromObj(al::LiveActor* actor, al::HitSensor* sensor, f32 offset) {}
522
523bool tryAppearMultiCoinFromObj(al::LiveActor* actor, const sead::Vector3f& trans, s32 step,
524 f32 offsetAbove) {
525 return tryAppearMultiCoinFromObj(actor, trans, quat: sead::Quatf::unit, step, offsetAbove);
526}
527
528bool tryAppearMultiCoinFromObj(al::LiveActor* actor, const sead::Vector3f& trans,
529 const sead::Quatf& quat, s32 step, f32 offsetAbove) {
530 if (step % 10 != 0)
531 return false;
532
533 sead::Vector3f upDir = sead::Vector3f(0.0f, 0.0f, 0.0f);
534 al::calcUpDir(up: &upDir, actor);
535
536 al::setAppearItemOffset(actor, offset: upDir * offsetAbove);
537 al::appearItem(actor, trans, quat, sensor: nullptr);
538 return true;
539}
540
541bool tryAppearMultiCoinFromObj(al::LiveActor* actor, al::HitSensor* sensor, s32 step,
542 f32 offsetAbove) {
543 if (step % 10 != 0)
544 return false;
545
546 sead::Vector3f upDir = sead::Vector3f(0.0f, 0.0f, 0.0f);
547 al::calcUpDir(up: &upDir, actor);
548
549 al::setAppearItemOffset(actor, offset: upDir * offsetAbove);
550 al::setAppearItemAttackerSensor(actor, sensor);
551 al::appearItem(actor);
552 return true;
553}
554
555bool tryAppearMultiCoinFromObj(al::LiveActor* actor, al::HitSensor* sensor, s32 step,
556 const sead::Vector3f& offset) {
557 if (step % 10 != 0)
558 return false;
559
560 sead::Vector3f localOffset;
561 al::calcTransLocalOffset(transOut: &localOffset, actor, transIn: offset);
562
563 al::setAppearItemOffset(actor, offset: localOffset - al::getTrans(actor));
564 al::setAppearItemAttackerSensor(actor, sensor);
565 al::appearItem(actor);
566 return true;
567}
568
569void syncCoin2DAnimFrame(al::LiveActor* actor, const char* name) {
570 if (al::isActionPlaying(actor, actionName: name)) {
571 al::StageSyncCounter* obj = al::getSceneObj<al::StageSyncCounter>(user: actor);
572 al::setVisAnimFrameForAction(actor,
573 obj->getCounter() % (s32)al::getVisAnimFrameMax(actor, name));
574 }
575}
576
577const char* getStageCoinCollectArchiveName(const al::LiveActor* actor) {
578 return al::getSceneObj<GameDataHolder>(user: actor)->getCoinCollectArchiveName(
579 worldId: GameDataFunction::getCurrentWorldId(accessor: actor));
580}
581
582const char* getStageCoinCollectEmptyArchiveName(const al::LiveActor* actor) {
583 return al::getSceneObj<GameDataHolder>(user: actor)->getCoinCollectEmptyArchiveName(
584 worldId: GameDataFunction::getCurrentWorldId(accessor: actor));
585}
586
587const char* getStageCoinCollect2DArchiveName(const al::LiveActor* actor) {
588 return al::getSceneObj<GameDataHolder>(user: actor)->getCoinCollect2DArchiveName(
589 worldId: GameDataFunction::getCurrentWorldId(accessor: actor));
590}
591
592const char* getStageCoinCollect2DEmptyArchiveName(const al::LiveActor* actor) {
593 return al::getSceneObj<GameDataHolder>(user: actor)->getCoinCollect2DEmptyArchiveName(
594 worldId: GameDataFunction::getCurrentWorldId(accessor: actor));
595}
596
597s32 getStageShineAnimFrame(const al::LiveActor* actor) {
598 return al::getSceneObj<GameDataHolder>(user: actor)->getShineAnimFrame(
599 worldId: GameDataFunction::getCurrentWorldId(accessor: actor));
600}
601
602s32 getStageShineAnimFrame(const al::LiveActor* actor, s32 worldId) {
603 return al::getSceneObj<GameDataHolder>(user: actor)->getShineAnimFrame(worldId);
604}
605
606s32 getStageShineAnimFrame(const al::LiveActor* actor, const char* stageName) {
607 s32 worldId =
608 al::getSceneObj<GameDataHolder>(user: actor)->getWorldList()->tryFindWorldIndexByMainStageName(
609 stageName);
610 worldId = sead::Mathi::max(a: 0, b: worldId);
611
612 return getStageShineAnimFrame(actor, worldId);
613}
614
615void startShineAnimAndSetFrameAndStop(al::LiveActor* actor, const char* animName, s32 frame,
616 bool isMatAnim) {
617 isMatAnim ? al::startMtpAnimAndSetFrameAndStop(actor, animName, frame) :
618 al::startMclAnimAndSetFrameAndStop(actor, animName, frame);
619}
620
621void setStageShineAnimFrame(al::LiveActor* actor, const char* stageName, s32 shineAnimFrame,
622 bool isMatAnim) {
623 if (shineAnimFrame != -1) {
624 if (shineAnimFrame == 99)
625 return;
626 return startShineAnimAndSetFrameAndStop(actor, animName: "Color", frame: shineAnimFrame, isMatAnim);
627 }
628 if (stageName) {
629 shineAnimFrame = getStageShineAnimFrame(actor, stageName);
630 return startShineAnimAndSetFrameAndStop(actor, animName: "Color", frame: shineAnimFrame, isMatAnim);
631 }
632 shineAnimFrame = getStageShineAnimFrame(actor);
633 if (shineAnimFrame != -1)
634 startShineAnimAndSetFrameAndStop(actor, animName: "Color", frame: shineAnimFrame, isMatAnim);
635}
636
637const char* getStageShineArchiveName(const al::LiveActor* actor, const char* stageName) {
638 s32 worldId =
639 al::getSceneObj<GameDataHolder>(user: actor)->getWorldList()->tryFindWorldIndexByMainStageName(
640 stageName);
641
642 return worldId == GameDataFunction::getWorldIndexPeach() ? "PowerStar" : "Shine";
643}
644
645const char* getStageShineEmptyArchiveName(const al::LiveActor* actor, const char* stageName) {
646 s32 worldId =
647 al::getSceneObj<GameDataHolder>(user: actor)->getWorldList()->tryFindWorldIndexByMainStageName(
648 stageName);
649
650 return worldId == GameDataFunction::getWorldIndexPeach() ? "PowerStarEmpty" : "ShineEmpty";
651}
652
653void setMaterialAsEmptyModel(al::LiveActor* actor) {
654 al::setModelAlphaMask(actor, 0.499f);
655}
656
657void setProjectionMtxAsEmptyModel2d(al::LiveActor* actor, const sead::Vector2f& vec) {
658 sead::Matrix44f matrix = sead::Matrix44f::ident;
659
660 sead::Vector3f frontDir = sead::Vector3f::zero;
661 sead::Vector3f upDir = sead::Vector3f::zero;
662
663 al::calcFrontDir(front: &frontDir, actor);
664 al::calcUpDir(up: &upDir, actor);
665
666 al::makeMtxProj(&matrix, vec, frontDir, upDir);
667
668 const sead::Vector3f& trans = al::getTrans(actor);
669 matrix.setCol(axis: 3, v: sead::Vector4f(trans.x, trans.y, trans.z, 1.0f));
670 al::setModelProjMtx0(actor->getModelKeeper(), matrix);
671}
672
673// void addDemoRacePrizeCoin(al::LiveActor* actor); TODO
674
675} // namespace rs
676
677namespace StageSceneFunction {
678// void appearPlayerDeadCoin(al::LiveActor* actor); TODO
679
680} // namespace StageSceneFunction
681