1#include "MapObj/Souvenir.h"
2
3#include <math/seadVector.h>
4
5#include "Library/LiveActor/ActorActionFunction.h"
6#include "Library/LiveActor/ActorInitInfo.h"
7#include "Library/LiveActor/ActorInitUtil.h"
8#include "Library/LiveActor/ActorMovementFunction.h"
9#include "Library/LiveActor/ActorPoseUtil.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
16#include "Util/SensorMsgFunction.h"
17
18namespace {
19NERVE_IMPL(Souvenir, Wait);
20NERVE_IMPL(Souvenir, ReactionCap);
21
22NERVES_MAKE_STRUCT(Souvenir, Wait, ReactionCap);
23} // namespace
24
25Souvenir::Souvenir(const char* name) : al::LiveActor(name) {}
26
27// Non-matching: regswap (https://decomp.me/scratch/8qJEm)
28void Souvenir::init(const al::ActorInitInfo& actorInitInfo) {
29 const char* suffix = nullptr;
30 al::tryGetStringArg(arg: &suffix, initInfo: actorInitInfo, key: "Suffix");
31 al::initMapPartsActor(actor: this, initInfo: actorInitInfo, suffix);
32 al::tryGetArg(arg: &mIsReactionPlayerUpperPunch, initInfo: actorInitInfo, key: "IsReactionPlayerUpperPunch");
33 al::tryGetArg(arg: &mIsThroughCapAttack, initInfo: actorInitInfo, key: "IsThroughCapAttack");
34 al::tryGetArg(arg: &mRotateYSpeed, initInfo: actorInitInfo, key: "RotateYSpeed");
35 al::initNerve(actor: this, nerve: &NrvSouvenir.Wait, maxStates: 0);
36 makeActorAlive();
37}
38
39void Souvenir::control() {
40 if (mRotateYSpeed != 0.0f) {
41 sead::Quatf* quat = al::getQuatPtr(actor: this);
42 al::rotateQuatYDirDegree(quat, *quat, mRotateYSpeed);
43 }
44}
45
46void Souvenir::attackSensor(al::HitSensor* self, al::HitSensor* other) {
47 if (!mIsThroughCapAttack && al::isSensorMapObj(self))
48 rs::sendMsgPushToPlayer(source: other, target: self);
49}
50
51bool Souvenir::receiveMsg(const al::SensorMsg* msg, al::HitSensor* self, al::HitSensor* other) {
52 if (al::isMsgPlayerDisregard(msg) || rs::isMsgPlayerDisregardHomingAttack(msg) ||
53 rs::isMsgPlayerDisregardTargetMarker(msg))
54 return true;
55
56 if (rs::isMsgCapTouchWall(msg) || rs::isMsgCapAttack(msg) || al::isMsgPlayerTrample(msg) ||
57 rs::isMsgPlayerAndCapHipDropAll(msg) || rs::isMsgPlayerAndCapObjHipDropAll(msg) ||
58 (al::isMsgPlayerObjUpperPunch(msg) && mIsReactionPlayerUpperPunch) ||
59 al::isMsgPlayerRollingAttack(msg) || al::isMsgPlayerObjRollingAttack(msg)) {
60 if (!al::isExistAction(actor: this, actionName: "ReactionCap"))
61 return false;
62
63 const sead::Vector3f& velocity = al::getVelocity(actor: al::getSensorHost(self));
64 if (!rs::isMsgCapAttack(msg) && velocity.length() < 5.0f)
65 return false;
66
67 if (!al::isNerve(user: this, nerve: &NrvSouvenir.Wait) &&
68 (!al::isNerve(user: this, nerve: &NrvSouvenir.ReactionCap) || !al::isGreaterStep(user: this, step: 10)))
69 return false;
70
71 al::setNerve(user: this, nerve: &NrvSouvenir.ReactionCap);
72 if (mIsThroughCapAttack &&
73 (rs::isMsgCapAttack(msg) || al::isMsgPlayerObjUpperPunch(msg) ||
74 al::isMsgPlayerTrample(msg) || rs::isMsgPlayerAndCapHipDropAll(msg) ||
75 rs::isMsgPlayerAndCapObjHipDropAll(msg)))
76 return false;
77
78 if (!rs::isMsgPlayerAndCapHipDropAll(msg) && !rs::isMsgPlayerAndCapObjHipDropAll(msg))
79 al::startHitReactionHitEffect(actor: this, name: "ヒット[小]", other: self, self: other);
80 else
81 al::startHitReactionHitEffect(actor: this, name: "ヒット", other: self, self: other);
82 return true;
83 }
84
85 return false;
86}
87
88void Souvenir::exeWait() {
89 if (al::isFirstStep(user: this)) {
90 if (((al::isExistAction(actor: this, actionName: "ReactionCap") && al::isActionPlaying(actor: this, actionName: "ReactionCap")) ||
91 (al::isExistAction(actor: this, actionName: "ReactionCap1") &&
92 al::isActionPlaying(actor: this, actionName: "ReactionCap1")) ||
93 (al::isExistAction(actor: this, actionName: "ReactionCap2") &&
94 al::isActionPlaying(actor: this, actionName: "ReactionCap2")) ||
95 (al::isExistAction(actor: this, actionName: "ReactionCap3") &&
96 al::isActionPlaying(actor: this, actionName: "ReactionCap3")) ||
97 (al::isExistAction(actor: this, actionName: "ReactionCap4") &&
98 al::isActionPlaying(actor: this, actionName: "ReactionCap4"))) &&
99 getNextAction() != nullptr)
100 return;
101
102 if (mIsWait) {
103 al::tryStartAction(actor: this, actionName: "Wait");
104 return;
105 }
106
107 if (al::isExistAction(actor: this, actionName: "WaitShop")) {
108 al::startActionAtRandomFrame(actor: this, actionName: "WaitShop");
109 return;
110 }
111 if (al::isExistAction(actor: this, actionName: "Shop")) {
112 al::startActionAtRandomFrame(actor: this, actionName: "Wait");
113 return;
114 }
115 }
116}
117
118inline const char* Souvenir::getNextAction() {
119 if (al::isActionPlaying(actor: this, actionName: "Wait")) {
120 if (!al::isExistAction(actor: this, actionName: "ReactionCap"))
121 return nullptr;
122
123 return "ReactionCap";
124 } else if (al::isActionPlaying(actor: this, actionName: "ReactionCap")) {
125 if (!al::isExistAction(actor: this, actionName: "ReactionCap1"))
126 return nullptr;
127
128 return "ReactionCap1";
129 } else if (al::isActionPlaying(actor: this, actionName: "ReactionCap1")) {
130 if (!al::isExistAction(actor: this, actionName: "ReactionCap2"))
131 return nullptr;
132
133 return "ReactionCap2";
134 } else if (al::isActionPlaying(actor: this, actionName: "ReactionCap2")) {
135 if (!al::isExistAction(actor: this, actionName: "ReactionCap3"))
136 return nullptr;
137
138 return "ReactionCap3";
139 } else if (al::isActionPlaying(actor: this, actionName: "ReactionCap3")) {
140 if (!al::isExistAction(actor: this, actionName: "ReactionCap4"))
141 return nullptr;
142
143 return "ReactionCap4";
144 } else if (al::isActionPlaying(actor: this, actionName: "ReactionCap4"))
145 return nullptr;
146
147 if (!al::isExistAction(actor: this, actionName: "ReactionCap"))
148 return nullptr;
149
150 return "ReactionCap";
151}
152
153void Souvenir::exeReactionCap() {
154 if (al::isFirstStep(user: this))
155 al::startAction(actor: this, actionName: getNextAction() ?: "ReactionCap");
156
157 if (al::isActionEnd(actor: this))
158 al::setNerve(user: this, nerve: &NrvSouvenir.Wait);
159}
160