MapObj: Implement RocketFlower (#1024)
Some checks are pending
Compile and verify functions / compile_verify (push) Waiting to run
Copy headers to separate repo / copy_headers (push) Waiting to run
decomp-dev / publish_progress_decomp_dev (1.0) (push) Waiting to run
lint / clang-format (push) Waiting to run
lint / custom-lint (push) Waiting to run
Check and verify that setup works on NixOS / nixos_verify (push) Waiting to run
progress / publish_progress (push) Waiting to run
testcompile / test_compile (push) Waiting to run
Trigger full-sync on the tracker repo on push / api-trigger-workflow (push) Waiting to run

This commit is contained in:
guymakinggames 2026-04-22 23:55:05 +01:00 committed by GitHub
parent 129691c069
commit 0f550e5aae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 329 additions and 26 deletions

View file

@ -82302,103 +82302,103 @@ MapObj/RocketFlower.o:
- offset: 0x2fd628
size: 128
label: _ZN12RocketFlowerC2EPKc
status: NotDecompiled
status: Matching
- offset: 0x2fd6a8
size: 140
label: _ZN12RocketFlowerC1EPKc
status: NotDecompiled
status: Matching
- offset: 0x2fd734
size: 268
label: _ZN12RocketFlower4initERKN2al13ActorInitInfoE
status: NotDecompiled
status: Matching
- offset: 0x2fd840
size: 28
label: _ZN12RocketFlower18initAfterPlacementEv
status: NotDecompiled
status: Matching
- offset: 0x2fd85c
size: 156
label: _ZN12RocketFlower12attackSensorEPN2al9HitSensorES2_
status: NotDecompiled
status: Matching
- offset: 0x2fd8f8
size: 84
label: _ZNK12RocketFlower13isEnableEquipEv
status: NotDecompiled
status: Matching
- offset: 0x2fd94c
size: 664
label: _ZN12RocketFlower10receiveMsgEPKN2al9SensorMsgEPNS0_9HitSensorES5_
status: NotDecompiled
status: Matching
- offset: 0x2fdbe4
size: 116
label: _ZN12RocketFlower15terminateFollowEv
status: NotDecompiled
status: Matching
- offset: 0x2fdc58
size: 76
label: _ZN12RocketFlower7exeWaitEv
status: NotDecompiled
status: Matching
- offset: 0x2fdca4
size: 100
label: _ZN12RocketFlower13exeWaitFollowEv
status: NotDecompiled
status: Matching
- offset: 0x2fdd08
size: 412
label: _ZN12RocketFlower19trySyncFlyingCapPosEv
status: NotDecompiled
status: Matching
- offset: 0x2fdea4
size: 324
label: _ZN12RocketFlower9exeFollowEv
status: NotDecompiled
status: Matching
- offset: 0x2fdfe8
size: 108
label: _ZN12RocketFlower15appearFlowerSubEv
status: NotDecompiled
status: Matching
- offset: 0x2fe054
size: 164
label: _ZN12RocketFlower13exeWaitAttachEv
status: NotDecompiled
status: Matching
- offset: 0x2fe0f8
size: 60
label: _ZN12RocketFlower9exeAttachEv
status: NotDecompiled
status: Matching
- offset: 0x2fe134
size: 48
label: _ZN12RocketFlower19setFollowFlowerPoseERKN4sead4QuatIfEERKNS0_7Vector3IfEE
status: NotDecompiled
status: Matching
- offset: 0x2fe164
size: 16
label: _ZN12RocketFlower9disappearEv
status: NotDecompiled
status: Matching
- offset: 0x2fe174
size: 124
label: _ZN12RocketFlower14disappearForceEv
status: NotDecompiled
status: Matching
- offset: 0x2fe1f0
size: 104
label: _ZN12RocketFlower7controlEv
status: NotDecompiled
status: Matching
- offset: 0x2fe258
size: 80
label: _ZNK12_GLOBAL__N_119RocketFlowerNrvWait7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x2fe2a8
size: 64
label: _ZNK12_GLOBAL__N_121RocketFlowerNrvAttach7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x2fe2e8
size: 104
label: _ZNK12_GLOBAL__N_125RocketFlowerNrvWaitFollow7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x2fe350
size: 8
label: _ZNK12_GLOBAL__N_121RocketFlowerNrvFollow7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x2fe358
size: 8
label: _ZNK12_GLOBAL__N_125RocketFlowerNrvWaitAttach7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
MapObj/RocketFlowerEquipWatcher.o:
'.text':
@ -135906,7 +135906,7 @@ Scene/ProjectActorFactory.o:
- offset: 0x4bd180
size: 52
label: _ZN2al19createActorFunctionI12RocketFlowerEEPNS_9LiveActorEPKc
status: NotDecompiled
status: Matching
lazy: true
- offset: 0x4bd1b4
size: 52

237
src/MapObj/RocketFlower.cpp Normal file
View file

@ -0,0 +1,237 @@
#include "MapObj/RocketFlower.h"
#include "Library/Collision/PartsConnectorUtil.h"
#include "Library/Effect/EffectSystemInfo.h"
#include "Library/LiveActor/ActorActionFunction.h"
#include "Library/LiveActor/ActorAnimFunction.h"
#include "Library/LiveActor/ActorClippingFunction.h"
#include "Library/LiveActor/ActorInitUtil.h"
#include "Library/LiveActor/ActorMovementFunction.h"
#include "Library/LiveActor/ActorPoseUtil.h"
#include "Library/LiveActor/ActorSensorUtil.h"
#include "Library/Math/MathUtil.h"
#include "Library/Nerve/NerveSetupUtil.h"
#include "Library/Nerve/NerveUtil.h"
#include "MapObj/RocketFlowerFunction.h"
#include "Util/PlayerUtil.h"
#include "Util/SensorMsgFunction.h"
namespace {
NERVE_IMPL(RocketFlower, Wait);
NERVE_IMPL(RocketFlower, Attach);
NERVE_IMPL(RocketFlower, WaitFollow);
NERVE_IMPL(RocketFlower, Follow);
NERVE_IMPL(RocketFlower, WaitAttach);
NERVES_MAKE_STRUCT(RocketFlower, Wait, Attach, WaitFollow, Follow, WaitAttach);
} // namespace
RocketFlower::RocketFlower(const char* name) : al::LiveActor(name) {}
void RocketFlower::init(const al::ActorInitInfo& info) {
al::initActor(this, info);
al::initNerve(this, &NrvRocketFlower.Wait, 0);
makeActorAlive();
mMtxConnector = al::tryCreateMtxConnector(this, info);
mFlowerSub = new al::LiveActor("ロケットフラワーの花");
al::initChildActorWithArchiveNameNoPlacementInfo(mFlowerSub, info, "RocketFlowerDash", nullptr);
al::startAction(mFlowerSub, "Wait");
mFlowerSub->makeActorDead();
RocketFlowerFunction::createRocketFlowerEquipWatcherIfNotExist(this, info);
al::setHitSensorPosPtr(this, "Equip", al::getTransPtr(mFlowerSub));
al::startAction(this, "Wait");
}
void RocketFlower::initAfterPlacement() {
if (mMtxConnector)
al::attachMtxConnectorToCollision(mMtxConnector, this, false);
}
void RocketFlower::attackSensor(al::HitSensor* self, al::HitSensor* other) {
if (!al::isSensorName(self, "Equip"))
return;
if (isEnableEquip()) {
if (rs::sendMsgRocketFlowerExtension(other, self))
al::setNerve(this, &NrvRocketFlower.Attach);
}
}
bool RocketFlower::isEnableEquip() const {
if (al::isNerve(this, &NrvRocketFlower.Follow) && !al::isNewNerve(this))
return true;
return al::isNerve(this, &NrvRocketFlower.WaitAttach);
}
bool RocketFlower::receiveMsg(const al::SensorMsg* message, al::HitSensor* other,
al::HitSensor* self) {
if (al::isMsgPlayerSpinAttack(message)) {
if (al::isNerve(this, &NrvRocketFlower.Wait)) {
al::invalidateClipping(this);
al::setNerve(this, &NrvRocketFlower.WaitFollow);
}
} else if (rs::isMsgCapItemGet(message)) {
if (al::isNerve(this, &NrvRocketFlower.Wait)) {
al::invalidateClipping(this);
al::setNerve(this, &NrvRocketFlower.Follow);
return true;
}
} else if (al::isMsgPlayerObjTouch(message) || rs::isMsgBlowObjAttack(message) ||
rs::isMsgFireDamageAll(message) || rs::isMsgHammerBrosHammerEnemyAttack(message) ||
rs::isMsgHammerBrosHammerHackAttack(message) || rs::isMsgHosuiAttack(message) ||
al::isMsgEnemyAttack(message) || al::isMsgKickStoneAttack(message) ||
rs::isMsgRadishAttack(message) || rs::isMsgSeedAttack(message) ||
rs::isMsgTankBullet(message) || rs::isMsgGamaneBulletThrough(message) ||
rs::isMsgHackAttackPoison(message) || rs::isMsgYoshiTongueAttack(message)) {
if (al::isSensorMapObj(self)) {
if (mReactionFrame == 0)
al::startAction(this, "Reaction");
mReactionFrame = 30;
}
} else if (rs::isMsgCapAttack(message)) {
if (al::isSensorMapObj(self) && !al::isNerve(this, &NrvRocketFlower.Wait) &&
!al::isNerve(this, &NrvRocketFlower.WaitFollow)) {
if (mReactionFrame == 0)
al::startAction(this, "Reaction");
mReactionFrame = 30;
}
} else if (al::isMsgPlayerPutOnEquipment(message) && al::isSensorName(self, "Equip") &&
isEnableEquip()) {
if (RocketFlowerFunction::requestEquipRocketFlower(this, other)) {
al::setNerve(this, &NrvRocketFlower.Attach);
return true;
}
terminateFollow();
}
return false;
}
void RocketFlower::terminateFollow() {
al::invalidateHitSensor(this, "Equip");
al::validateClipping(this);
mFlowerSub->kill();
al::startAction(this, "Appear");
mReactionFrame = 30;
al::startHitReaction(this, "復帰");
al::setNerve(this, &NrvRocketFlower.Wait);
}
void RocketFlower::exeWait() {
if (al::isFirstStep(this)) {
al::startVisAnim(this, "Show");
al::invalidateHitSensor(this, "Equip");
}
}
void RocketFlower::exeWaitFollow() {
if (trySyncFlyingCapPos()) {
al::setNerve(this, &NrvRocketFlower.Follow);
return;
}
if (al::isGreaterEqualStep(this, 30)) {
al::validateClipping(this);
al::setNerve(this, &NrvRocketFlower.Wait);
}
}
bool RocketFlower::trySyncFlyingCapPos() {
sead::Vector3f flyingCapPos;
if (!rs::tryGetFlyingCapPos(&flyingCapPos, this))
return false;
flyingCapPos += 50.0f * sead::Vector3f::ey;
al::resetPosition(mFlowerSub, flyingCapPos);
sead::Vector3f toPlayerHead = rs::getPlayerHeadPos(this) - flyingCapPos;
if (al::tryNormalizeOrZero(&toPlayerHead)) {
sead::Quatf quat;
quat.makeVectorRotation(sead::Vector3f::ez, toPlayerHead);
al::setQuat(mFlowerSub, quat);
}
return true;
}
void RocketFlower::exeFollow() {
if (al::isFirstStep(this)) {
appearFlowerSub();
mFollowLostFrame = 0;
}
if (trySyncFlyingCapPos()) {
mFollowLostFrame = 0;
return;
}
if (rs::isEquipCapCatched(this)) {
al::validateHitSensor(this, "Equip");
al::setNerve(this, &NrvRocketFlower.WaitAttach);
return;
}
if (mFollowLostFrame >= 16)
terminateFollow();
mFollowLostFrame++;
}
void RocketFlower::appearFlowerSub() {
al::startVisAnim(this, "Hide");
mFlowerSub->appear();
al::startAction(mFlowerSub, "Wait");
al::startAction(this, "ReactionCap");
mReactionFrame = 30;
al::startHitReaction(this, "花が取れた");
}
void RocketFlower::exeWaitAttach() {
rs::tryCalcPlayerModelHeadJointPos(al::getTransPtr(mFlowerSub), this);
if (al::isGreaterEqualStep(this, 20))
terminateFollow();
}
void RocketFlower::exeAttach() {
if (al::isFirstStep(this))
al::startAction(mFlowerSub, "Dash");
}
void RocketFlower::setFollowFlowerPose(const sead::Quatf& quat, const sead::Vector3f& trans) {
al::setQuat(mFlowerSub, quat);
al::resetPosition(mFlowerSub, trans);
}
void RocketFlower::disappear() {
al::startHitReaction(mFlowerSub, "消滅");
}
void RocketFlower::disappearForce() {
al::tryKillEmitterAndParticleAll(mFlowerSub);
al::invalidateHitSensor(this, "Equip");
al::validateClipping(this);
mFlowerSub->kill();
al::startAction(this, "Wait");
mReactionFrame = 30;
al::setNerve(this, &NrvRocketFlower.Wait);
}
void RocketFlower::control() {
if (al::isActionOneTime(this) && al::isActionEnd(this))
al::startAction(this, "Wait");
if (mReactionFrame != 0)
mReactionFrame--;
if (mMtxConnector)
al::connectPoseQT(this, mMtxConnector);
}

48
src/MapObj/RocketFlower.h Normal file
View file

@ -0,0 +1,48 @@
#pragma once
#include <math/seadQuat.h>
#include <math/seadVector.h>
#include "Library/LiveActor/LiveActor.h"
namespace al {
struct ActorInitInfo;
class HitSensor;
class MtxConnector;
class SensorMsg;
} // namespace al
class RocketFlower : public al::LiveActor {
public:
RocketFlower(const char* name);
void init(const al::ActorInitInfo& info) override;
void initAfterPlacement() override;
void attackSensor(al::HitSensor* self, al::HitSensor* other) override;
bool receiveMsg(const al::SensorMsg* message, al::HitSensor* other,
al::HitSensor* self) override;
void control() override;
bool isEnableEquip() const;
void terminateFollow();
void exeWait();
void exeWaitFollow();
bool trySyncFlyingCapPos();
void exeFollow();
void appearFlowerSub();
void exeWaitAttach();
void exeAttach();
void setFollowFlowerPose(const sead::Quatf& quat, const sead::Vector3f& trans);
void disappear();
void disappearForce();
private:
al::MtxConnector* mMtxConnector = nullptr;
al::LiveActor* mFlowerSub = nullptr;
s32 mReactionFrame = 0;
u32 mFollowLostFrame = 0;
};
static_assert(sizeof(RocketFlower) == 0x120);

View file

@ -0,0 +1,17 @@
#pragma once
namespace al {
struct ActorInitInfo;
class HitSensor;
class LiveActor;
} // namespace al
class RocketFlower;
namespace RocketFlowerFunction {
void createRocketFlowerEquipWatcherIfNotExist(const al::LiveActor* actor,
const al::ActorInitInfo& info);
bool requestEquipRocketFlower(RocketFlower* flower, al::HitSensor* sensor);
} // namespace RocketFlowerFunction

View file

@ -95,6 +95,7 @@
#include "MapObj/PoleGrabCeil.h"
#include "MapObj/ReactionMapParts.h"
#include "MapObj/RiseMapPartsHolder.h"
#include "MapObj/RocketFlower.h"
#include "MapObj/RouletteSwitch.h"
#include "MapObj/SaveFlagCheckObj.h"
#include "MapObj/ShineTowerRocket.h"
@ -672,7 +673,7 @@ const al::NameToCreator<al::ActorCreatorFunction> sProjectActorFactoryEntries[]
{"RiseMapParts", nullptr},
{"ReactionMapParts", al::createActorFunction<ReactionMapParts>},
{"RiseMapPartsHolder", al::createActorFunction<RiseMapPartsHolder>},
{"RocketFlower", nullptr},
{"RocketFlower", al::createActorFunction<RocketFlower>},
{"RollingCubeMapParts", al::createActorFunction<al::RollingCubeMapParts>},
{"RippleFixMapParts", nullptr},
{"RotateMapParts", al::createActorFunction<al::RotateMapParts>},