1#include "MapObj/TrampleSwitchTimer.h"
2
3#include "Library/Collision/PartsConnector.h"
4#include "Library/LiveActor/ActorActionFunction.h"
5#include "Library/LiveActor/ActorClippingFunction.h"
6#include "Library/LiveActor/ActorCollisionFunction.h"
7#include "Library/LiveActor/ActorInitInfo.h"
8#include "Library/LiveActor/ActorInitUtil.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/Obj/CollisionObj.h"
15#include "Library/Obj/PartsFunction.h"
16#include "Library/Placement/PlacementFunction.h"
17
18#include "MapObj/AppearSwitchTimer.h"
19#include "Util/SensorMsgFunction.h"
20
21namespace {
22NERVE_IMPL(TrampleSwitchTimer, Freeze);
23NERVE_IMPL(TrampleSwitchTimer, OffWait);
24NERVE_IMPL(TrampleSwitchTimer, OnWait);
25NERVE_IMPL(TrampleSwitchTimer, Off);
26NERVE_IMPL(TrampleSwitchTimer, On);
27
28NERVES_MAKE_NOSTRUCT(TrampleSwitchTimer, OnWait);
29NERVES_MAKE_STRUCT(TrampleSwitchTimer, Freeze, OffWait, Off, On);
30} // namespace
31
32TrampleSwitchTimer::TrampleSwitchTimer(const char* actorName) : LiveActor(actorName) {}
33
34void TrampleSwitchTimer::init(const al::ActorInitInfo& info) {
35 al::initActorWithArchiveName(actor: this, initInfo: info, archiveName: "TrampleSwitch", suffix: nullptr);
36
37 bool isNoReaction = false;
38 bool tryGetArg = al::tryGetArg(arg: &isNoReaction, initInfo: info, key: "IsNoReaction");
39
40 if (!isNoReaction || !tryGetArg) {
41 al::initNerve(actor: this, nerve: &NrvTrampleSwitchTimer.OffWait, maxStates: 0);
42 mAppearSwitchTimer = new AppearSwitchTimer();
43 mAppearSwitchTimer->init(info, this, this, this, this);
44
45 mIsFacingUp = al::isNearZeroOrLess(value: al::calcQuatUpY(al::getQuat(actor: this)));
46
47 mCollisionObj = al::createCollisionObj(parent: this, info, collisionFileName: "TrampleSwitch_Body",
48 hitSensor: al::getHitSensor(this, "PPanel"), joinMtxName: nullptr, suffix: nullptr);
49 mCollisionObj->makeActorAlive();
50 al::validateCollisionParts(mCollisionObj);
51
52 mMtxConnector = al::createMtxConnector(actor: this);
53 } else {
54 al::startAction(actor: this, actionName: "OffWait");
55 al::initNerve(actor: this, nerve: &NrvTrampleSwitchTimer.Freeze, maxStates: 0);
56 }
57
58 makeActorAlive();
59}
60
61void TrampleSwitchTimer::initAfterPlacement() {
62 al::LiveActor::initAfterPlacement();
63
64 if (mMtxConnector)
65 al::attachMtxConnectorToCollision(mtxConnector: mMtxConnector, actor: this, false);
66}
67
68void TrampleSwitchTimer::control() {
69 if (al::isNerve(user: this, nerve: &NrvTrampleSwitchTimer.Freeze))
70 return;
71
72 if (mMtxConnector)
73 al::connectPoseQT(actor: this, mtxConnector: mMtxConnector);
74
75 mAppearSwitchTimer->updateNerve();
76}
77
78void TrampleSwitchTimer::exeOn() {
79 if (al::isFirstStep(user: this))
80 al::startAction(actor: this, actionName: "On");
81
82 if (al::isActionEnd(actor: this))
83 al::setNerve(user: this, nerve: &OnWait);
84}
85
86void TrampleSwitchTimer::exeOnWait() {
87 if (al::isFirstStep(user: this)) {
88 al::invalidateHitSensors(this);
89 al::startAction(actor: this, actionName: "OnWait");
90 mAppearSwitchTimer->onSwitch();
91 }
92
93 if (!mAppearSwitchTimer->isSwitchOn())
94 al::setNerve(user: this, nerve: &NrvTrampleSwitchTimer.Off);
95}
96
97void TrampleSwitchTimer::exeOff() {
98 if (al::isFirstStep(user: this))
99 al::startAction(actor: this, actionName: "Off");
100 if (al::isActionEnd(actor: this))
101 al::setNerve(user: this, nerve: &NrvTrampleSwitchTimer.OffWait);
102}
103
104void TrampleSwitchTimer::exeOffWait() {
105 if (al::isFirstStep(user: this)) {
106 al::validateClipping(actor: this);
107 al::validateHitSensors(this);
108 al::startAction(actor: this, actionName: "OffWait");
109 }
110}
111
112void TrampleSwitchTimer::exeFreeze() {}
113
114// NON_MATCHING: extra register used for the last comparsion, https://decomp.me/scratch/IEP6S
115bool TrampleSwitchTimer::receiveMsg(const al::SensorMsg* message, al::HitSensor* other,
116 al::HitSensor* self) {
117 if (al::isNerve(user: this, nerve: &NrvTrampleSwitchTimer.Freeze))
118 return rs::isMsgPlayerDisregardHomingAttack(message);
119
120 if (al::isNerve(user: this, nerve: &NrvTrampleSwitchTimer.Off))
121 return false;
122
123 if (al::isSensorName(self, "PlayerRegard")) {
124 if (!mIsFacingUp && rs::isMsgPlayerDisregardTargetMarker(message))
125 return true;
126 return false;
127 }
128
129 if (mIsFacingUp && !al::isSensorName(self, "PPanel"))
130 return false;
131
132 bool v10 = (rs::isMsgCapTouchWall(message) || rs::isMsgCapAttackCollide(message)) &&
133 (mIsFacingUp || !al::isNearZeroOrGreater(value: al::getActorVelocity(other).y));
134 bool v11 = rs::isMsgCapHipDrop(message);
135 bool v12 = al::isMsgPlayerTouch(msg: message);
136
137 if (v12 || v10 || v11) {
138 if (al::isNerve(user: this, nerve: &NrvTrampleSwitchTimer.OffWait)) {
139 al::invalidateClipping(actor: this);
140 al::setNerve(user: this, nerve: &NrvTrampleSwitchTimer.On);
141 return true;
142 }
143 }
144 return false;
145}
146