1#include "MapObj/TrampleSwitch.h"
2
3#include "Library/Camera/CameraUtil.h"
4#include "Library/Collision/PartsConnector.h"
5#include "Library/Demo/DemoFunction.h"
6#include "Library/LiveActor/ActorActionFunction.h"
7#include "Library/LiveActor/ActorClippingFunction.h"
8#include "Library/LiveActor/ActorCollisionFunction.h"
9#include "Library/LiveActor/ActorInitFunction.h"
10#include "Library/LiveActor/ActorInitUtil.h"
11#include "Library/LiveActor/ActorPoseUtil.h"
12#include "Library/LiveActor/ActorSensorUtil.h"
13#include "Library/Math/MathUtil.h"
14#include "Library/Nerve/NerveSetupUtil.h"
15#include "Library/Nerve/NerveUtil.h"
16#include "Library/Obj/CollisionObj.h"
17#include "Library/Obj/PartsFunction.h"
18#include "Library/Placement/PlacementFunction.h"
19#include "Library/Stage/StageSwitchUtil.h"
20#include "Library/Thread/FunctorV0M.h"
21
22#include "MapObj/AppearSwitchSave.h"
23#include "Util/DemoUtil.h"
24#include "Util/SensorMsgFunction.h"
25
26namespace {
27NERVE_IMPL(TrampleSwitch, OffWait);
28NERVE_IMPL(TrampleSwitch, OnWait);
29NERVE_IMPL(TrampleSwitch, On);
30NERVE_IMPL(TrampleSwitch, Off);
31NERVE_IMPL(TrampleSwitch, OnDemoWaitStart);
32NERVE_IMPL(TrampleSwitch, OnDemo);
33
34NERVES_MAKE_NOSTRUCT(TrampleSwitch, OnDemo);
35NERVES_MAKE_STRUCT(TrampleSwitch, OffWait, OnWait, On, Off, OnDemoWaitStart);
36} // namespace
37
38TrampleSwitch::TrampleSwitch(const char* actorName) : al::LiveActor(actorName) {}
39
40void TrampleSwitch::init(const al::ActorInitInfo& info) {
41 al::initActorWithArchiveName(actor: this, initInfo: info, archiveName: "TrampleSwitch", suffix: nullptr);
42 al::initNerve(actor: this, nerve: &NrvTrampleSwitch.OffWait, maxStates: 0);
43
44 mMtxConnector = al::createMtxConnector(actor: this);
45 mAddDemoInfo = al::registDemoRequesterToAddDemoInfo(actor: this, initInfo: info, index: 0);
46 mIsFacingUp = al::isNearZeroOrLess(value: al::calcQuatUpY(al::getQuat(actor: this)));
47
48 mCollisionBody = al::createCollisionObj(parent: this, info, collisionFileName: "TrampleSwitch_Body",
49 hitSensor: al::getHitSensor(this, "PPanel"), joinMtxName: nullptr, suffix: nullptr);
50 mCollisionBody->makeActorAlive();
51 al::validateCollisionParts(mCollisionBody);
52
53 if (al::isObjectName(initInfo: info, name: "TrampleSwitchSave")) {
54 mAppearSwitchSave = new AppearSwitchSave(this, info);
55 if (mAppearSwitchSave->isOn()) {
56 al::invalidateClipping(actor: this);
57 al::setNerve(user: this, nerve: &NrvTrampleSwitch.OnWait);
58 }
59 if (mAppearSwitchSave->isOn())
60 al::tryOnStageSwitch(user: this, linkName: "SwitchPermanentOn");
61 else
62 al::tryOffStageSwitch(user: this, linkName: "SwitchPermanentOn");
63 } else {
64 using TrampleSwitchFunctor = al::FunctorV0M<TrampleSwitch*, void (TrampleSwitch::*)()>;
65
66 al::listenStageSwitchOff(user: this, eventName: "SwitchTrampleOn",
67 action: TrampleSwitchFunctor(this, &TrampleSwitch::offSwitch));
68 al::listenStageSwitchOn(user: this, eventName: "SwitchReset",
69 action: TrampleSwitchFunctor(this, &TrampleSwitch::resetSwitch));
70
71 if (al::tryGetBoolArgOrFalse(initInfo: info, key: "IsValidObjectCamera"))
72 mDemoCamera = al::initDemoObjectCamera(user: this, actorInitInfo: info, nullptr, "固定");
73 }
74 makeActorAlive();
75}
76
77void TrampleSwitch::offSwitch() {
78 if (al::isNerve(user: this, nerve: &NrvTrampleSwitch.On) || isOn()) {
79 al::invalidateClipping(actor: this);
80 al::setNerve(user: this, nerve: &NrvTrampleSwitch.Off);
81 }
82}
83
84void TrampleSwitch::resetSwitch() {
85 al::setNerve(user: this, nerve: &NrvTrampleSwitch.OffWait);
86 al::offStageSwitch(user: this, linkName: "SwitchTrampleOn");
87}
88
89void TrampleSwitch::initAfterPlacement() {
90 al::attachMtxConnectorToCollision(mtxConnector: mMtxConnector, actor: this, false);
91}
92
93void TrampleSwitch::control() {
94 al::connectPoseQT(actor: this, mtxConnector: mMtxConnector);
95}
96
97void TrampleSwitch::exeOffWait() {
98 if (al::isFirstStep(user: this)) {
99 al::validateClipping(actor: this);
100 al::startAction(actor: this, actionName: "OffWait");
101 }
102}
103
104void TrampleSwitch::exeOn() {
105 if (al::isFirstStep(user: this)) {
106 al::tryOnStageSwitch(user: this, linkName: "SwitchPermanentOn");
107 al::startAction(actor: this, actionName: "On");
108 }
109 if (al::isActionEnd(actor: this)) {
110 if (mDemoCamera) {
111 al::setNerve(user: this, nerve: &NrvTrampleSwitch.OnDemoWaitStart);
112 return;
113 }
114
115 if (mAppearSwitchSave)
116 mAppearSwitchSave->onSwitch();
117 else
118 al::tryOnStageSwitch(user: this, linkName: "SwitchTrampleOn");
119
120 al::setNerve(user: this, nerve: &NrvTrampleSwitch.OnWait);
121 }
122}
123
124void TrampleSwitch::exeOnDemoWaitStart() {
125 if (rs::requestStartDemoNormal(this, false)) {
126 if (mAppearSwitchSave)
127 mAppearSwitchSave->onSwitchDemo();
128 else {
129 al::tryOnStageSwitch(user: this, linkName: "SwitchTrampleOn");
130 al::tryOnStageSwitch(user: this, linkName: "SwitchPermanentOn");
131 }
132 al::startCamera(user: this, ticket: mDemoCamera);
133 al::addDemoActorFromAddDemoInfo(actor: this, info: mAddDemoInfo);
134 al::setNerve(user: this, nerve: &OnDemo);
135 }
136}
137
138void TrampleSwitch::exeOnDemo() {
139 if (al::isGreaterEqualStep(user: this, step: 150)) {
140 al::endCamera(user: this, ticket: mDemoCamera, -1, 0);
141 rs::requestEndDemoNormal(this);
142 al::setNerve(user: this, nerve: &NrvTrampleSwitch.OnWait);
143 }
144}
145
146void TrampleSwitch::exeOnWait() {
147 if (al::isFirstStep(user: this)) {
148 al::validateClipping(actor: this);
149 al::invalidateHitSensors(this);
150 al::startAction(actor: this, actionName: "OnWait");
151 }
152}
153
154void TrampleSwitch::exeOff() {
155 if (al::isFirstStep(user: this))
156 al::startAction(actor: this, actionName: "Off");
157 if (al::isActionEnd(actor: this))
158 al::setNerve(user: this, nerve: &NrvTrampleSwitch.OffWait);
159}
160
161bool TrampleSwitch::isOn() const {
162 return al::isNerve(user: this, nerve: &NrvTrampleSwitch.OnWait);
163}
164
165// NON_MATCHING: extra register used for the last comparsion, https://decomp.me/scratch/HyCSL
166bool TrampleSwitch::receiveMsg(const al::SensorMsg* message, al::HitSensor* other,
167 al::HitSensor* self) {
168 if (al::isNerve(user: this, nerve: &NrvTrampleSwitch.Off))
169 return false;
170 if (al::isSensorName(self, "PlayerRegard")) {
171 if (!mIsFacingUp && rs::isMsgPlayerDisregardTargetMarker(message))
172 return true;
173 return false;
174 }
175 if (mIsFacingUp && !al::isSensorName(self, "PPanel"))
176 return false;
177
178 bool v10 = (rs::isMsgCapTouchWall(message) || rs::isMsgCapAttackCollide(message)) &&
179 (mIsFacingUp || !al::isNearZeroOrGreater(value: al::getActorVelocity(other).y));
180 bool v11 = rs::isMsgCapHipDrop(message);
181 bool v12 = al::isMsgPlayerTouch(msg: message);
182
183 if (v12 || v10 || v11)
184 return trySetNerveOn();
185
186 return false;
187}
188
189bool TrampleSwitch::trySetNerveOn() {
190 if (al::isNerve(user: this, nerve: &NrvTrampleSwitch.OffWait)) {
191 al::invalidateClipping(actor: this);
192 al::setNerve(user: this, nerve: &NrvTrampleSwitch.On);
193 return true;
194 }
195 return false;
196}
197