1#include "Enemy/Megane.h"
2
3#include "Library/Base/StringUtil.h"
4#include "Library/Bgm/BgmLineFunction.h"
5#include "Library/Camera/CameraUtil.h"
6#include "Library/Collision/Collider.h"
7#include "Library/Collision/KCollisionServer.h"
8#include "Library/Effect/EffectSystemInfo.h"
9#include "Library/Joint/JointControllerKeeper.h"
10#include "Library/Joint/JointSpringController.h"
11#include "Library/LiveActor/ActorActionFunction.h"
12#include "Library/LiveActor/ActorAnimFunction.h"
13#include "Library/LiveActor/ActorAreaFunction.h"
14#include "Library/LiveActor/ActorClippingFunction.h"
15#include "Library/LiveActor/ActorCollisionFunction.h"
16#include "Library/LiveActor/ActorFlagFunction.h"
17#include "Library/LiveActor/ActorInitUtil.h"
18#include "Library/LiveActor/ActorModelFunction.h"
19#include "Library/LiveActor/ActorMovementFunction.h"
20#include "Library/LiveActor/ActorPoseUtil.h"
21#include "Library/LiveActor/ActorSensorUtil.h"
22#include "Library/LiveActor/LiveActorFunction.h"
23#include "Library/Math/MathUtil.h"
24#include "Library/Nature/NatureUtil.h"
25#include "Library/Nerve/NerveKeeper.h"
26#include "Library/Nerve/NerveSetupUtil.h"
27#include "Library/Nerve/NerveUtil.h"
28#include "Library/Play/Camera/CameraPoserSubjective.h"
29#include "Library/Player/PlayerUtil.h"
30#include "Library/Se/SeFunction.h"
31#include "Library/Stage/StageSwitchUtil.h"
32#include "Library/Thread/FunctorV0M.h"
33
34#include "Enemy/EnemyStateSwoon.h"
35#include "Layout/TestFilterGlasses.h"
36#include "Player/HackerStateNormalMove.h"
37#include "Player/PlayerActionTurnControl.h"
38#include "Player/PlayerHackStartShaderCtrl.h"
39#include "Player/PlayerPushReceiver.h"
40#include "Util/CameraUtil.h"
41#include "Util/Hack.h"
42#include "Util/InputInterruptTutorialUtil.h"
43#include "Util/SensorMsgFunction.h"
44
45namespace {
46NERVE_IMPL(Megane, Wait)
47NERVE_IMPL(Megane, Find)
48NERVE_IMPL(Megane, RunAway)
49NERVE_IMPL(Megane, Fall)
50NERVE_IMPL(Megane, Land)
51NERVE_IMPL(Megane, Trampled)
52NERVE_IMPL(Megane, WaitHack)
53NERVE_IMPL(Megane, HackStart)
54NERVE_IMPL(Megane, Hack)
55NERVE_IMPL(Megane, HackSlow)
56NERVE_IMPL(Megane, HackSubjective)
57NERVE_IMPL(Megane, HackFall)
58NERVE_IMPL(Megane, HackLand)
59NERVE_IMPL(Megane, Die)
60NERVE_IMPL(Megane, Rebirth)
61NERVE_IMPL(Megane, Appear)
62NERVE_IMPL(Megane, SpectaclesOff)
63NERVE_IMPL(Megane, SpectaclesOn)
64
65struct MeganeJointProperties {
66 sead::Vector3f position;
67 f32 stability;
68 f32 friction;
69 f32 limitDegree;
70};
71
72// TODO: Find a memory layout that fits these globals perfectly
73struct {
74 NERVES_MAKE_STRUCT(Megane, Wait, WaitHack, Hack, HackSlow, SpectaclesOn, Trampled, HackStart,
75 Rebirth, Die, Appear, Find, RunAway, Fall, Land, SpectaclesOff, HackFall,
76 HackSubjective, HackLand)
77
78 PlayerHackStartShaderParam playerHackStartShaderParam =
79 PlayerHackStartShaderParam(false, 400.0f, 10, 20);
80
81 MeganeJointProperties jointProperties[4] = {
82 {.position: {200.0f, 0.0f, 0.0f}, .stability: 0.025f, .friction: 0.9f, .limitDegree: 10.0f},
83 {.position: {200.0f, 0.0f, 0.0f}, .stability: 0.025f, .friction: 0.9f, .limitDegree: 10.0f},
84 {.position: {0.0f, -50.0f, -50.0f}, .stability: 0.1f, .friction: 0.95f, .limitDegree: 30.0f},
85 {.position: {0.0f, -50.0f, 50.0f}, .stability: 0.1f, .friction: 0.95f, .limitDegree: 30.0f},
86 };
87} MeganeData;
88
89} // namespace
90
91Megane::Megane(const char* name) : al::LiveActor(name) {}
92
93void Megane::init(const al::ActorInitInfo& initInfo) {
94 using MeganeFunctor = al::FunctorV0M<Megane*, void (Megane::*)()>;
95
96 al::initActorWithArchiveName(actor: this, initInfo, archiveName: "Megane", suffix: nullptr);
97 al::initNerve(actor: this, nerve: &MeganeData.NrvMegane.Wait, maxStates: 3);
98 mStateSwoon = new EnemyStateSwoon(this, "SwoonStart", "Swoon", "SwoonEnd", false, true);
99 mStateSwoon->initParams(swoonDuration: 180, trampledAnimName: nullptr);
100 al::initNerveState(user: this, state: mStateSwoon, nerve: &MeganeData.NrvMegane.WaitHack, hostName: "気絶");
101
102 mHackerState = new HackerStateNormalMove(this, &mPlayerHack, "Wait", "HackRun", "Fall");
103 mHackerState->set_54(2.0f);
104 mHackerState->set_5c(0.9f);
105 mHackerState->setMoveVelocity(0.8f);
106 mHackerState->set_49(true);
107 mHackerState->setTurnAngle(30.0f);
108 mHackerState->usePlayerTurnControl(true);
109 mHackerState->getTurnControl()->setup(3.0f, 55.0f, 8.0f, 8.0f, 20, 1, 30);
110 al::initNerveState(user: this, state: mHackerState, nerve: &MeganeData.NrvMegane.Hack, hostName: "憑依");
111
112 mHackerStateSpectacles = new HackerStateNormalMove(this, &mPlayerHack, "Wait", "Walk", "Fall");
113 mHackerStateSpectacles->set_54(1.2f);
114 mHackerStateSpectacles->setTurnAngle(30.0f);
115 al::initNerveState(user: this, state: mHackerStateSpectacles, nerve: &MeganeData.NrvMegane.HackSlow, hostName: "憑依メガネ");
116
117 mPlayerPushReceiver = new PlayerPushReceiver(this);
118 if (!al::trySyncStageSwitchAppear(actor: this))
119 makeActorAlive();
120
121 al::listenStageSwitchOnKill(user: this, action: MeganeFunctor(this, &Megane::notifyKillSwitch));
122 mCollisionPartsFilterMoveLimit = new al::CollisionPartsFilterSpecialPurpose("MoveLimit");
123 al::setColliderFilterCollisionParts(this, mCollisionPartsFilterMoveLimit);
124
125 al::LiveActor* subActor = al::getSubActor(actor: this, subActorName: "メガネ");
126 al::startAction(actor: subActor, actionName: "SpectaclesOn");
127 al::setActionFrame(actor: subActor, frame: al::getActionFrameMax(actor: subActor, actionName: "SpectaclesOn") - 1.0f);
128
129 mTestFilterGlasses =
130 new TestFilterGlasses("メガネーレイアウト", al::getLayoutInitInfo(initInfo), nullptr);
131 mStartingQuat.set(al::getQuat(actor: this));
132 mStartingPos.set(al::getTrans(actor: this));
133
134 mCapTargetInfo = rs::createCapTargetInfo(this, nullptr);
135 mCameraPoserSubjective = new al::CameraPoserSubjective("主観");
136 mCameraTicket =
137 alCameraFunction::initCamera(poser: mCameraPoserSubjective, user: this, actorInitInfo: initInfo, nullptr, 9);
138 mSpectaclesNerveKeeper = new al::NerveKeeper(this, &MeganeData.NrvMegane.SpectaclesOn, 0);
139
140 mPlayerHackStartShaderCtrl =
141 new PlayerHackStartShaderCtrl(this, &MeganeData.playerHackStartShaderParam);
142
143 al::initJointControllerKeeper(this, 4);
144
145 const char* jointNames[4] = {"Grass1", "Grass2", "EarringL", "EarringR"};
146
147 for (s32 i = 0; i < 4; i++) {
148 al::JointSpringController* jointController =
149 al::initJointSpringController(this, jointNames[i]);
150 jointController->setChildLocalPos(MeganeData.jointProperties[i].position);
151 jointController->setStability(MeganeData.jointProperties[i].stability);
152 jointController->setFriction(MeganeData.jointProperties[i].friction);
153 jointController->setLimitDegree(MeganeData.jointProperties[i].limitDegree);
154 al::StringTmp<128>("ダイナミクス[%s]", jointNames[i]).cstr();
155 }
156
157 mCapReceiverSensor = al::getHitSensor(this, "CapReceiver");
158}
159
160bool Megane::receiveMsg(const al::SensorMsg* message, al::HitSensor* other, al::HitSensor* self) {
161 if (rs::tryReceiveMsgInitCapTargetAndSetCapTargetInfo(message, mCapTargetInfo))
162 return true;
163
164 if (rs::isMsgTargetMarkerPosition(message)) {
165 rs::setMsgTargetMarkerPosition(message, al::getSensorPos(this, "Head") +
166 (al::getSensorRadius(this, "Head") + 50.0f) *
167 sead::Vector3f::ey);
168 return true;
169 }
170
171 if (al::isMsgPlayerDisregard(msg: message))
172 return isNerveDieOrRebirth();
173
174 f32 geyserRaiseDistance = 0.0f;
175 f32 geyserRaiseSpeed = 0.0f;
176 if (rs::tryGetSandGeyserRaise(message, &geyserRaiseDistance, &geyserRaiseSpeed)) {
177 if (self == mCapReceiverSensor)
178 return false;
179 if (al::getVelocity(actor: this).y < 15.0f) {
180 al::addVelocityY(actor: this, y: 2.0f);
181 al::limitVelocityY(actor: this, limitY: 15.0f);
182 al::scaleVelocityHV(actor: this, factorH: 0.9f, factorV: 1.0f);
183 }
184 return true;
185 }
186
187 if (rs::isMsgEnableMapCheckPointWarp(message))
188 return rs::isMsgEnableMapCheckPointWarpCollidedGround(message, this);
189
190 if (self != mCapReceiverSensor && isNormalNerveWithWaitHack() &&
191 rs::tryReceiveMsgNpcScareByEnemyIgnoreTargetHack(message, mCapTargetInfo))
192 return true;
193
194 if (al::isMsgPushAll(msg: message)) {
195 if (self == mCapReceiverSensor)
196 return false;
197 if (isNormalNerveWithWaitHack())
198 return al::tryReceiveMsgPushAndAddVelocityH(this, message, other, self, 3.0f);
199 }
200
201 if (al::isMsgPlayerTrampleReflect(msg: message)) {
202 if (self == mCapReceiverSensor)
203 return false;
204
205 if (al::isNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack)) {
206 if (mStateSwoon->tryReceiveMsgTrampleReflect(message)) {
207 rs::requestHitReactionToAttacker(message, self, other);
208 return true;
209 }
210 return false;
211 }
212
213 if (isNormalNerveWithoutWaitHack() && al::isSensorName(self, "Head")) {
214 rs::requestHitReactionToAttacker(message, self, other);
215 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Trampled);
216 return true;
217 }
218 return false;
219 }
220
221 if (rs::isMsgThrowObjHitReflect(message) || rs::isMsgSphinxRideAttackReflect(message)) {
222 rs::requestHitReactionToAttacker(message, self, other);
223 if (isNormalNerveWithoutWaitHack())
224 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Trampled);
225 return true;
226 }
227
228 if (rs::isMsgPlayerAndCapObjHipDropReflectAll(message)) {
229 if (self == mCapReceiverSensor)
230 return false;
231
232 if (al::isNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack)) {
233 if (mStateSwoon->tryReceiveMsgObjHipDropReflect(message)) {
234 rs::requestHitReactionToAttacker(message, self, other);
235 return true;
236 }
237 return false;
238 }
239
240 if (isNormalNerveWithoutWaitHack() && al::isSensorName(self, "Head")) {
241 rs::requestHitReactionToAttacker(message, self, other);
242 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Trampled);
243 return true;
244 }
245 return false;
246 }
247
248 if (rs::isMsgKillByShineGet(message)) {
249 if (self == mCapReceiverSensor)
250 return false;
251 if (isNormalNerveWithWaitHack())
252 return tryReceiveMsgKillByShineGet(message);
253 }
254
255 if (rs::isMsgCapEnableLockOn(message) &&
256 (isNormalNerveWithWaitHack() || (al::isNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack) &&
257 mStateSwoon->tryReceiveMsgStartLockOn(message)))) {
258 mIsHack = true;
259 return true;
260 }
261
262 if (rs::isMsgCapCancelLockOn(message)) {
263 mIsHack = false;
264 if (al::isNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack))
265 mStateSwoon->tryReceiveMsgEndSwoon(message);
266 return true;
267 }
268
269 if (rs::isMsgStartHack(message)) {
270 if (isNormalNerveWithoutWaitHack()) {
271 prepareHack(self, other);
272 al::startAction(actor: this, actionName: "Wait");
273 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackStart);
274 return true;
275 }
276
277 if (al::isNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack) &&
278 mStateSwoon->tryReceiveMsgStartHack(message)) {
279 prepareHack(self, other);
280 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackStart);
281 return true;
282 }
283 }
284
285 if (rs::isMsgHackMarioCheckpointFlagWarp(message)) {
286 endCameraSubjective();
287 al::setColliderFilterCollisionParts(this, mCollisionPartsFilterMoveLimit);
288 rs::tryEndHackStartDemo(mPlayerHack, this);
289 rs::endHack(&mPlayerHack);
290 al::showModelIfHide(actor: this);
291 al::endBgmSituation(this, "WearMeganeGlasses", false);
292 al::tryStartVisAnimIfNotPlaying(this, "HackOff");
293 al::tryStartMtpAnimIfNotPlaying(this, "HackOff");
294 al::tryStartVisAnimIfNotPlayingForAction(this, "CapOff");
295 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack);
296 return true;
297 }
298
299 if (rs::isMsgCancelHack(message)) {
300 endCameraSubjective();
301 al::setColliderFilterCollisionParts(this, mCollisionPartsFilterMoveLimit);
302 rs::tryEndHackStartDemo(mPlayerHack, this);
303 rs::endHack(&mPlayerHack);
304 al::showModelIfHide(actor: this);
305 al::endBgmSituation(this, "WearMeganeGlasses", false);
306 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack);
307 return true;
308 }
309
310 if (rs::isMsgHackMarioDemo(message)) {
311 endCameraSubjective();
312 al::setColliderFilterCollisionParts(this, mCollisionPartsFilterMoveLimit);
313 rs::tryEndHackStartDemo(mPlayerHack, this);
314 rs::endHack(&mPlayerHack);
315 al::hideModelIfShow(actor: this);
316 al::hideModelIfShow(actor: al::getSubActor(actor: this, subActorName: "メガネ"));
317 al::setVelocityZero(this);
318 al::invalidateClipping(actor: this);
319 al::endBgmSituation(this, "WearMeganeGlasses", false);
320 al::startAction(actor: this, actionName: "Wait");
321 al::tryKillEmitterAndParticleAll(this);
322 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Rebirth);
323 return true;
324 }
325
326 if (rs::isMsgHackMarioDead(message)) {
327 endCameraSubjective();
328 al::setColliderFilterCollisionParts(this, mCollisionPartsFilterMoveLimit);
329 rs::tryEndHackStartDemo(mPlayerHack, this);
330 rs::endHack(&mPlayerHack);
331 al::showModelIfHide(actor: this);
332 al::endBgmSituation(this, "WearMeganeGlasses", false);
333 al::invalidateClipping(actor: this);
334 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Die);
335 return true;
336 }
337
338 if (rs::isMsgCancelHackByDokan(message)) {
339 endCameraSubjective();
340 al::setColliderFilterCollisionParts(this, mCollisionPartsFilterMoveLimit);
341 rs::tryEndHackStartDemo(mPlayerHack, this);
342 rs::endHack(&mPlayerHack);
343 al::showModelIfHide(actor: this);
344 al::endBgmSituation(this, "WearMeganeGlasses", false);
345 al::tryAddRippleLarge(this);
346 al::invalidateClipping(actor: this);
347 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Die);
348 return true;
349 }
350
351 if (rs::isMsgPushToPlayer(message) && isHack() && self != mCapReceiverSensor) {
352 mPlayerPushReceiver->receivePushMsg(message, other, self, 3.0f);
353 return true;
354 }
355 return false;
356}
357
358void Megane::attackSensor(al::HitSensor* self, al::HitSensor* other) {
359 if (self == mCapReceiverSensor)
360 return;
361
362 if ((al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Wait) ||
363 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Appear) ||
364 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Find) ||
365 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.RunAway) ||
366 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Fall) ||
367 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Land) ||
368 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Trampled) ||
369 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack)) &&
370 al::isSensorEnemyBody(self)) {
371 if (rs::sendMsgMeganeAttack(source: other, target: self))
372 return;
373 if (al::sendMsgPushAndKillVelocityToTargetH(this, self, other))
374 return;
375 rs::sendMsgPushToPlayer(source: other, target: self);
376 return;
377 }
378
379 if (isHack()) {
380 if (isEnableTrample(self, other) && rs::sendMsgMeganeHackTrample(source: other, target: self))
381 return;
382 if (rs::sendMsgHackAttackKick(source: other, target: self))
383 return;
384 if (rs::sendMsgHackAttackMapObj(source: other, target: self))
385 return;
386 if (rs::sendMsgMeganeAttack(source: other, target: self))
387 return;
388 if (rs::sendMsgHackerNoReaction(mPlayerHack, other, self))
389 return;
390 al::sendMsgPushAndKillVelocityToTargetH(this, self, other);
391 }
392}
393
394void Megane::updateCollider() {
395 sead::Vector3f pushVelocity;
396 mPlayerPushReceiver->calcPushedVelocity(&pushVelocity, al::getVelocity(actor: this));
397
398 if (al::isNoCollide(actor: this)) {
399 al::getTransPtr(actor: this)->add(a: pushVelocity);
400 getCollider()->onInvalidate();
401 mPlayerPushReceiver->clear();
402 return;
403 }
404
405 if (al::isNerve(user: this, nerve: &MeganeData.NrvMegane.HackStart))
406 getCollider()->collide(sead::Vector3f::ey * -10.0f);
407 else
408 al::getTransPtr(actor: this)->add(a: getCollider()->collide(pushVelocity));
409 mPlayerPushReceiver->clear();
410}
411
412void Megane::control() {
413 updateDither();
414 mSpectaclesNerveKeeper->update();
415
416 if (isHack() && !al::isHideModel(actor: this))
417 al::showSilhouetteModelIfHide(actor: this);
418 else
419 al::hideSilhouetteModelIfShow(actor: this);
420
421 if (isHack()) {
422 if (rs::isHackCapSeparateFlying(mPlayerHack))
423 al::tryStartVisAnimIfNotPlayingForAction(this, "CapOff");
424 else
425 al::tryStartVisAnimIfNotPlayingForAction(this, "CapOn");
426
427 if (!al::isNerve(user: this, nerve: &MeganeData.NrvMegane.HackStart) ||
428 rs::isHackStartDemoEnterMario(mPlayerHack)) {
429 al::tryStartVisAnimIfNotPlaying(this, "HackOff");
430 al::tryStartMtpAnimIfNotPlaying(this, "HackOff");
431 } else {
432 al::tryStartVisAnimIfNotPlaying(this, "HackOn");
433 al::tryStartMtpAnimIfNotPlaying(this, "HackOn");
434 }
435 } else {
436 al::tryStartVisAnimIfNotPlaying(this, "HackOff");
437 al::tryStartMtpAnimIfNotPlaying(this, "HackOff");
438 al::tryStartVisAnimIfNotPlayingForAction(this, "CapOff");
439 }
440
441 if (!isNerveDieOrRebirth() &&
442 (((al::isCollidedFloorCode(this, "DamageFire") || al::isCollidedFloorCode(this, "Needle") ||
443 al::isCollidedFloorCode(this, "Poison")) &&
444 !al::isCollidedFloorCode(this, "Needle")) ||
445 al::isInDeathArea(actor: this))) {
446 if (isHack()) {
447 endCameraSubjective();
448 al::setColliderFilterCollisionParts(this, mCollisionPartsFilterMoveLimit);
449 rs::tryEndHackStartDemo(mPlayerHack, this);
450 rs::endHack(&mPlayerHack);
451 al::showModelIfHide(actor: this);
452 }
453 al::tryAddRippleLarge(this);
454 al::invalidateClipping(actor: this);
455 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Die);
456 }
457
458 if (!isHack()) {
459 mIsHackTutorialVisible = false;
460 return;
461 }
462
463 if (al::isInAreaObj(actor: this, name: "MeganePlayGuideChangeArea")) {
464 if (!mIsHackTutorialVisible) {
465 rs::changeHackTutorialText(this, "HackEnd");
466 mIsHackTutorialVisible = true;
467 }
468 return;
469 }
470
471 if (mIsHackTutorialVisible) {
472 rs::resetHackTutorialText(this);
473 mIsHackTutorialVisible = false;
474 }
475}
476
477void Megane::notifyKillSwitch() {
478 if (isNerveDieOrRebirth())
479 return;
480
481 if (isHack()) {
482 endCameraSubjective();
483 al::setColliderFilterCollisionParts(this, mCollisionPartsFilterMoveLimit);
484 rs::tryEndHackStartDemo(mPlayerHack, this);
485 rs::endHack(&mPlayerHack);
486 al::showModelIfHide(actor: this);
487 }
488
489 al::invalidateClipping(actor: this);
490 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Die);
491}
492
493bool Megane::isNerveDieOrRebirth() const {
494 return al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Die) ||
495 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Rebirth);
496}
497
498bool Megane::isNormalNerveWithWaitHack() const {
499 return isNormalNerveWithoutWaitHack() || al::isNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack);
500}
501
502bool Megane::isNormalNerveWithoutWaitHack() const {
503 return al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Wait) ||
504 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Appear) ||
505 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Find) ||
506 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Fall) ||
507 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Land) ||
508 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Trampled) ||
509 al::isNerve(user: this, nerve: &MeganeData.NrvMegane.RunAway);
510}
511
512bool Megane::tryReceiveMsgKillByShineGet(const al::SensorMsg* message) {
513 if (rs::isMsgKillByShineGet(message)) {
514 al::deleteEffectAll(this);
515 al::hideModelIfShow(actor: this);
516 al::hideModelIfShow(actor: al::getSubActor(actor: this, subActorName: "メガネ"));
517 al::setVelocityZero(this);
518 al::invalidateClipping(actor: this);
519 al::startAction(actor: this, actionName: "Wait");
520 al::resetPosition(actor: this, trans: mStartingPos);
521 al::tryKillEmitterAndParticleAll(this);
522 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Rebirth);
523 return true;
524 }
525 return false;
526}
527
528void Megane::prepareHack(al::HitSensor* self, al::HitSensor* other) {
529 al::invalidateClipping(actor: this);
530 mPlayerHack = rs::startHack(self, other, nullptr);
531 rs::startHackStartDemo(mPlayerHack, this);
532 rs::addHackStartDemoActor(mPlayerHack, al::getSubActor(actor: this, subActorName: "メガネ"));
533}
534
535void Megane::endCameraSubjective() {
536 if (al::isActiveCamera(ticket: mCameraTicket))
537 al::endCamera(user: this, ticket: mCameraTicket, -1, false);
538}
539
540bool Megane::isHack() const {
541 return mPlayerHack != nullptr;
542}
543
544bool Megane::isEnableTrample(al::HitSensor* self, al::HitSensor* other) const {
545 if (al::isNerve(user: this, nerve: &MeganeData.NrvMegane.HackFall) && al::isSensorName(self, "Body")) {
546 sead::Vector3f dir = al::getSensorPos(other) - al::getSensorPos(self);
547 if (al::tryNormalizeOrZero(out: &dir))
548 return 0.0f < dir.dot(t: al::getGravity(actor: this));
549 }
550 return false;
551}
552
553void Megane::updateMovement() {
554 al::reboundVelocityPart(actor: this, ground: 0.0f, wall: 0.0f, ceiling: 0.0f, threshold: 0.0f);
555 if (al::isCollidedGround(this))
556 al::addVelocityToGravityFittedGround(actor: this, force: 2.0f, maxAirTime: 0);
557 else
558 al::addVelocityToGravity(actor: this, force: 2.0f);
559 al::scaleVelocity(actor: this, factor: 0.95f);
560}
561
562bool Megane::tryShiftFall() {
563 if (!al::isOnGround(this, 4)) {
564 al::invalidateClipping(actor: this);
565 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Fall);
566 return true;
567 }
568 return false;
569}
570
571void Megane::updateRunAwayDirection() {
572 sead::Vector3f runAwayDirection;
573 al::calcDirToActorH(out: &runAwayDirection, actor: this, target: al::getPlayerActor(this, 0));
574 runAwayDirection.negate();
575 recordWallNormal();
576
577 if (mRunAwayWallTime != 0) {
578 f32 rundot = mWallNormal.dot(t: runAwayDirection);
579 if (rundot < -0.99f) {
580 f32 tmp = -runAwayDirection.x;
581 runAwayDirection.x = runAwayDirection.z;
582 runAwayDirection.z = tmp;
583 } else if (rundot < 0.0f) {
584 al::verticalizeVec(out: &runAwayDirection, vertical: mWallNormal, vec: runAwayDirection);
585 al::normalize(vec: &runAwayDirection);
586 }
587 mRunAwayWallTime--;
588 }
589 al::turnToDirection(actor: this, dir: runAwayDirection, deg: 4.0f);
590}
591
592void Megane::shiftWaitOrRunAway() {
593 if (al::calcDistanceH(actor: this, target: al::getPlayerActor(this, 0)) < 1000.0f)
594 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.RunAway);
595 else
596 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Wait);
597}
598
599bool Megane::isTriggerStare() const {
600 return rs::isTriggerHackAnyButton(mPlayerHack) || rs::isTriggerHackSwing(mPlayerHack);
601}
602
603bool Megane::isTriggerSubjective() const {
604 return rs::isTriggerSubjectiveCamera(mPlayerHack) && al::isOnGround(this, 0);
605}
606
607void Megane::startCameraSubjective() {
608 if (al::isActiveCamera(ticket: mCameraTicket))
609 return;
610 sead::Vector3f frontDir;
611 al::calcFrontDir(front: &frontDir, actor: this);
612 frontDir.y = 0.0;
613 if (al::tryNormalizeOrZero(out: &frontDir)) {
614 f32 angle = sead::Mathf::rad2deg(rad: sead::Mathf::atan2(y: frontDir.x, x: frontDir.z));
615 mCameraPoserSubjective->setStartAngleH(angle);
616 }
617 mCameraPoserSubjective->setCameraOffsetUp(100.0f);
618 al::startCamera(user: this, ticket: mCameraTicket, unk: -1);
619}
620
621void Megane::faceToCameraFront() {
622 sead::Vector3f lookDir;
623 al::calcCameraLookDir(lookDir: &lookDir, user: this, viewIdx: 0);
624 lookDir.y = 0.0f;
625 if (al::tryNormalizeOrZero(out: &lookDir))
626 al::faceToDirection(actor: this, dir: lookDir);
627}
628
629void Megane::tryToggleSpectaclesNerve() {
630 if (isTriggerStare()) {
631 if (mSpectaclesNerveKeeper->getCurrentNerve() == &MeganeData.NrvMegane.SpectaclesOn)
632 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOff);
633 else
634 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOn);
635 }
636}
637
638void Megane::shiftHackNerveOnGround() {
639 if (mSpectaclesNerveKeeper->getCurrentNerve() == &MeganeData.NrvMegane.SpectaclesOn)
640 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackSlow);
641 else
642 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Hack);
643}
644
645void Megane::putOnSpectaclesForce() {
646 if (mSpectaclesNerveKeeper->getCurrentNerve() != &MeganeData.NrvMegane.SpectaclesOn)
647 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOn);
648 al::LiveActor* subActor = al::getSubActor(actor: this, subActorName: "メガネ");
649 al::startAction(actor: subActor, actionName: "SpectaclesOn");
650 al::setActionFrame(actor: subActor, frame: al::getActionFrameMax(actor: subActor, actionName: "SpectaclesOn") - 1.0f);
651}
652
653bool Megane::isWearingGlasses() const {
654 return isHack() &&
655 mSpectaclesNerveKeeper->getCurrentNerve() == &MeganeData.NrvMegane.SpectaclesOn;
656}
657
658void Megane::updateDither() {
659 const sead::Vector3f& cameraPos = al::getCameraPos(user: this, viewIdx: 0);
660 sead::Vector3f cameraDir = al::getCameraAt(user: this, viewIdx: 0) - cameraPos;
661 al::tryNormalizeOrZero(out: &cameraDir);
662
663 sead::Vector3f actorDir = al::getTrans(actor: this) - cameraPos;
664 f32 actorDistance = actorDir.length();
665 al::tryNormalizeOrZero(out: &actorDir);
666
667 al::LiveActor* subActor = al::getSubActor(actor: this, subActorName: "メガネ");
668 f32 targetAlphaMask = 0.0f;
669 if (cameraDir.dot(t: actorDir) > 0.0f)
670 targetAlphaMask =
671 sead::Mathf::clamp(value: (actorDistance - 700.0f + 500.0f) / 500.0f, low: 0.0f, high: 1.0f);
672
673 if (mModelAlphaMask > targetAlphaMask)
674 mModelAlphaMask = targetAlphaMask;
675 else if (targetAlphaMask - mModelAlphaMask > 0.1f)
676 mModelAlphaMask += 0.1f;
677 else
678 mModelAlphaMask = targetAlphaMask;
679
680 al::setModelAlphaMask(actor: this, mModelAlphaMask);
681 al::setModelAlphaMask(actor: subActor, mModelAlphaMask);
682}
683
684void Megane::recordWallNormal() {
685 if (!al::isCollidedWall(this))
686 return;
687
688 sead::Vector3f velocity = al::getVelocity(actor: this);
689 if (!al::tryNormalizeOrZero(out: &velocity) || velocity.dot(t: al::getCollidedWallNormal(this)) >= 0.0f)
690 return;
691
692 sead::Vector3f normal = al::getCollidedWallNormal(this);
693 normal.y = 0.0f;
694 if (!al::tryNormalizeOrZero(out: &normal))
695 return;
696
697 f32 lerpFactor = mRunAwayWallTime / 30.0f;
698 normal = normal * (1.0f - lerpFactor) + mWallNormal * lerpFactor;
699 if (al::tryNormalizeOrZero(out: &normal)) {
700 mWallNormal.set(normal);
701 mRunAwayWallTime = 30;
702 }
703}
704
705void Megane::exeWait() {
706 if (al::isFirstStep(user: this)) {
707 al::startAction(actor: this, actionName: "Wait");
708 al::getVelocityPtr(actor: this)->set({0.0f, 0.0f, 0.0f});
709 }
710
711 sead::Vector3f frontDir;
712 al::calcFrontDir(front: &frontDir, actor: this);
713 bool isFacePlayer = al::isFaceToTargetDegreeH(actor: this, target: al::getPlayerPos(this, 0), face: frontDir, degH: 10.0f);
714 if (isFacePlayer) {
715 if (mWaitDelay != 0)
716 mWaitDelay--;
717 } else {
718 mWaitDelay = 30;
719 }
720
721 if (al::isActionPlaying(actor: this, actionName: "Wait")) {
722 if (!isFacePlayer)
723 al::startAction(actor: this, actionName: "Turn");
724 } else {
725 sead::Vector3f playerDirection;
726 al::calcDirToActorH(out: &playerDirection, actor: this, target: al::getPlayerActor(this, 0));
727 if (al::turnToDirection(actor: this, dir: playerDirection, deg: 3.0f) && mWaitDelay == 0)
728 al::startAction(actor: this, actionName: "Wait");
729 }
730
731 updateMovement();
732
733 if (al::isGreaterEqualStep(user: this, step: 4) && tryShiftFall())
734 return;
735
736 if (al::isGreaterEqualStep(user: this, step: 30)) {
737 if (al::calcDistanceH(actor: this, target: al::getPlayerActor(this, 0)) < 1000.0f) {
738 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Find);
739 return;
740 }
741 }
742
743 if (mSpectaclesNerveKeeper->getCurrentNerve() != &MeganeData.NrvMegane.SpectaclesOn &&
744 al::isActionPlaying(actor: this, actionName: "Wait")) {
745 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOn);
746 }
747}
748
749void Megane::exeFind() {
750 if (al::isFirstStep(user: this))
751 al::startAction(actor: this, actionName: "Find");
752
753 al::scaleVelocity(actor: this, factor: 0.9f);
754 if (al::isGreaterEqualStep(user: this, step: 2) &&
755 mSpectaclesNerveKeeper->getCurrentNerve() != &MeganeData.NrvMegane.SpectaclesOff) {
756 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOff);
757 }
758
759 if (tryShiftFall())
760 return;
761
762 if (al::isActionEnd(actor: this))
763 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.RunAway);
764}
765
766void Megane::exeRunAway() {
767 if (al::isFirstStep(user: this)) {
768 al::startAction(actor: this, actionName: "EnemyRun");
769 if (mSpectaclesNerveKeeper->getCurrentNerve() != &MeganeData.NrvMegane.SpectaclesOff)
770 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOff);
771 mRunAwayWallTime = 0;
772 }
773
774 updateRunAwayDirection();
775
776 sead::Vector3f front;
777 al::calcQuatFront(front: &front, actor: this);
778 f32 nerveRate = al::calcNerveRate(user: this, min: 150, max: 180);
779 al::addVelocityToDirection(actor: this, dir: front, force: nerveRate * 0.5f + (1.0f - nerveRate) * 0.7f);
780 updateMovement();
781
782 if (tryShiftFall())
783 return;
784
785 if (al::calcDistanceH(actor: this, target: al::getPlayerActor(this, 0)) > 1200.0f ||
786 al::isGreaterEqualStep(user: this, step: 360)) {
787 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Wait);
788 }
789}
790
791void Megane::exeFall() {
792 if (al::isFirstStep(user: this))
793 al::startAction(actor: this, actionName: "Fall");
794
795 al::scaleVelocity(actor: this, factor: 0.95f);
796 al::addVelocityToGravity(actor: this, force: 2.0f);
797
798 if (al::isOnGround(this, 0)) {
799 al::validateClipping(actor: this);
800 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Land);
801 }
802}
803
804void Megane::exeLand() {
805 if (al::isFirstStep(user: this))
806 al::startAction(actor: this, actionName: "Land");
807
808 updateMovement();
809
810 if (!al::isOnGroundNoVelocity(this, 4)) {
811 al::invalidateClipping(actor: this);
812 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Fall);
813 return;
814 }
815
816 if (al::isActionEnd(actor: this))
817 shiftWaitOrRunAway();
818}
819
820void Megane::exeTrampled() {
821 if (al::isFirstStep(user: this))
822 al::startAction(actor: this, actionName: "Reaction");
823
824 updateMovement();
825
826 if (al::isActionEnd(actor: this))
827 shiftWaitOrRunAway();
828}
829
830void Megane::exeWaitHack() {
831 if (al::isFirstStep(user: this)) {
832 al::getVelocityPtr(actor: this)->set({0.0f, 0.0f, 0.0f});
833 mIsHack = false;
834 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOff);
835 mPlayerPos.set(al::getPlayerPos(this, 0));
836 }
837
838 updateMovement();
839
840 if (al::updateNerveState(user: this) && !mIsHack) {
841 al::validateClipping(actor: this);
842 shiftWaitOrRunAway();
843 }
844}
845
846void Megane::exeHackStart() {
847 if (al::isFirstStep(user: this))
848 al::setVelocityZero(this);
849
850 if (rs::isHackStartDemoEnterMario(mPlayerHack)) {
851 if (!al::isActionPlaying(actor: this, actionName: "HackStart")) {
852 al::startAction(actor: this, actionName: "HackStart");
853 mPlayerHackStartShaderCtrl->start();
854 return;
855 }
856 mPlayerHackStartShaderCtrl->update();
857 if (al::isActionEnd(actor: this)) {
858 mPlayerHackStartShaderCtrl->end();
859 rs::endHackStartDemo(mPlayerHack, this);
860 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Hack);
861 }
862 }
863}
864
865void Megane::exeHack() {
866 if (al::isFirstStep(user: this)) {
867 al::setColliderFilterCollisionParts(this, nullptr);
868 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOff);
869 al::endBgmSituation(this, "WearMeganeGlasses", false);
870 }
871
872 al::updateNerveState(user: this);
873 if (isTriggerStare() && (u32)mSpectaclesNerveKeeper->getCurrentStep() > 4)
874 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOn);
875
876 if (!al::isOnGroundNoVelocity(this, 5)) {
877 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackFall);
878 return;
879 }
880
881 if (isTriggerSubjective() && rs::isEnableStartSubjectiveCamera(actor: this)) {
882 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackSubjective);
883 return;
884 }
885
886 if (mSpectaclesNerveKeeper->getCurrentNerve() == &MeganeData.NrvMegane.SpectaclesOn)
887 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackSlow);
888}
889
890void Megane::exeHackSlow() {
891 if (al::isFirstStep(user: this))
892 al::startBgmSituation(this, "WearMeganeGlasses", false);
893
894 al::holdSe(this, "MoveOverSpectacles");
895 al::updateNerveState(user: this);
896
897 if (isTriggerStare() && (u32)mSpectaclesNerveKeeper->getCurrentStep() > 4)
898 mSpectaclesNerveKeeper->setNerve(&MeganeData.NrvMegane.SpectaclesOff);
899
900 if (!al::isOnGroundNoVelocity(this, 5)) {
901 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackFall);
902 return;
903 }
904
905 if (isTriggerSubjective() && rs::isEnableStartSubjectiveCamera(actor: this)) {
906 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackSubjective);
907 return;
908 }
909
910 if (mSpectaclesNerveKeeper->getCurrentNerve() == &MeganeData.NrvMegane.SpectaclesOff)
911 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Hack);
912}
913
914void Megane::exeHackSubjective() {
915 if (al::isFirstStep(user: this)) {
916 al::startAction(actor: this, actionName: "Wait");
917 startCameraSubjective();
918 }
919
920 if (al::isOnGroundNoVelocity(this, 0))
921 al::setVelocityZero(this);
922 al::addVelocityToGravityNaturalOrFittedGround(actor: this, force: 2.0f);
923
924 faceToCameraFront();
925 tryToggleSpectaclesNerve();
926
927 if (!al::isOnGroundNoVelocity(this, 5)) {
928 endCameraSubjective();
929 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackFall);
930 return;
931 }
932
933 if (isTriggerSubjective() || !rs::isEnableStartSubjectiveCamera(actor: this)) {
934 endCameraSubjective();
935 shiftHackNerveOnGround();
936 }
937}
938
939void Megane::exeHackFall() {
940 if (al::isFirstStep(user: this))
941 al::startAction(actor: this, actionName: "Fall");
942
943 al::scaleVelocity(actor: this, factor: 0.95f);
944 al::addVelocityToGravity(actor: this, force: 2.0f);
945 tryToggleSpectaclesNerve();
946
947 if (al::isOnGround(this, 0)) {
948 if (al::isGreaterEqualStep(user: this, step: 15))
949 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackLand);
950 else
951 shiftHackNerveOnGround();
952 }
953}
954
955void Megane::exeHackLand() {
956 if (al::isFirstStep(user: this))
957 al::startAction(actor: this, actionName: "Land");
958
959 al::scaleVelocity(actor: this, factor: al::isOnGround(this, 0) ? 0.0f : 0.95f);
960 al::addVelocityToGravityNaturalOrFittedGround(actor: this, force: 2.0f);
961
962 tryToggleSpectaclesNerve();
963
964 if (!al::isOnGround(this, 5)) {
965 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.HackFall);
966 return;
967 }
968
969 if (al::isActionEnd(actor: this))
970 shiftHackNerveOnGround();
971}
972
973void Megane::exeDie() {
974 if (al::isFirstStep(user: this)) {
975 al::hideModelIfShow(actor: this);
976 al::startHitReaction(actor: this, name: "死亡");
977 al::setVelocityZero(this);
978 al::startAction(actor: this, actionName: "Wait");
979 al::stopAction(actor: this);
980 al::endBgmSituation(this, "WearMeganeGlasses", false);
981 }
982
983 if (al::isGreaterEqualStep(user: this, step: 120))
984 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Rebirth);
985}
986
987void Megane::exeRebirth() {
988 if (al::isFirstStep(user: this)) {
989 al::setQuat(actor: this, quat: mStartingQuat);
990 al::resetPosition(actor: this, trans: mStartingPos);
991 }
992
993 if (al::isStep(user: this, step: 180))
994 al::startHitReaction(actor: this, name: "出現予兆");
995
996 if (al::isGreaterEqualStep(user: this, step: 300)) {
997 al::validateClipping(actor: this);
998 al::showModelIfHide(actor: this);
999 al::showModelIfHide(actor: al::getSubActor(actor: this, subActorName: "メガネ"));
1000 al::tryDeleteEffect(this, "AppearSign");
1001 al::startHitReaction(actor: this, name: "出現");
1002 al::faceToPlayer(this);
1003 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Appear);
1004 }
1005}
1006
1007void Megane::exeAppear() {
1008 if (al::isFirstStep(user: this)) {
1009 al::startAction(actor: this, actionName: "Appear");
1010 al::getVelocityPtr(actor: this)->set({0.0f, 0.0f, 0.0f});
1011 putOnSpectaclesForce();
1012 }
1013
1014 updateMovement();
1015
1016 if (al::isGreaterEqualStep(user: this, step: 4) && tryShiftFall())
1017 return;
1018
1019 if (al::isActionEnd(actor: this))
1020 al::setNerve(user: this, nerve: &MeganeData.NrvMegane.Wait);
1021}
1022
1023void Megane::exeSpectaclesOff() {
1024 if (mSpectaclesNerveKeeper->getCurrentStep() == 0 && isHack())
1025 al::startHitReaction(actor: this, name: "メガネを外した");
1026
1027 al::LiveActor* subActor = al::tryGetSubActor(actor: this, subActorName: "メガネ");
1028
1029 if (!mTestFilterGlasses->isEnd()) {
1030 mTestFilterGlasses->end();
1031 if (subActor)
1032 al::startSe(subActor, "SpectaclesOff");
1033 }
1034
1035 if (subActor) {
1036 if (isHack() && !rs::isHackCapSeparateFlying(mPlayerHack)) {
1037 if (!al::isActionPlaying(actor: subActor, actionName: "SpectaclesOff")) {
1038 bool isActionPlaying = al::isActionPlaying(actor: subActor, actionName: "SpectaclesOffEnemy");
1039 al::startAction(actor: subActor, actionName: "SpectaclesOff");
1040 if (isActionPlaying)
1041 al::setActionFrame(actor: subActor, frame: al::getActionFrameMax(actor: this) - 1.0f);
1042 }
1043 return;
1044 }
1045
1046 if (!al::isActionPlaying(actor: subActor, actionName: "SpectaclesOffEnemy")) {
1047 bool isActionPlaying = al::isActionPlaying(actor: subActor, actionName: "SpectaclesOff");
1048 al::startAction(actor: subActor, actionName: "SpectaclesOffEnemy");
1049 if (isActionPlaying)
1050 al::setActionFrame(actor: subActor, frame: al::getActionFrameMax(actor: this) - 1.0f);
1051 }
1052 }
1053}
1054
1055void Megane::exeSpectaclesOn() {
1056 if (mSpectaclesNerveKeeper->getCurrentStep() == 0 && isHack())
1057 al::startHitReaction(actor: this, name: "メガネをかけた");
1058
1059 al::LiveActor* subActor = al::tryGetSubActor(actor: this, subActorName: "メガネ");
1060 if (isHack()) {
1061 if (!mTestFilterGlasses->isAlive()) {
1062 mTestFilterGlasses->startAppear();
1063 if (subActor)
1064 al::startSe(subActor, "SpectaclesOn");
1065 }
1066 } else if (!mTestFilterGlasses->isEnd()) {
1067 mTestFilterGlasses->end();
1068 }
1069
1070 mSpectaclesOnCounter++;
1071 if (subActor && !al::isActionPlaying(actor: subActor, actionName: "SpectaclesOn")) {
1072 al::startAction(actor: subActor, actionName: "SpectaclesOn");
1073 mSpectaclesOnCounter = 0;
1074 }
1075}
1076