diff --git a/data/file_list.yml b/data/file_list.yml index 037dbedb29..0fcd0d4a3b 100644 --- a/data/file_list.yml +++ b/data/file_list.yml @@ -130133,45 +130133,45 @@ Player/YoshiStateEgg.o: label: - _ZN13YoshiStateEggC1ERKN2al13ActorInitInfoEPNS0_9LiveActorEPK19IUsePlayerCollisionPK11PlayerConstPKNS0_18WaterSurfaceFinderEP23PlayerModelChangerYoshi - _ZN13YoshiStateEggC2ERKN2al13ActorInitInfoEPNS0_9LiveActorEPK19IUsePlayerCollisionPK11PlayerConstPKNS0_18WaterSurfaceFinderEP23PlayerModelChangerYoshi - status: NotDecompiled + status: Matching - offset: 0x49775c size: 104 label: _ZN13YoshiStateEgg6appearEv - status: NotDecompiled + status: Matching - offset: 0x4977c4 size: 16 label: _ZN13YoshiStateEgg4killEv - status: NotDecompiled + status: Matching - offset: 0x4977d4 size: 92 label: _ZN13YoshiStateEgg9exeAppearEv - status: NotDecompiled + status: Matching - offset: 0x497830 size: 260 - label: '' - status: NotDecompiled + label: _ZN12_GLOBAL__N_113updateEggMoveEPN2al9LiveActorEPK19IUsePlayerCollisionPK11PlayerConst + status: Matching - offset: 0x497934 size: 100 label: _ZN13YoshiStateEgg7exeWaitEv - status: NotDecompiled + status: Matching - offset: 0x497998 size: 128 label: _ZN13YoshiStateEgg29reactionCollidedCollisionCodeEv - status: NotDecompiled + status: Matching - offset: 0x497a18 size: 36 label: _ZN13YoshiStateEggD0Ev - status: NotDecompiled + status: Matching lazy: true - offset: 0x497a3c size: 104 label: _ZNK12_GLOBAL__N_120YoshiStateEggNrvWait7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x497aa4 size: 96 label: _ZNK12_GLOBAL__N_122YoshiStateEggNrvAppear7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true Player/YoshiStateHack.o: '.text': diff --git a/src/Player/PlayerModelChangerYoshi.h b/src/Player/PlayerModelChangerYoshi.h new file mode 100644 index 0000000000..99a25c9034 --- /dev/null +++ b/src/Player/PlayerModelChangerYoshi.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include "Library/HostIO/HioNode.h" + +#include "Player/IPlayerModelChanger.h" + +namespace al { +class LiveActor; +} // namespace al + +class PlayerModelHolder; + +class PlayerModelChangerYoshi : public al::HioNode, public IPlayerModelChanger { +public: + PlayerModelChangerYoshi(const al::LiveActor* host, PlayerModelHolder* modelHolder); + + bool isFireFlower() const override; + bool isMini() const override; + bool isChange() const override; + bool is2DModel() const override; + bool isHiddenModel() const override; + bool isHiddenShadowMask() const override; + void resetPosition() override; + void hideModel() override; + void hideSilhouette() override; + void hideShadowMask() override; + void showModel() override; + void showSilhouette() override; + void showShadowMask() override; + + void syncHost(); + void syncModelFlag(al::LiveActor* actor); + void appearModel(); + void killModel(); + void changeModel(al::LiveActor* actor); + +private: + const al::LiveActor* mHost = nullptr; + al::LiveActor* mModelActor = nullptr; + PlayerModelHolder* mModelHolder = nullptr; + u16 mModelFlags = 0; + bool mIsSilhouetteVisible = false; + u8 _23[0x35] = {}; +}; + +static_assert(sizeof(PlayerModelChangerYoshi) == 0x58); diff --git a/src/Player/YoshiEgg.h b/src/Player/YoshiEgg.h new file mode 100644 index 0000000000..271bcc5022 --- /dev/null +++ b/src/Player/YoshiEgg.h @@ -0,0 +1,37 @@ +#pragma once + +#include "Library/LiveActor/LiveActor.h" + +class IUsePlayerCollision; + +namespace al { +struct ActorInitInfo; +class HitSensor; +class SensorMsg; +} // namespace al + +class YoshiEgg : public al::LiveActor { +public: + YoshiEgg(const al::LiveActor* host, const IUsePlayerCollision* collision); + + 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 initPlacementEgg(); + void appearEgg(); + bool isEndAppear() const; + bool isBreak() const; + void exeAppear(); + void exeWait(); + void exeBreak(); + +private: + const al::LiveActor* mHost = nullptr; + const IUsePlayerCollision* mCollision = nullptr; + al::HitSensor* mBodySensor = nullptr; +}; + +static_assert(sizeof(YoshiEgg) == 0x120); diff --git a/src/Player/YoshiStateEgg.cpp b/src/Player/YoshiStateEgg.cpp new file mode 100644 index 0000000000..1c6d9e647d --- /dev/null +++ b/src/Player/YoshiStateEgg.cpp @@ -0,0 +1,112 @@ +#include "Player/YoshiStateEgg.h" + +#include "Library/LiveActor/ActorActionFunction.h" +#include "Library/LiveActor/ActorAreaFunction.h" +#include "Library/LiveActor/ActorClippingFunction.h" +#include "Library/LiveActor/ActorMovementFunction.h" +#include "Library/LiveActor/ActorPoseUtil.h" +#include "Library/LiveActor/ActorSensorUtil.h" +#include "Library/Nature/NatureUtil.h" +#include "Library/Nerve/NerveSetupUtil.h" +#include "Library/Nerve/NerveUtil.h" + +#include "Player/PlayerConst.h" +#include "Player/PlayerModelChangerYoshi.h" +#include "Player/YoshiEgg.h" +#include "Util/ObjUtil.h" +#include "Util/PlayerCollisionUtil.h" +#include "Util/PlayerHackFunction.h" + +namespace { +void updateEggMove(al::LiveActor* actor, const IUsePlayerCollision* collision, + const PlayerConst* playerConst); + +NERVE_IMPL(YoshiStateEgg, Wait); +NERVE_IMPL(YoshiStateEgg, Appear); + +NERVES_MAKE_NOSTRUCT(YoshiStateEgg, Wait, Appear); +} // namespace + +YoshiStateEgg::YoshiStateEgg(const al::ActorInitInfo& info, al::LiveActor* player, + const IUsePlayerCollision* collision, const PlayerConst* playerConst, + const al::WaterSurfaceFinder* waterSurfaceFinder, + PlayerModelChangerYoshi* modelChanger) + : al::ActorStateBase("卵", player), mCollision(collision), mConst(playerConst), + mWaterSurfaceFinder(waterSurfaceFinder), mModelChanger(modelChanger) { + mEgg = new YoshiEgg(player, collision); + mEgg->init(info); + initNerve(&Wait, 0); +} + +void YoshiStateEgg::appear() { + al::ActorStateBase::appear(); + mEgg->kill(); + al::invalidateHitSensors(mActor); + + if (mIsFirstPlacement) { + mIsFirstPlacement = false; + mEgg->initPlacementEgg(); + al::setNerve(this, &Wait); + } else { + al::setNerve(this, &Appear); + } +} + +void YoshiStateEgg::kill() { + al::ActorStateBase::kill(); + al::validateHitSensors(mActor); +} + +void YoshiStateEgg::exeAppear() { + if (al::isFirstStep(this)) + mEgg->appearEgg(); + + updateEggMove(mActor, mCollision, mConst); + + if (mEgg->isEndAppear()) + al::setNerve(this, &Wait); +} + +namespace { +void updateEggMove(al::LiveActor* actor, const IUsePlayerCollision* collision, + const PlayerConst* playerConst) { + if (rs::isCollidedGround(collision)) { + rs::waitGround(actor, collision, playerConst->getGravity(), playerConst->getFallSpeedMax(), + playerConst->getSlerpQuatGrav(), 0.0f); + return; + } + + const sead::Vector3f& gravity = al::getGravity(actor); + f32 gravityValue = playerConst->getGravity(); + sead::Vector3f velocity = {gravityValue * gravity.x, gravityValue * gravity.y, + gravityValue * gravity.z}; + al::tryAddVelocityLimit(actor, velocity, playerConst->getFallSpeedMax()); +} +} // namespace + +void YoshiStateEgg::exeWait() { + if (al::isFirstStep(this)) + al::validateClipping(mActor); + + updateEggMove(mActor, mCollision, mConst); + + if (mEgg->isBreak()) { + mModelChanger->appearModel(); + kill(); + } +} + +bool YoshiStateEgg::reactionCollidedCollisionCode() { + if (isDead()) + return false; + + al::LiveActor* player = mActor; + if (al::isInDeathArea(player) || + (al::isNerve(this, &Wait) && + (rs::isTouchHackCancelCollisionCode(player, mCollision) || al::isInWater(player)))) { + al::startHitReaction(player, "[ヨッシー]死亡"); + return true; + } + + return false; +} diff --git a/src/Player/YoshiStateEgg.h b/src/Player/YoshiStateEgg.h new file mode 100644 index 0000000000..21eb71765d --- /dev/null +++ b/src/Player/YoshiStateEgg.h @@ -0,0 +1,38 @@ +#pragma once + +#include "Library/Nerve/NerveStateBase.h" + +namespace al { +struct ActorInitInfo; +class WaterSurfaceFinder; +} // namespace al + +class IUsePlayerCollision; +class PlayerConst; +class PlayerModelChangerYoshi; +class YoshiEgg; + +class YoshiStateEgg : public al::ActorStateBase { +public: + YoshiStateEgg(const al::ActorInitInfo& info, al::LiveActor* player, + const IUsePlayerCollision* collision, const PlayerConst* playerConst, + const al::WaterSurfaceFinder* waterSurfaceFinder, + PlayerModelChangerYoshi* modelChanger); + + void appear() override; + void kill() override; + + void exeAppear(); + void exeWait(); + bool reactionCollidedCollisionCode(); + +private: + const IUsePlayerCollision* mCollision = nullptr; + const PlayerConst* mConst = nullptr; + const al::WaterSurfaceFinder* mWaterSurfaceFinder = nullptr; + YoshiEgg* mEgg = nullptr; + PlayerModelChangerYoshi* mModelChanger = nullptr; + bool mIsFirstPlacement = true; +}; + +static_assert(sizeof(YoshiStateEgg) == 0x50);