1#include "Library/MapObj/GateMapParts.h"
2
3#include "Library/Audio/System/SimpleAudioUser.h"
4#include "Library/Base/StringUtil.h"
5#include "Library/LiveActor/ActorActionFunction.h"
6#include "Library/LiveActor/ActorClippingFunction.h"
7#include "Library/LiveActor/ActorInitFunction.h"
8#include "Library/LiveActor/ActorInitUtil.h"
9#include "Library/LiveActor/ActorPoseUtil.h"
10#include "Library/Math/MathUtil.h"
11#include "Library/Nerve/NerveSetupUtil.h"
12#include "Library/Nerve/NerveUtil.h"
13#include "Library/Placement/PlacementFunction.h"
14#include "Library/Se/SeFunction.h"
15#include "Library/Stage/StageSwitchUtil.h"
16#include "Library/Thread/FunctorV0M.h"
17
18namespace {
19using namespace al;
20
21NERVE_ACTION_IMPL(GateMapParts, Wait)
22NERVE_ACTION_IMPL(GateMapParts, Open)
23NERVE_ACTION_IMPL(GateMapParts, Bound)
24NERVE_ACTION_IMPL(GateMapParts, End)
25
26NERVE_ACTIONS_MAKE_STRUCT(GateMapParts, Wait, Open, Bound, End)
27} // namespace
28
29namespace al {
30GateMapParts::GateMapParts(const char* name) : LiveActor(name) {}
31
32void GateMapParts::init(const ActorInitInfo& info) {
33 using GateMapPartsFunctor = FunctorV0M<GateMapParts*, void (GateMapParts::*)()>;
34
35 initNerveAction(actor: this, actionName: "Wait", collector: &NrvGateMapParts.collector, maxStates: 0);
36 initMapPartsActor(actor: this, initInfo: info, suffix: nullptr);
37 tryGetQuatPtr(actor: this);
38
39 mTrans = getTrans(actor: this);
40 mQuat = getQuat(actor: this);
41
42 tryGetLinksTrans(trans: &mMoveNextTrans, initInfo: info, linkName: "MoveNext");
43 tryGetLinksQuat(quat: &mMoveNextQuat, initInfo: info, linkName: "MoveNext");
44
45 tryGetArg(arg: &mOpenTime, initInfo: info, key: "OpenTime");
46 tryGetArg(arg: &mBoundRate, initInfo: info, key: "BoundRate");
47 tryGetArg(arg: &mHitReactionCount, initInfo: info, key: "HitReactionCount");
48
49 listenStageSwitchOnStart(user: this, action: GateMapPartsFunctor(this, &GateMapParts::start));
50
51 bool isPlaySuccessSe = false;
52 tryGetArg(arg: &isPlaySuccessSe, initInfo: info, key: "IsPlaySuccessSe");
53
54 if (isPlaySuccessSe)
55 mSuccessSeObj = new SimpleAudioUser("SuccessSeObj", info);
56
57 makeActorAlive();
58}
59
60void GateMapParts::start() {
61 if (!isNerve(user: this, nerve: NrvGateMapParts.Wait.data()))
62 return;
63
64 appearAndSetStart();
65}
66
67void GateMapParts::appearAndSetStart() {
68 invalidateClipping(actor: this);
69 startNerveAction(actor: this, actionName: "Open");
70}
71
72void GateMapParts::exeWait() {
73 if (isFirstStep(user: this))
74 validateClipping(actor: this);
75}
76
77void GateMapParts::exeOpen() {
78 updatePose(rate: calcNerveSquareInRate(user: this, max: mOpenTime - 1));
79
80 if (isGreaterEqualStep(user: this, step: mOpenTime - 1)) {
81 mCurrentBoundRate = mBoundRate;
82 mCurrentBoundSteps = (s32)(mBoundRate * (f32)mOpenTime * 2);
83 mHitReactionCurrent = 0;
84
85 if (mMaxHitReactions > mHitReactionCurrent && mCurrentBoundSteps > 1) {
86 startNerveAction(actor: this, actionName: "Bound");
87
88 return;
89 }
90
91 if (mSuccessSeObj != nullptr)
92 startSe(mSuccessSeObj, "Riddle");
93
94 startNerveAction(actor: this, actionName: "End");
95
96 if (mHitReactionCount < 2)
97 startHitReaction(actor: this, name: "バウンド1回目");
98 }
99}
100
101void GateMapParts::updatePose(f32 rate) {
102 rate = sead::Mathf::clamp(value: rate, low: 0.0f, high: 1.0f);
103
104 lerpVec(getTransPtr(actor: this), mTrans, mMoveNextTrans, rate);
105 slerpQuat(getQuatPtr(actor: this), mQuat, mMoveNextQuat, rate);
106}
107
108void GateMapParts::exeBound() {
109 if (isFirstStep(user: this)) {
110 if (mHitReactionCurrent++ < mHitReactionCount)
111 startHitReaction(actor: this, name: StringTmp<32>("バウンド%d回目", mHitReactionCurrent).cstr());
112
113 tryStartSeWithParam(this, "BoundStart", (f32)(mMaxHitReactions - mHitReactionCurrent), "");
114 }
115
116 f32 rate = calcNerveRate(user: this, max: mCurrentBoundSteps - 1);
117 rate = sead::Mathf::pow(x: mCurrentBoundRate * (rate * 2 - 1.0f), y: 2);
118 rate += (1.0f - sead::Mathf::pow(x: mCurrentBoundRate, y: 2));
119
120 updatePose(rate);
121
122 if (isGreaterEqualStep(user: this, step: mCurrentBoundSteps - 1)) {
123 mCurrentBoundRate *= mBoundRate;
124 mCurrentBoundSteps = (s32)(mBoundRate * (f32)mCurrentBoundSteps);
125
126 if (mMaxHitReactions > mHitReactionCurrent && mCurrentBoundSteps > 1) {
127 startNerveAction(actor: this, actionName: "Bound");
128
129 return;
130 }
131
132 if (mSuccessSeObj != nullptr)
133 startSe(mSuccessSeObj, "Riddle");
134
135 startNerveAction(actor: this, actionName: "End");
136 }
137}
138
139void GateMapParts::exeEnd() {
140 if (isFirstStep(user: this)) {
141 validateClipping(actor: this);
142 updatePose(rate: 1.0f);
143 }
144}
145} // namespace al
146