From b30be5a37cca4649b69fd29a360456f28c12e3d5 Mon Sep 17 00:00:00 2001 From: CaptainProton42 Date: Sun, 31 May 2026 10:07:28 +0100 Subject: [PATCH] emario initial pass --- include/Enemy/Emario.hpp | 51 +++++++ include/Enemy/EnemyMario.hpp | 38 +++++ src/Enemy/emario.cpp | 266 +++++++++++++++++++++++++++++++++++ 3 files changed, 355 insertions(+) create mode 100644 include/Enemy/Emario.hpp create mode 100644 include/Enemy/EnemyMario.hpp diff --git a/include/Enemy/Emario.hpp b/include/Enemy/Emario.hpp new file mode 100644 index 00000000..8b69ffee --- /dev/null +++ b/include/Enemy/Emario.hpp @@ -0,0 +1,51 @@ +#ifndef ENEMY_EMARIO_HPP +#define ENEMY_EMARIO_HPP + +#include +#include + +class TEnemyMario; + +class TEMario : public TSpineEnemy { +public: + TEMario(const char* name); + + virtual void load(JSUMemoryInputStream& stream); + virtual void loadAfter(); + virtual void init(TLiveManager* liveManager); + virtual BOOL receiveMessage(THitActor* sender, u32 message); + virtual void kill(); + + virtual void perform(u32, JDrama::TGraphics*); + + BOOL isGoal(); + BOOL isReachedToGate() const; + BOOL isDownWaitingToTalk() const; + void startRunAway(); + void startMonteReplay(u32 param1); + void startGateDrawing(); + void forceDisappear(); + + // fabricated and fake + static f32 vecDist(const JGeometry::TVec3& a, + const JGeometry::TVec3& b) + { + return JGeometry::TVec3(a - b).length(); + } + +private: + TEnemyMario* mEnemyMario; // 0x150 + u32 unk154; + u32 unk158; + u32 unk15C; + u32 unk160; +}; + +class TEMarioManager : public TEnemyManager { + TEMarioManager(const char* name); + + virtual void load(JSUMemoryInputStream&); + virtual TSpineEnemy* createEnemyInstance(); +}; + +#endif diff --git a/include/Enemy/EnemyMario.hpp b/include/Enemy/EnemyMario.hpp new file mode 100644 index 00000000..99015a9a --- /dev/null +++ b/include/Enemy/EnemyMario.hpp @@ -0,0 +1,38 @@ +#ifndef ENEMY_ENEMY_MARIO_HPP +#define ENEMY_ENEMY_MARIO_HPP + +#include +#include "Strategic/HitActor.hpp" + +class TEnemyMario : public TMario { +public: + // stub + void initEnemyValues(); + void startMonteReplay(u32); + void startDisappear(u16); + void startRunAway(); + void startGateDrawing(); + void hitWater(THitActor*); + u8 thinkTrample(); + void reachGoal(); + + // Frabricated + bool checkUnk4292() const + { + if (unk4292 == 0xb || unk4292 == 0xc || unk4292 == 0x11) { + return true; + } + return false; + } + +public: + u16 unk4290; // goal flag for + u16 unk4292; // some kind of state + char unk4294[10]; + TEMario* mEMario; // 0x42A0 + char unk42A4[12]; + f32 unk42B0; // distance for a collision check + char unk42B4[94]; +}; + +#endif diff --git a/src/Enemy/emario.cpp b/src/Enemy/emario.cpp index 8b137891..69b80ff5 100644 --- a/src/Enemy/emario.cpp +++ b/src/Enemy/emario.cpp @@ -1 +1,267 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// rogue includes needed for matching sinit & bss +#include +#include + +TEMario::TEMario(const char* name) + : TSpineEnemy(name) +{ +} + +void TEMario::load(JSUMemoryInputStream& stream) +{ + TSpineEnemy::load(stream); + + stream.read(&unk154, 4); + stream.read(&unk158, 4); + stream.read(&unk15C, 4); + stream.read(&unk160, 4); + + stream.readU32(); + stream.readU32(); + + if (unk154 == 0xff) { + unk154 = 0; + } + + if (unk158 == 0xFF) { + unk158 = 0; + } + + if (unk15C == 0xFF) { + unk15C = 0; + } + + if (unk160 == 0xFF) { + unk160 = 0; + } + + mEnemyMario = new TEnemyMario(); + mEnemyMario->mEMario = this; + + // "Mario 2 P" + if (strcmp(mName, "マリオ2P") == 0) { + mEnemyMario->setGamePad(gpMarDirector->unk18[1]); + mEnemyMario->unk388 = 3; + } + + // "Mario 3 P" + if (strcmp(mName, "マリオ3P") == 0) { + mEnemyMario->setGamePad(gpMarDirector->unk18[2]); + mEnemyMario->unk388 = 4; + } + + // "Mario 4 P + if (strcmp(mName, "マリオ4P") == 0) { + mEnemyMario->setGamePad(gpMarDirector->unk18[3]); + mEnemyMario->unk388 = 5; + } + + TNameRef* rootNameRef + = JDrama::TNameRefGen::getInstance()->getRootNameRef(); + + // "Mario Character" + const char marioCharName[] = "マリオ キャラ"; + mEnemyMario->unk3C + = JDrama::TNameRefGen::search(marioCharName); + + mEnemyMario->initValues(); + + mEnemyMario->mPosition = getPosition(); + mEnemyMario->mRotation = getRotation(); + mEnemyMario->mScaling = getScaling(); + + mEnemyMario->mFaceAngle.y = getRotation().y * 0.0027777778f * 65536.0f; + + mEnemyMario->initEnemyValues(); + + mEnemyMario->onFlag(MARIO_FLAG_NPC_TALKING); +} + +void TEMario::loadAfter() +{ + mEnemyMario->loadAfter(); + if (SMS_isMultiPlayerMap()) { + gpCamera->addMultiPlayer(&mPosition, 60.0f, 150.0f); + } +} +void TEMario::init(TLiveManager* manager) +{ + if (!manager) { + if (TObjChara* chara = (TObjChara*)unk3C) { + mMActorKeeper = new TMActorKeeper(nullptr, 1); + mMActorKeeper->mModelLoaderFlags = 0x11300000; + mMActor = mMActorKeeper->createMActorFromDefaultBmd( + chara->getFolder(), 0); + for (int i = 0; i < mMActor->unk4->mModelData->mMaterialNum; i++) { + SMS_InitPacket_Fog(mMActor->unk4, i); + } + mMActor->setBtk("kagemario_scroll"); + } + gpConductor->registerAloneActor(this); + } else { + mManager = manager; + mMActorKeeper = new TMActorKeeper(mManager, 1); + mManager->manageActor(this); + mMActor = mMActorKeeper->createMActorFromNthData(0, 0); + } + + if (mMActor != nullptr) { + gpScreenTexture->replace(mMActor->getModel()->getModelData(), + "H_kagemario_dummy"); + } + + onHitFlag(HIT_FLAG_NO_COLLISION); + offLiveFlag(LIVE_FLAG_UNK400); + + if (!mAnmSound) + initAnmSound(); + + initHitActor(0x8000002, 0x4, 0xe5000000, 70.0f, 45.0f, 60.0f, 40.0f); + + offHitFlag(HIT_FLAG_NO_COLLISION); + onLiveFlag(LIVE_FLAG_UNK10); +} + +BOOL TEMario::receiveMessage(THitActor* sender, u32 message) +{ + TSpineEnemy::receiveMessage(sender, message); + + if (message == HIT_MESSAGE_SPRAYED_BY_WATER) { + mEnemyMario->hitWater(sender); + return TRUE; + } else if (message == HIT_MESSAGE_TRAMPLE) { + return mEnemyMario->thinkTrample(); + } else if (sender->getActorType() == 0x40000246) { + mEnemyMario->reachGoal(); + } + return FALSE; +} + +void TEMario::kill() +{ + if (SMS_isMultiPlayerMap()) { + gpCamera->removeMultiPlayer(&mPosition); + } +} + +BOOL TEMario::isGoal() +{ + if (mEnemyMario->unk4290 & 1) { + return TRUE; + } + return FALSE; +} + +BOOL TEMario::isReachedToGate() const +{ + if (mEnemyMario->unk4292 == 0x18) { + return TRUE; + } + return FALSE; +} + +BOOL TEMario::isDownWaitingToTalk() const +{ + if (mEnemyMario->unk4292 == 0xf) { + return TRUE; + } + return FALSE; +} + +void TEMario::startRunAway() { mEnemyMario->startRunAway(); } + +void TEMario::startMonteReplay(u32 param1) +{ + mEnemyMario->startMonteReplay(param1); +} + +void TEMario::startGateDrawing() { mEnemyMario->startGateDrawing(); } + +void TEMario::forceDisappear() { mEnemyMario->startDisappear(9); } + +void TEMario::perform(u32 flags, JDrama::TGraphics* gfx) +{ + if (checkLiveFlag(LIVE_FLAG_UNK40)) { + return; + } + + if (!(flags & 0x1)) { + return; + } + + if (mEnemyMario->checkUnk4292() == 0) { + return; + } + + for (s32 i = 0; i < mColCount; ++i) { + switch (mCollisions[i]->mActorType) { + case 0x80000001: { + const f32 d = vecDist(mPosition, mCollisions[i]->getPosition()); + if (d < mEnemyMario->unk42B0) { + mCollisions[i]->receiveMessage(this, HIT_MESSAGE_ATTACK); + } + } break; + + case 0x400000bc: { + if (!mEnemyMario->checkStatusFlag(0x10000)) { + const f32 dmgRadius = mEnemyMario->getDamageRadius(); + const f32 atkRadius = mCollisions[i]->getAttackRadius(); + const f32 d = vecDist(mCollisions[i]->getPosition(), mPosition); + + if (d < (dmgRadius + atkRadius)) { + mEnemyMario->changePlayerStatus(0x810446, 0, false); + mEnemyMario->emitGetEffect(); + } + } + } break; + } + } + + mEnemyMario->perform(flags, gfx); + + if (flags & 0x1) { + mPosition = mEnemyMario->getPosition(); + mRotation = mEnemyMario->getRotation(); + mScaling = mEnemyMario->getScaling(); + + setAttackRadius(mEnemyMario->getAttackRadius()); + setAttackHeight(mEnemyMario->getAttackHeight()); + setDamageRadius(mEnemyMario->getDamageRadius()); + setDamageHeight(mEnemyMario->getDamageHeight()); + } +} + +TEMarioManager::TEMarioManager(const char* name) + : TEnemyManager(name) +{ +} + +void TEMarioManager::load(JSUMemoryInputStream& stream) +{ + unk38 = new TSpineEnemyParams("/enemy/emario.prm"); + TEnemyManager::load(stream); +} + +TSpineEnemy* TEMarioManager::createEnemyInstance() +{ + // "Pseudo Mario" + return new TEMario("マリオモドキ"); +}