From 9090655294b12dccaf5bc3bed8a82378f1afc43d Mon Sep 17 00:00:00 2001 From: guymakinggames <66076221+guymakinggames@users.noreply.github.com> Date: Wed, 22 Apr 2026 22:27:25 +0100 Subject: [PATCH] MapObj: Implement `BossKnuckleFix` (#1021) --- data/file_list.yml | 22 ++++---- src/MapObj/BossKnuckleFix.cpp | 89 +++++++++++++++++++++++++++++++ src/MapObj/BossKnuckleFix.h | 31 +++++++++++ src/Scene/ProjectActorFactory.cpp | 3 +- 4 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 src/MapObj/BossKnuckleFix.cpp create mode 100644 src/MapObj/BossKnuckleFix.h diff --git a/data/file_list.yml b/data/file_list.yml index 988def97..81aedb62 100644 --- a/data/file_list.yml +++ b/data/file_list.yml @@ -59551,45 +59551,45 @@ MapObj/BossKnuckleFix.o: - offset: 0x222ee4 size: 128 label: _ZN14BossKnuckleFixC2EPKc - status: NotDecompiled + status: Matching - offset: 0x222f64 size: 140 label: _ZN14BossKnuckleFixC1EPKc - status: NotDecompiled + status: Matching - offset: 0x222ff0 size: 336 label: _ZN14BossKnuckleFix4initERKN2al13ActorInitInfoE - status: NotDecompiled + status: Matching - offset: 0x223140 size: 208 label: _ZN14BossKnuckleFix10receiveMsgEPKN2al9SensorMsgEPNS0_9HitSensorES5_ - status: NotDecompiled + status: Matching - offset: 0x223210 size: 60 label: _ZN14BossKnuckleFix7exeWaitEv - status: NotDecompiled + status: Matching - offset: 0x22324c size: 88 label: _ZN14BossKnuckleFix11exeReactionEv - status: NotDecompiled + status: Matching - offset: 0x2232a4 size: 104 label: _ZN14BossKnuckleFix16exeReactionLargeEv - status: NotDecompiled + status: Matching - offset: 0x22330c size: 64 label: _ZNK12_GLOBAL__N_121BossKnuckleFixNrvWait7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x22334c size: 108 label: _ZNK12_GLOBAL__N_130BossKnuckleFixNrvReactionLarge7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x2233b8 size: 92 label: _ZNK12_GLOBAL__N_125BossKnuckleFixNrvReaction7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true MapObj/BreakablePole.o: '.text': @@ -133676,7 +133676,7 @@ Scene/ProjectActorFactory.o: - offset: 0x4b66dc size: 52 label: _ZN2al19createActorFunctionI14BossKnuckleFixEEPNS_9LiveActorEPKc - status: NotDecompiled + status: Matching lazy: true - offset: 0x4b6710 size: 52 diff --git a/src/MapObj/BossKnuckleFix.cpp b/src/MapObj/BossKnuckleFix.cpp new file mode 100644 index 00000000..a763c45e --- /dev/null +++ b/src/MapObj/BossKnuckleFix.cpp @@ -0,0 +1,89 @@ +#include "MapObj/BossKnuckleFix.h" + +#include + +#include "Library/LiveActor/ActorActionFunction.h" +#include "Library/LiveActor/ActorAnimFunction.h" +#include "Library/LiveActor/ActorCollisionFunction.h" +#include "Library/LiveActor/ActorInitUtil.h" +#include "Library/LiveActor/ActorPoseUtil.h" +#include "Library/LiveActor/ActorResourceFunction.h" +#include "Library/LiveActor/ActorSensorUtil.h" +#include "Library/LiveActor/LiveActorFunction.h" +#include "Library/Nerve/NerveSetupUtil.h" +#include "Library/Nerve/NerveUtil.h" +#include "Library/Obj/CollisionObj.h" +#include "Library/Stage/StageSwitchUtil.h" + +#include "Util/SensorMsgFunction.h" + +namespace { +NERVE_IMPL(BossKnuckleFix, Wait); +NERVE_IMPL(BossKnuckleFix, ReactionLarge); +NERVE_IMPL(BossKnuckleFix, Reaction); + +NERVES_MAKE_STRUCT(BossKnuckleFix, Wait, ReactionLarge, Reaction); +} // namespace + +BossKnuckleFix::BossKnuckleFix(const char* name) : al::LiveActor(name) {} + +void BossKnuckleFix::init(const al::ActorInitInfo& info) { + al::initActorWithArchiveName(this, info, "BossKnuckleBody", "Fix"); + al::initNerve(this, &NrvBossKnuckleFix.Wait, 0); + // NOTE: color of embedded grand shine is hardcoded to 5 (Sand) + al::startMclAnimAndSetFrameAndStop(al::getSubActor(this, "グランドシャイン"), "Color", 5.0f); + al::trySyncStageSwitchKill(this); + makeActorAlive(); + + mCollisionObj = new al::CollisionObj(info, al::getModelResource(this), "MoveLimit", + al::getHitSensor(this, "Body"), nullptr, nullptr); + al::setCollisionPartsSpecialPurposeName(mCollisionObj, "MoveLimit"); + al::setTrans(mCollisionObj, al::getTrans(this)); + al::setRotate(mCollisionObj, {0.0f, 90.0f, 0.0f}); + mCollisionObj->makeActorAlive(); +} + +bool BossKnuckleFix::receiveMsg(const al::SensorMsg* message, al::HitSensor* other, + al::HitSensor* self) { + if (rs::isMsgPlayerDisregardHomingAttack(message)) + return true; + + if (al::isNerve(this, &NrvBossKnuckleFix.Wait) && + (rs::isMsgSphinxRideAttackTouch(message) || rs::isMsgPlayerAndCapHipDropAll(message))) { + rs::requestHitReactionToAttacker(message, self, other); + + mReactionCount++; + if (mReactionCount >= 3) { + mReactionCount = 0; + al::setNerve(this, &NrvBossKnuckleFix.ReactionLarge); + } else + al::setNerve(this, &NrvBossKnuckleFix.Reaction); + + return !rs::isMsgPlayerAndCapHipDropAll(message); + } + + return false; +} + +void BossKnuckleFix::exeWait() { + if (al::isFirstStep(this)) + al::startAction(this, "MapWait"); +} + +void BossKnuckleFix::exeReaction() { + if (al::isFirstStep(this)) + al::startAction(this, "MapReaction"); + + if (al::isActionEnd(this)) + al::setNerve(this, &NrvBossKnuckleFix.Wait); +} + +void BossKnuckleFix::exeReactionLarge() { + if (al::isFirstStep(this)) { + al::startAction(this, "MapReactionLarge"); + al::tryOnStageSwitch(this, "ReactionOn"); + } + + if (al::isActionEnd(this)) + al::setNerve(this, &NrvBossKnuckleFix.Wait); +} diff --git a/src/MapObj/BossKnuckleFix.h b/src/MapObj/BossKnuckleFix.h new file mode 100644 index 00000000..3217b7a8 --- /dev/null +++ b/src/MapObj/BossKnuckleFix.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "Library/LiveActor/LiveActor.h" + +namespace al { +struct ActorInitInfo; +class CollisionObj; +class HitSensor; +class SensorMsg; +} // namespace al + +class BossKnuckleFix : public al::LiveActor { +public: + BossKnuckleFix(const char* name); + + void init(const al::ActorInitInfo& info) override; + bool receiveMsg(const al::SensorMsg* message, al::HitSensor* other, + al::HitSensor* self) override; + + void exeWait(); + void exeReaction(); + void exeReactionLarge(); + +private: + al::CollisionObj* mCollisionObj = nullptr; + s32 mReactionCount = 0; +}; + +static_assert(sizeof(BossKnuckleFix) == 0x118); diff --git a/src/Scene/ProjectActorFactory.cpp b/src/Scene/ProjectActorFactory.cpp index 41bddf29..62ad88e4 100644 --- a/src/Scene/ProjectActorFactory.cpp +++ b/src/Scene/ProjectActorFactory.cpp @@ -69,6 +69,7 @@ #include "MapObj/AllDeadWatcherWithShine.h" #include "MapObj/AnagramAlphabet.h" #include "MapObj/BlockEmpty2D.h" +#include "MapObj/BossKnuckleFix.h" #include "MapObj/CapBomb.h" #include "MapObj/CapHanger.h" #include "MapObj/CapSwitch.h" @@ -164,7 +165,7 @@ const al::NameToCreator sProjectActorFactoryEntries[] {"BossForestWander", al::createActorFunction}, {"BossKnuckle", nullptr}, {"BossKnuckleCounterGround", nullptr}, - {"BossKnuckleFix", nullptr}, + {"BossKnuckleFix", al::createActorFunction}, {"BossMagma", nullptr}, {"BossRaid", nullptr}, {"BossRaidNpc", nullptr},