Enemy: Implement Kuribo2D (#664)

This commit is contained in:
Shishu the Dragon 2025-07-02 00:04:38 +12:00 committed by GitHub
parent 54cbb6d20e
commit 633e51654b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 325 additions and 28 deletions

View file

@ -35638,112 +35638,112 @@ Enemy/Kuribo2D.o:
- offset: 0x149b78
size: 188
label: _ZN8Kuribo2DC2EPKc
status: NotDecompiled
status: Matching
- offset: 0x149c34
size: 184
label: _ZN8Kuribo2DC1EPKc
status: NotDecompiled
status: Matching
- offset: 0x149cec
size: 352
label: _ZN8Kuribo2D4initERKN2al13ActorInitInfoE
status: NotDecompiled
status: Matching
- offset: 0x149e4c
size: 112
label: _ZN8Kuribo2D9startWalkEv
status: NotDecompiled
status: Matching
- offset: 0x149ebc
size: 84
label: _ZN8Kuribo2D5resetEv
status: NotDecompiled
status: Matching
- offset: 0x149f10
size: 228
label: _ZN8Kuribo2D12attackSensorEPN2al9HitSensorES2_
status: NotDecompiled
status: Matching
- offset: 0x149ff4
size: 360
label: _ZN8Kuribo2D10receiveMsgEPKN2al9SensorMsgEPNS0_9HitSensorES5_
status: NotDecompiled
status: Matching
- offset: 0x14a15c
size: 76
label: _ZN8Kuribo2D7controlEv
status: NotDecompiled
status: Matching
- offset: 0x14a1a8
size: 204
label: _ZN8Kuribo2D17appearByGeneratorERKN4sead7Vector3IfEES4_
status: NotDecompiled
status: Matching
- offset: 0x14a274
size: 16
label: _ZNK8Kuribo2D6isWaitEv
status: NotDecompiled
status: Matching
- offset: 0x14a284
size: 60
label: _ZN8Kuribo2D7exeWaitEv
status: NotDecompiled
status: Matching
- offset: 0x14a2c0
size: 196
label: _ZN8Kuribo2D20exeFallAfterGenerateEv
status: NotDecompiled
status: Matching
- offset: 0x14a384
size: 508
label: _ZN8Kuribo2D7exeWalkEv
status: NotDecompiled
status: Matching
- offset: 0x14a580
size: 112
label: _ZN8Kuribo2D12exePressDownEv
status: NotDecompiled
status: Matching
- offset: 0x14a5f0
size: 228
label: _ZN8Kuribo2D11exeBlowDownEv
status: NotDecompiled
status: Matching
- offset: 0x14a6d4
size: 8
label: _ZNK8Kuribo2D23getActorDimensionKeeperEv
status: NotDecompiled
status: Matching
lazy: true
- offset: 0x14a6dc
size: 8
label: _ZThn264_NK8Kuribo2D23getActorDimensionKeeperEv
status: NotDecompiled
status: Matching
lazy: true
- offset: 0x14a6e4
size: 8
label: _ZNK12_GLOBAL__N_115Kuribo2DNrvWalk7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x14a6ec
size: 64
label: _ZNK12_GLOBAL__N_115Kuribo2DNrvWait7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x14a72c
size: 116
label: _ZNK12_GLOBAL__N_120Kuribo2DNrvPressDown7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x14a7a0
size: 8
label: _ZNK12_GLOBAL__N_119Kuribo2DNrvBlowDown7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x14a7a8
size: 8
label: _ZNK12_GLOBAL__N_128Kuribo2DNrvFallAfterGenerate7executeEPN2al11NerveKeeperE
status: NotDecompiled
status: Matching
guess: true
- offset: 0x14a7b0
size: 28
label: _ZNK2al10FunctorV0MIP8Kuribo2DMS1_FvvEEclEv
status: NotDecompiled
status: Matching
lazy: true
- offset: 0x14a7cc
size: 76
label: _ZNK2al10FunctorV0MIP8Kuribo2DMS1_FvvEE5cloneEv
status: NotDecompiled
status: Matching
lazy: true
- offset: 0x14a818
size: 4
label: _ZN2al10FunctorV0MIP8Kuribo2DMS1_FvvEED0Ev
status: NotDecompiled
status: Matching
lazy: true
Enemy/KuriboGenerator2D.o:
'.text':
@ -134704,7 +134704,7 @@ Scene/ProjectActorFactory.o:
- offset: 0x4b93f0
size: 52
label: _ZN2al19createActorFunctionI8Kuribo2DEEPNS_9LiveActorEPKc
status: NotDecompiled
status: Matching
lazy: true
- offset: 0x4b9424
size: 52

251
src/Enemy/Kuribo2D.cpp Normal file
View file

@ -0,0 +1,251 @@
#include "Enemy/Kuribo2D.h"
#include "Library/Item/ItemUtil.h"
#include "Library/LiveActor/ActorActionFunction.h"
#include "Library/LiveActor/ActorAreaFunction.h"
#include "Library/LiveActor/ActorClippingFunction.h"
#include "Library/LiveActor/ActorCollisionFunction.h"
#include "Library/LiveActor/ActorFlagFunction.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 "Library/Stage/StageSwitchUtil.h"
#include "Library/Thread/FunctorV0M.h"
#include "Util/ActorDimensionUtil.h"
#include "Util/ItemUtil.h"
#include "Util/SensorMsgFunction.h"
namespace {
NERVE_IMPL(Kuribo2D, Walk)
NERVE_IMPL(Kuribo2D, Wait)
NERVE_IMPL(Kuribo2D, PressDown)
NERVE_IMPL(Kuribo2D, BlowDown)
NERVE_IMPL(Kuribo2D, FallAfterGenerate)
NERVES_MAKE_STRUCT(Kuribo2D, Walk, Wait, PressDown, BlowDown, FallAfterGenerate)
} // namespace
Kuribo2D::Kuribo2D(const char* name) : al::LiveActor(name) {}
void Kuribo2D::init(const al::ActorInitInfo& initInfo) {
using Kuribo2DFunctor = al::FunctorV0M<Kuribo2D*, void (Kuribo2D::*)()>;
al::initActorWithArchiveName(this, initInfo, "Kuribo2D", nullptr);
al::initNerve(this, &NrvKuribo2D.Walk, 0);
rs::createAndSetFilter2DOnly(this);
mDimensionKeeper = rs::createDimensionKeeper(this);
rs::updateDimensionKeeper(mDimensionKeeper);
if (!rs::isIn2DArea(this)) {
makeActorDead();
return;
}
rs::snap2D(this, this, 500.0f);
if (al::listenStageSwitchOnStart(this, Kuribo2DFunctor(this, &Kuribo2D::startWalk)))
al::setNerve(this, &NrvKuribo2D.Wait);
mInitTrans.set(al::getTrans(this));
mInitFront.set(al::getFront(this));
al::listenStageSwitchOn(this, "SwitchReset", Kuribo2DFunctor(this, &Kuribo2D::reset));
makeActorAlive();
}
void Kuribo2D::startWalk() {
al::onCollide(this);
al::validateClipping(this);
rs::updateDimensionKeeper(mDimensionKeeper);
rs::snap2D(this, this, 500.0f);
if (al::isOnGround(this, 0))
al::setNerve(this, &NrvKuribo2D.Walk);
else
al::setNerve(this, &NrvKuribo2D.FallAfterGenerate);
}
void Kuribo2D::reset() {
al::setTrans(this, mInitTrans);
al::setFront(this, mInitFront);
al::onCollide(this);
appear();
al::setNerve(this, &NrvKuribo2D.Walk);
}
void Kuribo2D::attackSensor(al::HitSensor* self, al::HitSensor* other) {
if (al::isNerve(this, &NrvKuribo2D.PressDown) || al::isNerve(this, &NrvKuribo2D.BlowDown))
return;
if (al::isSensorEnemyBody(self) && al::isSensorEnemyBody(other) &&
rs::sendMsgPush2D(other, self)) {
if (al::isFaceToTargetDegreeH(this, al::getSensorPos(other), al::getFront(this), 5.0f)) {
al::turnFront(this, 180.0f);
al::setVelocityToFront(this, 2.5f);
}
}
if (al::isSensorEnemyAttack(self))
rs::sendMsgEnemyAttack2D(other, self);
}
bool Kuribo2D::receiveMsg(const al::SensorMsg* message, al::HitSensor* other, al::HitSensor* self) {
if (al::isMsgPlayerDisregard(message))
return true;
if (al::isNerve(this, &NrvKuribo2D.PressDown) || al::isNerve(this, &NrvKuribo2D.BlowDown))
return false;
if (rs::isMsgBlockUpperPunch2D(message))
return receiveDefeatMsg(message, other, self, &NrvKuribo2D.BlowDown);
if (rs::isMsgPush2D(message)) {
if (al::isFaceToTargetDegreeH(this, al::getSensorPos(other), al::getFront(this), 5.0f)) {
al::turnFront(this, 180.0f);
al::addVelocityToFront(this, 5.0f);
}
return true;
}
if (rs::isMsgPlayerTrample2D(message))
return receiveDefeatMsg(message, other, self, &NrvKuribo2D.PressDown);
if (rs::isMsgKouraAttack2D(message))
return receiveDefeatMsg(message, other, self, &NrvKuribo2D.BlowDown);
return false;
}
void Kuribo2D::control() {
if (al::isInDeathArea(this)) {
al::startHitReaction(this, "消滅");
kill();
}
}
void Kuribo2D::appearByGenerator(const sead::Vector3f& trans, const sead::Vector3f& front) {
al::setTrans(this, trans);
al::setFront(this, front);
rs::updateDimensionKeeper(mDimensionKeeper);
if (!rs::isIn2DArea(this)) {
kill();
return;
}
sead::Vector3f dimensionGravity;
rs::calcDimensionGravity(&dimensionGravity, this, al::getGravity(this));
al::setGravity(this, dimensionGravity);
al::setVelocityZero(this);
al::offCollide(this);
al::invalidateHitSensors(this);
appear();
al::setNerve(this, &NrvKuribo2D.Wait);
}
bool Kuribo2D::isWait() const {
return al::isNerve(this, &NrvKuribo2D.Wait);
}
void Kuribo2D::exeWalk() {
if (al::isFirstStep(this)) {
al::startAction(this, "Walk");
al::setVelocityToFront(this, 2.5f);
}
rs::updateDimensionKeeper(mDimensionKeeper);
if (!rs::isIn2DArea(this)) {
kill();
return;
}
rs::snap2D(this, this, 500.0f);
if (al::isCollidedWall(this)) {
const sead::Vector3f& wallNormal = al::getCollidedWallNormal(this);
if (wallNormal.dot(al::getFront(this)) < 0.1f) {
al::turnFront(this, 180.0f);
al::addVelocityToFront(this, 5.0f);
updateCollider();
}
}
al::addVelocityToGravity(this, 0.65f);
al::scaleVelocityDirection(this, al::getGravity(this), 0.98f);
al::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f);
sead::Vector3f horizVel = al::getVelocity(this);
al::verticalizeVec(&horizVel, al::getGravity(this), horizVel);
f32 horizSpeed = horizVel.length();
if (horizSpeed != 0.0f && !al::isNear(horizSpeed, 2.5f)) {
if (al::tryNormalizeOrZero(&horizVel))
al::scaleVelocityDirection(this, horizVel, 2.5f / horizSpeed);
}
}
void Kuribo2D::exeWait() {
if (al::isFirstStep(this))
al::startAction(this, "Wait");
}
void Kuribo2D::exePressDown() {
if (al::isFirstStep(this)) {
al::startAction(this, "PressDown");
al::setVelocityZero(this);
}
if (al::isActionEnd(this)) {
al::startHitReaction(this, "消滅");
kill();
}
}
void Kuribo2D::exeBlowDown() {
sead::Vector3f dimensionGravity;
rs::calcDimensionGravity(&dimensionGravity, this, al::getGravity(this));
if (al::isFirstStep(this)) {
al::startAction(this, "Down");
al::offCollide(this);
al::invalidateClipping(this);
al::addVelocityToDirection(this, -dimensionGravity, 15.6f);
}
al::addVelocityToDirection(this, dimensionGravity, 0.73f);
al::scaleVelocity(this, 0.98f);
if (al::isGreaterEqualStep(this, 270)) {
al::onCollide(this);
kill();
}
}
void Kuribo2D::exeFallAfterGenerate() {
rs::updateDimensionKeeper(mDimensionKeeper);
if (!rs::isIn2DArea(this)) {
kill();
return;
}
rs::snap2D(this, this, 500.0f);
if (al::isOnGround(this, 0)) {
al::setNerve(this, &NrvKuribo2D.Walk);
return;
}
al::addVelocityToGravity(this, 0.65f);
al::scaleVelocityDirection(this, al::getGravity(this), 0.98f);
al::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f);
}
bool Kuribo2D::receiveDefeatMsg(const al::SensorMsg* message, al::HitSensor* other,
al::HitSensor* self, al::Nerve* nextNerve) {
rs::setAppearItemFactorAndOffsetByMsg(this, message, other);
rs::requestHitReactionToAttacker(message, self, other);
al::appearItem(this);
al::setNerve(this, nextNerve);
return true;
}

