1#include "MapObj/ElectricWire/ElectricWireRailKeeper.h"
2
3#include "Library/Camera/CameraTicket.h"
4#include "Library/Camera/CameraUtil.h"
5#include "Library/LiveActor/ActorClippingFunction.h"
6#include "Library/LiveActor/ActorFlagFunction.h"
7#include "Library/LiveActor/ActorInitFunction.h"
8#include "Library/LiveActor/ActorInitInfo.h"
9#include "Library/LiveActor/ActorInitUtil.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/Placement/PlacementInfo.h"
15#include "Library/Rail/RailUtil.h"
16#include "Library/Stage/StageSwitchUtil.h"
17#include "Library/Thread/FunctorV0M.h"
18
19#include "MapObj/ElectricWire/ElectricWire.h"
20
21namespace {
22NERVE_IMPL(ElectricWireRailKeeper, Standby)
23NERVE_IMPL(ElectricWireRailKeeper, Wait)
24
25NERVES_MAKE_NOSTRUCT(ElectricWireRailKeeper, Standby, Wait)
26} // namespace
27
28ElectricWireRailKeeper::ElectricWireRailKeeper(const char* name) : LiveActor(name) {}
29
30ElectricWireRailKeeper::ElectricWireRailKeeper(const char* name, al::LiveActor* wire)
31 : LiveActor(name), mElectricWire(reinterpret_cast<ElectricWire*>(wire)) {}
32
33void ElectricWireRailKeeper::init(const al::ActorInitInfo& info) {
34 using ElectricWireRailKeeperFunctor =
35 al::FunctorV0M<ElectricWireRailKeeper*, void (ElectricWireRailKeeper::*)()>;
36
37 al::initActorSceneInfo(actor: this, info);
38 al::initActorPoseTRSV(actor: this);
39 al::initActorSRT(actor: this, info);
40 al::initActorClipping(actor: this, initInfo: info);
41 al::initStageSwitch(this, info);
42
43 ElectricWire* wire = mElectricWire;
44 al::tryGetArg(arg: &mIsShowLine, initInfo: info, key: "IsShowLine");
45 if (wire->isElectricWireRadio())
46 mIsShowLine = false;
47 al::tryGetArg(arg: &mIsThrowaway, initInfo: info, key: "IsThrowaway");
48 if (al::tryGetLinksTrans(trans: &mPlayerPosOnVerticalMove, initInfo: info, linkName: "PlayerHeadPosOnVerticalMove"))
49 mPosType = PosType::HEAD;
50 else if (al::tryGetLinksTrans(trans: &mPlayerPosOnVerticalMove, initInfo: info, linkName: "PlayerBottomPosOnVerticalMove"))
51 mPosType = PosType::BOTTOM;
52 if (!al::isExistRail(initInfo: info, linkName: "Rail")) {
53 makeActorDead();
54 return;
55 }
56 initRailKeeper(info, linkName: "Rail");
57 s32 pointNum = al::getRailPointNum(railHolder: this);
58 s32 needCameraPointNum = 0;
59 for (s32 i = 0; i < pointNum; ++i)
60 if (isRailPointIsNeedCamera(index: i) || isRailPointIsNeedStartCameraHackEnd(index: i))
61 ++needCameraPointNum;
62 if (needCameraPointNum > 0)
63 mCameraTickets.allocBuffer(ptrNumMax: needCameraPointNum, heap: nullptr);
64 for (s32 i = 0; i < pointNum; ++i) {
65 al::CameraTicket* ticket = nullptr;
66 // Yes, memory leak in new FixedSafeString
67 if (isRailPointIsNeedCamera(index: i)) {
68 auto* id = new sead::FixedSafeString<0x20>();
69 id->format(formatStr: "%d", i);
70 ticket = al::initObjectCamera(user: mElectricWire, actorInitInfo: info, id->cstr(), nullptr);
71 }
72 al::CameraTicket* ticketHack = nullptr;
73 if (isRailPointIsNeedStartCameraHackEnd(index: i)) {
74 auto* id = new sead::FixedSafeString<0x20>();
75 id->format(formatStr: "%d(Entrance)", i);
76 ticketHack = al::initEntranceCamera(user: mElectricWire, placementInfo: *info.placementInfo, id->cstr());
77 }
78 if (ticket != nullptr || ticketHack != nullptr)
79 mCameraTickets.pushBack(ptr: new TicketHolder{.ticket: ticket, .ticketHackEnd: ticketHack, .pointIdx: i});
80 }
81 al::initExecutorUpdate(actor: this, info, "地形オブジェ[Movement]");
82 al::initNerve(actor: this, nerve: &Wait, maxStates: 0);
83 makeActorAlive();
84 if (al::listenStageSwitchOnAppear(
85 user: this, action: ElectricWireRailKeeperFunctor(this, &ElectricWireRailKeeper::appearBySwitch)))
86 kill();
87 al::listenStageSwitchOnKill(
88 user: this, action: ElectricWireRailKeeperFunctor(this, &ElectricWireRailKeeper::killBySwitch));
89}
90
91void ElectricWireRailKeeper::appear() {
92 LiveActor::appear();
93 mElectricWire->tryUpdateDisplayModel();
94 al::setNerve(user: this, nerve: &Wait);
95}
96
97void ElectricWireRailKeeper::kill() {
98 LiveActor::kill();
99 mElectricWire->tryUpdateDisplayModel();
100}
101
102bool ElectricWireRailKeeper::isRailPointFaceToCameraDir(s32 index) const {
103 al::PlacementInfo* info = getRailPointInfo(index);
104 bool ret;
105 if (al::tryGetArg(arg: &ret, placementInfo: *info, key: "IsFaceToCamera"))
106 return ret;
107 return false;
108}
109
110bool ElectricWireRailKeeper::isRailPointPlacementPole(s32 index) const {
111 al::PlacementInfo* info = getRailPointInfo(index);
112 bool ret;
113 if (al::tryGetArg(arg: &ret, placementInfo: *info, key: "IsPlacementPole"))
114 return ret;
115 return false;
116}
117
118bool ElectricWireRailKeeper::isRailPointEnableTargetEndCollision(s32 index) const {
119 al::PlacementInfo* info = getRailPointInfo(index);
120 bool ret = true;
121 al::tryGetArg(arg: &ret, placementInfo: *info, key: "IsEnableTargetEndCollision");
122 return ret;
123}
124
125bool ElectricWireRailKeeper::isRailPointIgnore(s32 index) const {
126 al::PlacementInfo* info = getRailPointInfo(index);
127 bool ret;
128 if (al::tryGetArg(arg: &ret, placementInfo: *info, key: "IsIgnore"))
129 return ret;
130 return false;
131}
132
133bool ElectricWireRailKeeper::isRailPointSpringFix(s32 index) const {
134 al::PlacementInfo* info = getRailPointInfo(index);
135 bool ret;
136 if (al::tryGetArg(arg: &ret, placementInfo: *info, key: "IsSpringFix"))
137 return ret;
138 return false;
139}
140
141bool ElectricWireRailKeeper::isRailPointIsNeedCamera(s32 index) const {
142 al::PlacementInfo* info = getRailPointInfo(index);
143 bool ret = false;
144 al::tryGetArg(arg: &ret, placementInfo: *info, key: "IsNeedCamera");
145 return ret;
146}
147
148bool ElectricWireRailKeeper::isRailPointIsNeedStartCameraHackEnd(s32 index) const {
149 al::PlacementInfo* info = getRailPointInfo(index);
150 bool ret = false;
151 al::tryGetArg(arg: &ret, placementInfo: *info, key: "IsNeedStartCameraHackEnd");
152 return ret;
153}
154
155bool ElectricWireRailKeeper::isRailPointIsExpandRailSelectableAngle(s32 index) const {
156 al::PlacementInfo* info = getRailPointInfo(index);
157 bool ret = false;
158 al::tryGetArg(arg: &ret, placementInfo: *info, key: "IsExpandRailSelectableAngle");
159 return ret;
160}
161
162bool ElectricWireRailKeeper::isRailPointIsDisplayPointModelForce(s32 index) const {
163 al::PlacementInfo* info = getRailPointInfo(index);
164 bool ret = false;
165 al::tryGetArg(arg: &ret, placementInfo: *info, key: "IsDisplayPointModelForce");
166 return ret;
167}
168
169bool ElectricWireRailKeeper::tryGetRailPointOutDir(sead::Vector3f* out, s32 index) const {
170 al::PlacementInfo* info = getRailPointInfo(index);
171 al::PlacementInfo linksInfo{};
172 if (al::tryGetLinksInfo(railPlacementInfo: &linksInfo, placementInfo: *info, linkName: "DestinationPoint")) {
173 sead::Vector3f linksTrans;
174 if (!al::tryGetLinksTrans(trans: &linksTrans, placementInfo: *info, linkName: "DestinationPoint"))
175 return false;
176 sead::Vector3f railPointPos{};
177 al::calcRailPointPos(&railPointPos, railHolder: this, index);
178 out->set(linksTrans);
179 *out -= railPointPos;
180 return al::tryNormalizeOrZero(out);
181 } else {
182 bool isOutToRailPointDir = false;
183 al::tryGetArg(arg: &isOutToRailPointDir, placementInfo: *info, key: "IsOutToRailPointDir");
184 if (isOutToRailPointDir)
185 return al::tryGetUp(up: out, placementInfo: *info);
186 }
187 return false;
188}
189
190bool ElectricWireRailKeeper::tryGetRailPointDestinationTrans(sead::Vector3f* out, s32 index) const {
191 al::PlacementInfo* info = getRailPointInfo(index);
192 return al::tryGetLinksTrans(trans: out, placementInfo: *info, linkName: "DestinationPoint");
193}
194
195bool ElectricWireRailKeeper::tryGetRailPointFastenerMoveLimitAreaFlag(s32* out, s32 index) const {
196 al::PlacementInfo* info = getRailPointInfo(index);
197 return al::tryGetArg(arg: out, placementInfo: *info, key: "FastenerMoveLimitAreaFlag");
198}
199
200al::CameraTicket* ElectricWireRailKeeper::findRailPointCameraTicket(s32 pointIdx) const {
201 for (s32 i = 0; i < mCameraTickets.size(); ++i) {
202 TicketHolder* holder = mCameraTickets[i];
203 if (holder->pointIdx == pointIdx)
204 return holder->ticket;
205 }
206 return nullptr;
207}
208
209const al::CameraTicket*
210ElectricWireRailKeeper::findRailPointStartCameraHackEndTicket(s32 pointIdx) const {
211 for (s32 i = 0; i < mCameraTickets.size(); ++i) {
212 TicketHolder* ticket = mCameraTickets[i];
213 if (ticket->pointIdx == pointIdx)
214 return ticket->ticketHackEnd;
215 }
216 return nullptr;
217}
218
219bool ElectricWireRailKeeper::tryGetPlayerHeadPosOnVerticalMove(
220 sead::Vector3f* playerHeadPos) const {
221 if (mPosType == PosType::HEAD) {
222 playerHeadPos->set(mPlayerPosOnVerticalMove);
223 return true;
224 }
225 return false;
226}
227
228bool ElectricWireRailKeeper::tryGetPlayerBottomPosOnVerticalMove(
229 sead::Vector3f* playerBottomPos) const {
230 if (mPosType == PosType::BOTTOM) {
231 playerBottomPos->set(mPlayerPosOnVerticalMove);
232 return true;
233 }
234 return false;
235}
236
237void ElectricWireRailKeeper::endCameraIfActive() {
238 for (s32 i = 0; i < mCameraTickets.size(); ++i) {
239 TicketHolder* holder = mCameraTickets[i];
240 if (al::isActiveCamera(ticket: holder->ticket))
241 al::endCamera(user: mElectricWire, ticket: holder->ticket, -1, false);
242 }
243}
244
245al::PlacementInfo* ElectricWireRailKeeper::getRailPointInfo(s32 index) const {
246 return al::getRailPointInfo(railHolder: this, index);
247}
248
249void ElectricWireRailKeeper::appearBySwitch() {
250 if (al::isAlive(actor: this))
251 return;
252
253 appear();
254 al::invalidateClipping(actor: this);
255 al::setNerve(user: this, nerve: &Standby);
256}
257
258void ElectricWireRailKeeper::killBySwitch() {
259 if (al::isDead(actor: this))
260 return;
261 kill();
262}
263
264void ElectricWireRailKeeper::exeStandby() {
265 if (al::isGreaterStep(user: this, step: 10)) {
266 al::validateClipping(actor: this);
267 al::setNerve(user: this, nerve: &Wait);
268 }
269}
270
271void ElectricWireRailKeeper::exeWait() {}
272
273bool ElectricWireRailKeeper::isNerveStandby() const {
274 return al::isNerve(user: this, nerve: &Standby);
275}
276