| 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 | |
| 45 | namespace { |
| 46 | NERVE_IMPL(Megane, Wait) |
| 47 | NERVE_IMPL(Megane, Find) |
| 48 | NERVE_IMPL(Megane, RunAway) |
| 49 | NERVE_IMPL(Megane, Fall) |
| 50 | NERVE_IMPL(Megane, Land) |
| 51 | NERVE_IMPL(Megane, Trampled) |
| 52 | NERVE_IMPL(Megane, WaitHack) |
| 53 | NERVE_IMPL(Megane, HackStart) |
| 54 | NERVE_IMPL(Megane, Hack) |
| 55 | NERVE_IMPL(Megane, HackSlow) |
| 56 | NERVE_IMPL(Megane, HackSubjective) |
| 57 | NERVE_IMPL(Megane, HackFall) |
| 58 | NERVE_IMPL(Megane, HackLand) |
| 59 | NERVE_IMPL(Megane, Die) |
| 60 | NERVE_IMPL(Megane, Rebirth) |
| 61 | NERVE_IMPL(Megane, Appear) |
| 62 | NERVE_IMPL(Megane, SpectaclesOff) |
| 63 | NERVE_IMPL(Megane, SpectaclesOn) |
| 64 | |
| 65 | struct 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 |
| 73 | struct { |
| 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 | |
| 91 | Megane::Megane(const char* name) : al::LiveActor(name) {} |
| 92 | |
| 93 | void 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 | |
| 160 | bool 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 | |
| 358 | void 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 | |
| 394 | void 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 | |
| 412 | void 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 | |
| 477 | void 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 | |
| 493 | bool Megane::isNerveDieOrRebirth() const { |
| 494 | return al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Die) || |
| 495 | al::isNerve(user: this, nerve: &MeganeData.NrvMegane.Rebirth); |
| 496 | } |
| 497 | |
| 498 | bool Megane::isNormalNerveWithWaitHack() const { |
| 499 | return isNormalNerveWithoutWaitHack() || al::isNerve(user: this, nerve: &MeganeData.NrvMegane.WaitHack); |
| 500 | } |
| 501 | |
| 502 | bool 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 | |
| 512 | bool 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 | |
| 528 | void 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 | |
| 535 | void Megane::endCameraSubjective() { |
| 536 | if (al::isActiveCamera(ticket: mCameraTicket)) |
| 537 | al::endCamera(user: this, ticket: mCameraTicket, -1, false); |
| 538 | } |
| 539 | |
| 540 | bool Megane::isHack() const { |
| 541 | return mPlayerHack != nullptr; |
| 542 | } |
| 543 | |
| 544 | bool 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 | |
| 553 | void 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 | |
| 562 | bool 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 | |
| 571 | void 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 | |
| 592 | void 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 | |
| 599 | bool Megane::isTriggerStare() const { |
| 600 | return rs::isTriggerHackAnyButton(mPlayerHack) || rs::isTriggerHackSwing(mPlayerHack); |
| 601 | } |
| 602 | |
| 603 | bool Megane::isTriggerSubjective() const { |
| 604 | return rs::isTriggerSubjectiveCamera(mPlayerHack) && al::isOnGround(this, 0); |
| 605 | } |
| 606 | |
| 607 | void 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 | |
| 621 | void 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 | |
| 629 | void 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 | |
| 638 | void 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 | |
| 645 | void 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 | |
| 653 | bool Megane::isWearingGlasses() const { |
| 654 | return isHack() && |
| 655 | mSpectaclesNerveKeeper->getCurrentNerve() == &MeganeData.NrvMegane.SpectaclesOn; |
| 656 | } |
| 657 | |
| 658 | void 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 | |
| 684 | void 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 | |
| 705 | void 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 | |
| 749 | void 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 | |
| 766 | void 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 | |
| 791 | void 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 | |
| 804 | void 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 | |
| 820 | void 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 | |
| 830 | void 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 | |
| 846 | void 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 | |
| 865 | void 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 | |
| 890 | void 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 | |
| 914 | void 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 | |
| 939 | void 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 | |
| 955 | void 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 | |
| 973 | void 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 | |
| 987 | void 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 | |
| 1007 | void 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 | |
| 1023 | void 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 | |
| 1055 | void 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 | |