diff --git a/data/file_list.yml b/data/file_list.yml index 64c53263..67c7659c 100644 --- a/data/file_list.yml +++ b/data/file_list.yml @@ -3324,7 +3324,7 @@ Boss/BossForest/BossForest.o: - offset: 0x0183d8 size: 4 label: _ZN12IUseDemoSkip22updateOnlyDemoGraphicsEv - status: NotDecompiled + status: Matching lazy: true - offset: 0x0183dc size: 8 @@ -18326,79 +18326,79 @@ Boss/Koopa/KoopaStateDeadAndDemoBattleEnd.o: label: - _ZN30KoopaStateDeadAndDemoBattleEndC1EPN2al9LiveActorEP17KoopaDemoExecutorP8KoopaCapP17KoopaWeaponHolderS2_b - _ZN30KoopaStateDeadAndDemoBattleEndC2EPN2al9LiveActorEP17KoopaDemoExecutorP8KoopaCapP17KoopaWeaponHolderS2_b - status: NotDecompiled + status: Matching - offset: 0x09daa8 size: 48 label: _ZN30KoopaStateDeadAndDemoBattleEnd6appearEv - status: NotDecompiled + status: Matching - offset: 0x09dad8 size: 72 label: _ZN30KoopaStateDeadAndDemoBattleEnd4killEv - status: NotDecompiled + status: Matching - offset: 0x09db20 size: 52 label: _ZNK30KoopaStateDeadAndDemoBattleEnd11isFirstDemoEv - status: NotDecompiled + status: Matching - offset: 0x09db54 size: 52 label: _ZThn32_NK30KoopaStateDeadAndDemoBattleEnd11isFirstDemoEv - status: NotDecompiled + status: Matching - offset: 0x09db88 size: 68 label: _ZNK30KoopaStateDeadAndDemoBattleEnd16isEnableSkipDemoEv - status: NotDecompiled + status: Matching - offset: 0x09dbcc size: 72 label: _ZThn32_NK30KoopaStateDeadAndDemoBattleEnd16isEnableSkipDemoEv - status: NotDecompiled + status: Matching - offset: 0x09dc14 size: 72 label: _ZN30KoopaStateDeadAndDemoBattleEnd8skipDemoEv - status: NotDecompiled + status: Matching - offset: 0x09dc5c size: 76 label: _ZThn32_N30KoopaStateDeadAndDemoBattleEnd8skipDemoEv - status: NotDecompiled + status: Matching - offset: 0x09dca8 size: 160 label: _ZN30KoopaStateDeadAndDemoBattleEnd7exeDeadEv - status: NotDecompiled + status: Matching - offset: 0x09dd48 size: 76 label: _ZN30KoopaStateDeadAndDemoBattleEnd8exeStartEv - status: NotDecompiled + status: Matching - offset: 0x09dd94 size: 120 label: _ZN30KoopaStateDeadAndDemoBattleEnd7exeDemoEv - status: NotDecompiled + status: Matching - offset: 0x09de0c size: 4 label: _ZN30KoopaStateDeadAndDemoBattleEnd7exeSkipEv - status: NotDecompiled + status: Matching - offset: 0x09de10 size: 36 label: _ZN30KoopaStateDeadAndDemoBattleEndD0Ev - status: NotDecompiled + status: Matching lazy: true - offset: 0x09de34 size: 8 label: _ZNK12_GLOBAL__N_137KoopaStateDeadAndDemoBattleEndNrvDead7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x09de3c size: 8 label: _ZNK12_GLOBAL__N_137KoopaStateDeadAndDemoBattleEndNrvDemo7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x09de44 size: 4 label: _ZNK12_GLOBAL__N_137KoopaStateDeadAndDemoBattleEndNrvSkip7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x09de48 size: 76 label: _ZNK12_GLOBAL__N_138KoopaStateDeadAndDemoBattleEndNrvStart7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true Boss/Koopa/KoopaStateDemoBattleStart.o: '.text': diff --git a/src/Boss/Koopa/KoopaCap.h b/src/Boss/Koopa/KoopaCap.h new file mode 100644 index 00000000..6b0a4e88 --- /dev/null +++ b/src/Boss/Koopa/KoopaCap.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include + +#include "Library/LiveActor/LiveActor.h" + +namespace al { +struct ActorInitInfo; +class HitSensor; +class LiveActor; +class SensorMsg; +} // namespace al + +class KoopaCapPlayerBinder; + +class KoopaCap : public al::LiveActor { +public: + static KoopaCap* create(const al::LiveActor*, const al::ActorInitInfo&, KoopaCapPlayerBinder*, + bool); + + KoopaCap(const char*, const al::LiveActor*); + + void init(const al::ActorInitInfo&) override; + void makeActorDead() override; + void appear() override; + void kill() override; + void disappear(); + void control() override; + void updateCollider() override; + void attackSensor(al::HitSensor* self, al::HitSensor* other) override; + bool receiveMsg(const al::SensorMsg* message, al::HitSensor* other, + al::HitSensor* self) override; + bool isEquip() const; + bool isWaitHover() const; + bool isDown() const; + bool isEndWaitHoverStart() const; + bool isSpinMove() const; + bool isAttach() const; + bool isNecessaryUpdateAttachQT() const; + bool isFlyBack() const; + bool isEndFlyBack() const; + bool isDownRecover() const; + bool isPlayingCatchDemo() const; + bool isPlayerBinding() const; + void startDemo(); + void endDemo(); + void startAttach(const char*); + void startWaitHover(s32); + void startSpinThrowChase(const sead::Vector3f*, f32, bool); + void startDownRecover(); + void forceStartFlyBackIfNearPlayerToKoopa(); + void requestStartAction(const char*); + void onFinish(); + void offFinish(); + void setFastPunchRate(f32); + void endEquipAndBlowDown(); + void endEquipAndKill(); + void exeDemo(); + void exeAppear(); + void exeWait(); + void exeAttach(); + void exeWaitHoverDelay(); + void exeWaitHoverStart(); + void exeWaitHover(); + void exeSpinThrow(); + void exeFlyBack(); + void exeFlyBackAfter(); + void exeSpinHit(); + void exeDownJumpStart(); + void exeDownJump(); + void exeDownJumpEnd(); + void exeDown(); + void exeDownRecoverStart(); + void exeDownRecover(); + void exeDownRecoverEnd(); + void exeEquip(); + +private: + const al::LiveActor* mOwner = nullptr; + u8 _110[0x60]; +}; + +static_assert(sizeof(KoopaCap) == 0x170); diff --git a/src/Boss/Koopa/KoopaDemoExecutor.h b/src/Boss/Koopa/KoopaDemoExecutor.h new file mode 100644 index 00000000..36ec55cb --- /dev/null +++ b/src/Boss/Koopa/KoopaDemoExecutor.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +namespace al { +struct ActorInitInfo; +class AddDemoInfo; +class EventFlowExecutor; +class LiveActor; +} // namespace al + +class ChurchDoor; +class IUseDemoSkip; +class KoopaCameraCtrl; +class KoopaCap; +class KoopaShip; +class Peach; + +class KoopaDemoExecutor { +public: + KoopaDemoExecutor(); + + void init(al::LiveActor*, const al::ActorInitInfo&, al::EventFlowExecutor*, KoopaCameraCtrl*, + Peach*); + void initLv1(const al::ActorInitInfo&, al::LiveActor*, KoopaCap*, KoopaShip*); + void registerDemoModel(al::LiveActor*); + void initMoonChurch(const al::ActorInitInfo&, ChurchDoor*, al::LiveActor*); + void initLv2(const al::ActorInitInfo&, al::LiveActor*, KoopaCap*, al::LiveActor*); + bool update(); + void startDemoAction(const char*, bool); + void skip(); + void killAll(); + bool tryStartChurchEnterDemo(IUseDemoSkip*, al::AddDemoInfo*); + void start(const char*); + bool tryStartChurchStartDemo(IUseDemoSkip*, al::AddDemoInfo*); + bool tryStartBattleStartDemo(IUseDemoSkip*); + bool tryStartBattleEndDemo(IUseDemoSkip* demoSkip); + bool tryStartClashBasementDemo(IUseDemoSkip*); + +private: + u8 _0[0x120]; +}; + +static_assert(sizeof(KoopaDemoExecutor) == 0x120); diff --git a/src/Boss/Koopa/KoopaStateDeadAndDemoBattleEnd.cpp b/src/Boss/Koopa/KoopaStateDeadAndDemoBattleEnd.cpp new file mode 100644 index 00000000..bf665294 --- /dev/null +++ b/src/Boss/Koopa/KoopaStateDeadAndDemoBattleEnd.cpp @@ -0,0 +1,107 @@ +#include "Boss/Koopa/KoopaStateDeadAndDemoBattleEnd.h" + +#include "Library/LiveActor/ActorActionFunction.h" +#include "Library/LiveActor/ActorMovementFunction.h" +#include "Library/LiveActor/ActorSensorUtil.h" +#include "Library/Nerve/NerveSetupUtil.h" +#include "Library/Nerve/NerveUtil.h" + +#include "Boss/BossUtil/BossUtil.h" +#include "Boss/Koopa/KoopaCap.h" +#include "Boss/Koopa/KoopaDemoExecutor.h" +#include "Boss/Koopa/KoopaFunction.h" +#include "Boss/Koopa/KoopaWeaponHolder.h" +#include "Util/DemoUtil.h" + +namespace { +IUseDemoSkip* getDemoSkip(KoopaStateDeadAndDemoBattleEnd* state) { + return state; +} + +NERVE_IMPL(KoopaStateDeadAndDemoBattleEnd, Dead); +NERVE_IMPL(KoopaStateDeadAndDemoBattleEnd, Demo); +NERVE_IMPL(KoopaStateDeadAndDemoBattleEnd, Skip); +NERVE_IMPL(KoopaStateDeadAndDemoBattleEnd, Start); +NERVES_MAKE_NOSTRUCT(KoopaStateDeadAndDemoBattleEnd, Dead, Demo, Skip, Start); +} // namespace + +KoopaStateDeadAndDemoBattleEnd::KoopaStateDeadAndDemoBattleEnd( + al::LiveActor* actor, KoopaDemoExecutor* demoExecutor, KoopaCap* cap, + KoopaWeaponHolder* weaponHolder, al::LiveActor* demoActor, bool isKoopaLv2) + : al::ActorStateBase("死亡~戦闘終了デモ", actor), mDemoExecutor(demoExecutor), mCap(cap), + mWeaponHolder(weaponHolder), mDemoActor(demoActor), mIsKoopaLv2(isKoopaLv2) { + initNerve(&Dead, 0); +} + +void KoopaStateDeadAndDemoBattleEnd::appear() { + NerveStateBase::appear(); + al::setNerve(this, &Dead); + al::invalidateHitSensors(mActor); +} + +void KoopaStateDeadAndDemoBattleEnd::kill() { + NerveStateBase::kill(); + rs::requestEndDemoWithPlayer(mActor); + if (mIsKoopaLv2) + rs::saveShowDemoBossBattleEndKoopaLv2(mActor); + mDemoActor->makeActorDead(); +} + +bool KoopaStateDeadAndDemoBattleEnd::isFirstDemo() const { + if (mIsKoopaLv2) + return rs::isAlreadyShowDemoBossBattleEndKoopaLv2(mActor) ^ 1; + return true; +} + +bool KoopaStateDeadAndDemoBattleEnd::isEnableSkipDemo() const { + if (al::isNerve(this, &Demo)) + return al::isFirstStep(this) ^ 1; + return false; +} + +void KoopaStateDeadAndDemoBattleEnd::skipDemo() { + mDemoExecutor->skip(); + KoopaFunction::onSwitchGraphicsLevelBattleEnd(mActor); + al::setNerve(this, &Skip); + kill(); +} + +void KoopaStateDeadAndDemoBattleEnd::exeDead() { + if (al::isFirstStep(this)) { + al::startAction(mActor, "Die"); + al::setVelocityZero(mActor); + } + + if (al::isStep(this, 1)) + al::startHitReaction(mActor, "ダメージとどめ"); + + if (al::isActionEnd(mActor)) { + KoopaStateDeadAndDemoBattleEnd* demoSkip = this; + if (mDemoExecutor->tryStartBattleEndDemo(demoSkip)) { + al::setNerve(this, &Demo); + return; + } + al::setNerve(this, &Start); + } +} + +void KoopaStateDeadAndDemoBattleEnd::exeStart() { + if (mDemoExecutor->tryStartBattleEndDemo(getDemoSkip(this))) + al::setNerve(this, &Demo); +} + +void KoopaStateDeadAndDemoBattleEnd::exeDemo() { + if (al::isFirstStep(this)) { + mCap->endEquipAndKill(); + mWeaponHolder->makeActorDeadAll(); + KoopaFunction::offSwitchBattleKeepOn(mActor); + } + + if (al::isGreaterEqualStep(this, 436)) + KoopaFunction::onSwitchGraphicsLevelBattleEnd(mActor); + + if (mDemoExecutor->update()) + kill(); +} + +void KoopaStateDeadAndDemoBattleEnd::exeSkip() {} diff --git a/src/Boss/Koopa/KoopaStateDeadAndDemoBattleEnd.h b/src/Boss/Koopa/KoopaStateDeadAndDemoBattleEnd.h new file mode 100644 index 00000000..da62f434 --- /dev/null +++ b/src/Boss/Koopa/KoopaStateDeadAndDemoBattleEnd.h @@ -0,0 +1,40 @@ +#pragma once + +#include "Library/Nerve/NerveStateBase.h" + +#include "Demo/IUseDemoSkip.h" + +namespace al { +class LiveActor; +} + +class KoopaCap; +class KoopaDemoExecutor; +class KoopaWeaponHolder; + +class KoopaStateDeadAndDemoBattleEnd : public al::ActorStateBase, public IUseDemoSkip { +public: + KoopaStateDeadAndDemoBattleEnd(al::LiveActor* actor, KoopaDemoExecutor* demoExecutor, + KoopaCap* cap, KoopaWeaponHolder* weaponHolder, + al::LiveActor* demoActor, bool isKoopaLv2); + + void appear() override; + void kill() override; + bool isFirstDemo() const override; + bool isEnableSkipDemo() const override; + void skipDemo() override; + + void exeDead(); + void exeStart(); + void exeDemo(); + void exeSkip(); + +private: + KoopaDemoExecutor* mDemoExecutor = nullptr; + KoopaCap* mCap = nullptr; + KoopaWeaponHolder* mWeaponHolder = nullptr; + al::LiveActor* mDemoActor = nullptr; + bool mIsKoopaLv2 = false; +}; + +static_assert(sizeof(KoopaStateDeadAndDemoBattleEnd) == 0x50); diff --git a/src/Boss/Koopa/KoopaWeaponHolder.h b/src/Boss/Koopa/KoopaWeaponHolder.h new file mode 100644 index 00000000..0fce64fa --- /dev/null +++ b/src/Boss/Koopa/KoopaWeaponHolder.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace al { +struct ActorInitInfo; +class LiveActor; +} // namespace al + +class KoopaCap; + +class KoopaWeaponHolder { +public: + static KoopaWeaponHolder* create(const al::LiveActor*, const al::ActorInitInfo&, s32); + + KoopaWeaponHolder(); + void makeActorDeadAll(); + void killAll(); + void cancelAll(); + void* findDeadDamageBall() const; + void* findDeadDamageBallBomb() const; + void disappearAllDummyCap(); + void killAllDummyCapWaitHover(); + bool isAllAliveDummyCapWaitHover() const; + KoopaCap* getDummyCap(s32) const; + KoopaCap* findDeadDummyCap() const; + void resetWeaponItemGenerateLimitByDamage(); + +private: + void* mItemHolder = nullptr; + void* mRingBeamEmitter = nullptr; + void* mWeaponCapGroup = nullptr; + void* mDamageBallGroup = nullptr; + void* mDamageBallBombGroup = nullptr; +}; + +static_assert(sizeof(KoopaWeaponHolder) == 0x28);