1#include "Npc/ShineTowerNpc.h"
2
3#include <prim/seadSafeString.h>
4
5#include "Library/LiveActor/ActorInitUtil.h"
6#include "Library/LiveActor/ActorModelFunction.h"
7#include "Library/LiveActor/ActorMovementFunction.h"
8#include "Library/Math/MathUtil.h"
9#include "Library/Message/MessageHolder.h"
10#include "Library/Message/MessageTagDataHolder.h"
11#include "Library/Nerve/NerveSetupUtil.h"
12#include "Library/Nerve/NerveUtil.h"
13#include "Library/Player/PlayerUtil.h"
14
15#include "System/GameDataFunction.h"
16#include "Util/NpcEventFlowUtil.h"
17
18namespace {
19NERVE_IMPL(ShineTowerNpc, Wait);
20NERVE_IMPL(ShineTowerNpc, GoKoopa);
21NERVE_IMPL(ShineTowerNpc, NoBalloon);
22
23NERVES_MAKE_STRUCT(ShineTowerNpc, Wait, GoKoopa);
24NERVES_MAKE_NOSTRUCT(ShineTowerNpc, NoBalloon);
25} // namespace
26
27ShineTowerNpc::ShineTowerNpc(const char* name) : al::LiveActor(name) {}
28
29void ShineTowerNpc::init(const al::ActorInitInfo& actorInitInfo) {
30 al::initActorWithArchiveName(actor: this, initInfo: actorInitInfo, archiveName: "NpcCap", suffix: nullptr);
31 al::initNerve(actor: this, nerve: &NrvShineTowerNpc.Wait, maxStates: 0);
32 mEventFlowExecutor = rs::initEventFlow(this, actorInitInfo, "HomeMechanicNpc", nullptr);
33 al::MessageTagDataHolder* msgTagDataHolder = al::initMessageTagDataHolder(1);
34 al::registerMessageTagDataScore(msgTagDataHolder, "Score", &mRemainingShineCount);
35 rs::initEventMessageTagDataHolder(mEventFlowExecutor, msgTagDataHolder);
36
37 makeActorAlive();
38 al::hideModel(actor: this);
39 mRemainingShineCount = getRemainingShineCount(actor: this);
40 if (mRemainingShineCount == 0)
41 al::setNerve(user: this, nerve: &NrvShineTowerNpc.GoKoopa);
42}
43
44s32 getRemainingShineCount(al::LiveActor* actor) {
45 bool isGameClear = false;
46 s32 unlockShine = GameDataFunction::findUnlockShineNum(isGameClear: &isGameClear, accessor: actor);
47 s32 payShine = GameDataFunction::getPayShineNum(accessor: actor);
48 if (isGameClear)
49 payShine = GameDataFunction::getTotalPayShineNum(accessor: actor);
50
51 return sead::Mathi::max(a: 0, b: unlockShine - payShine);
52}
53
54void ShineTowerNpc::noBalloon() {
55 al::setNerve(user: this, nerve: &NoBalloon);
56}
57
58void ShineTowerNpc::startBalloon() {
59 mRemainingShineCount = getRemainingShineCount(actor: this);
60 if (mRemainingShineCount == 0)
61 al::setNerve(user: this, nerve: &NrvShineTowerNpc.GoKoopa);
62 else
63 al::setNerve(user: this, nerve: &NrvShineTowerNpc.Wait);
64}
65
66void ShineTowerNpc::exeWait() {
67 if (al::isFirstStep(user: this)) {
68 sead::FixedSafeString<0x40> string;
69 string.format(formatStr: "RestShineNum");
70 rs::startEventFlow(mEventFlowExecutor, string.cstr());
71 }
72
73 al::turnToTarget(actor: this, target: al::getPlayerActor(this, 0), deg: 2.0f);
74 mRemainingShineCount = getRemainingShineCount(actor: this);
75 if (mRemainingShineCount == 0) {
76 al::setNerve(user: this, nerve: &NrvShineTowerNpc.GoKoopa);
77 return;
78 }
79 rs::updateEventFlow(mEventFlowExecutor);
80}
81
82void ShineTowerNpc::exeGoKoopa() {
83 if (al::isFirstStep(user: this))
84 rs::startEventFlow(mEventFlowExecutor, "GoKoopa");
85
86 al::turnToTarget(actor: this, target: al::getPlayerActor(this, 0), deg: 2.0f);
87 rs::updateEventFlow(mEventFlowExecutor);
88}
89
90void ShineTowerNpc::exeNoBalloon() {
91 mRemainingShineCount = getRemainingShineCount(actor: this);
92}
93