42
src/Enemy/Kuribo2D.h Normal file
View file

@ -0,0 +1,42 @@
#pragma once
#include "Library/LiveActor/LiveActor.h"
#include "Util/IUseDimension.h"
namespace al {
class Nerve;
}
class Kuribo2D : public al::LiveActor, public IUseDimension {
public:
Kuribo2D(const char* name);
void init(const al::ActorInitInfo& initInfo) override;
void startWalk();
void reset();
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;
void appearByGenerator(const sead::Vector3f& trans, const sead::Vector3f& front);
bool isWait() const;
void exeWalk();
void exeWait();
void exePressDown();
void exeBlowDown();
void exeFallAfterGenerate();
ActorDimensionKeeper* getActorDimensionKeeper() const override { return mDimensionKeeper; }
private:
ActorDimensionKeeper* mDimensionKeeper = nullptr;
sead::Vector3f mInitTrans = sead::Vector3f::zero;
sead::Vector3f mInitFront = sead::Vector3f::zero;
inline bool receiveDefeatMsg(const al::SensorMsg* message, al::HitSensor* other,
al::HitSensor* self, al::Nerve* nextNerve);
};
static_assert(sizeof(Kuribo2D) == 0x130);

View file

@ -32,6 +32,7 @@
#include "Boss/Mofumofu/MofumofuScrap.h"
#include "Enemy/Gamane.h"
#include "Enemy/KaronWing.h"
#include "Enemy/Kuribo2D.h"
#include "Enemy/Mummy.h"
#include "Enemy/Nokonoko2D.h"
#include "Enemy/Pecho.h"
@ -345,7 +346,7 @@ const al::NameToCreator<al::ActorCreatorFunction> sProjectActorFactoryEntries[]
{"KoopaLv2", nullptr},
{"KoopaLv3", nullptr},
{"KoopaShip", nullptr},
{"Kuribo2D3D", nullptr},
{"Kuribo2D3D", al::createActorFunction<Kuribo2D>},
{"KuriboGenerator2D3D", nullptr},
{"KuriboGirl", al::createActorFunction<KuriboGirl>},
{"KuriboPossessed", nullptr},

View file

@ -414,10 +414,11 @@ def header_check_line(line, path, visibility, should_start_class, is_in_struct):
"Functions ending with an underscore are either protected or private!", path)
elif visibility == 2: # private
if line == "};" or line == "" or line == "union {" or line.startswith("struct") or line.startswith("enum"): return
if "(" in line and ")" in line: return
newline = line
if "=" in line:
newline = line.split("=")[0].strip()
elif "(" in line or ")" in line:
return
elif line.endswith(";"):
newline = line.split(";")[0].strip()
else:
@ -571,6 +572,8 @@ def main():
for dir in [project_root/'lib'/'al', project_root/'src']:
for root, _, files in os.walk(dir):
for file in files:
if os.path.basename(file) == ".DS_Store":
continue
file_path = os.path.join(root, file)
file_str = str(file_path)
if args.run_clang_format: