From 19632e9b183402bb9a05030e12d0f1003765c31a Mon Sep 17 00:00:00 2001 From: Colin Noga Date: Tue, 6 Mar 2012 21:50:10 -0600 Subject: Improvements to ThwompaDomp, game.h, added Poodle, topman sprite --- NewerProject.yaml | 4 +- bossPodouble.yaml | 10 + bossThwompaDomp.yaml | 8 + include/game.h | 4 +- kamek_pal.x | 5 +- src/bossPodouble.cpp | 706 ++++++++++++++++++++++++++++++++++++++++++++++++ src/bossThwompaDomp.cpp | 223 ++++++++------- src/soundPlayer.S | 28 ++ src/topman.cpp | 480 ++++++++++++++++++++++++++++++++ topman.yaml | 10 + 10 files changed, 1369 insertions(+), 109 deletions(-) create mode 100644 bossPodouble.yaml create mode 100644 src/bossPodouble.cpp create mode 100644 src/topman.cpp create mode 100644 topman.yaml diff --git a/NewerProject.yaml b/NewerProject.yaml index 3a9ee3f..6726764 100644 --- a/NewerProject.yaml +++ b/NewerProject.yaml @@ -38,9 +38,11 @@ modules: - processed/bossRamboo.yaml - processed/bossBalboaWrench.yaml - processed/bossWrenchThrow.yaml + - processed/bossPodouble.yaml - processed/effectVideo.yaml - processed/fakeStarCoin.yaml - processed/shyguy.yaml - processed/meteor.yaml - - processed/pengi.yaml + - processed/topman.yaml + # - processed/pengi.yaml # - processed/actorlog.yaml diff --git a/bossPodouble.yaml b/bossPodouble.yaml new file mode 100644 index 0000000..4d34ffe --- /dev/null +++ b/bossPodouble.yaml @@ -0,0 +1,10 @@ +--- +# Replaces Ship_Window + +source_files: [../src/bossPodouble.cpp] +hooks: + - name: PodoubleBuild + type: add_func_pointer + src_addr_pal: 0x8097B0D0 + target_func: 'daPodouble::build(void)' + diff --git a/bossThwompaDomp.yaml b/bossThwompaDomp.yaml index 1994794..b087a17 100644 --- a/bossThwompaDomp.yaml +++ b/bossThwompaDomp.yaml @@ -8,3 +8,11 @@ hooks: src_addr_pal: 0x80aebda0 target_func: 'daEnMegaDosun_c::build(void)' + + - name: UpdateShyGuySpriteInfo + type: patch + addr_pal: 0x8030D5B4 #0x8030D590 + # [204] ( 16, 48) ( 0, -24 16: 24) 64? 64? 0? 0? | [8:Environment?] + # 00CC 0000 00000010 00000030 00000000 FFFFFFE8 00000010 00000018 0040 0040 0000 0000 0008 0000 + data: '0002 0000' + # 0x8030A340 + sprite num * 0x28 == offset diff --git a/include/game.h b/include/game.h index f458dfd..7c10d05 100755 --- a/include/game.h +++ b/include/game.h @@ -1805,14 +1805,14 @@ public: virtual void _vfD0(Vec2 *p, float f); // mostly same as vfC8, but uses PLAYER_SE_OBJ/GROUP_BOOT/SE_OBJ_CMN_SPLASH_POISON // I'll add methods as I need them - int outOfZone(Vec3 pos, float* rect, u8 zone); + bool outOfZone(Vec3 pos, float* rect, u8 zone); bool checkZoneBoundaries(u32 flags); // I think this method is for that, anyway void Delete(u8 param1); // fBase_c::Delete(void); ~dStageActor_c(); - static void create(Actors type, u32 settings, Vec *pos, S16Vec *rot, u8 layer); + static dStageActor_c *create(Actors type, u32 settings, Vec *pos, S16Vec *rot, u8 layer); static dStageActor_c *createChild(Actors type, dStageActor_c *parent, u32 settings, Vec *pos, S16Vec *rot, u8 layer); // these are valid while in onCreate diff --git a/kamek_pal.x b/kamek_pal.x index 0e02ed7..c5c5790 100644 --- a/kamek_pal.x +++ b/kamek_pal.x @@ -52,6 +52,7 @@ SECTIONS { getRectByID__9dCourse_cFUcP5mRect = 0x8008E890; modifyPlayerPropertiesWithRollingObject = 0x80057820; + EN_LandbarrelPlayerCollision = 0x80A582A0; /* Boss Related */ @@ -81,6 +82,8 @@ SECTIONS { StateID_DemoControl__7dPlayer = 0x80354E1C; PlayWrenchSound = 0x808A94C0; + WaterManager = 0x8042A3E0; + CheckforLiquid = 0x800EBA40; /* Mr Sun Related */ @@ -1441,7 +1444,7 @@ SECTIONS { SpawnThwompEffects = 0x809f6660; - + .text : { FILL (0) diff --git a/src/bossPodouble.cpp b/src/bossPodouble.cpp new file mode 100644 index 0000000..663781e --- /dev/null +++ b/src/bossPodouble.cpp @@ -0,0 +1,706 @@ +#include +#include +#include +#include +#include +#include "effects.h" +#include "player.h" + +void poodleCollisionCallback(ActivePhysics *apThis, ActivePhysics *apOther); + +void poodleCollisionCallback(ActivePhysics *apThis, ActivePhysics *apOther) { + if (apOther->owner->name == BROS_FIREBALL) { return; } + else if (apOther->owner->name == BROS_ICEBALL) { return; } + else { dEn_c::collisionCallback(apThis, apOther); } + } + +class daPodouble : public dEn_c { + int onCreate(); + int onDelete(); + int onExecute(); + int onDraw(); + + mHeapAllocator_c allocator; + nw4r::g3d::ResFile resFile; + + m3d::mdl_c bodyModel; + m3d::mdl_c fogModel; + m3d::mdl_c fog2Model; + + m3d::anmTexSrt_c body; + + m3d::anmChr_c fogChr; + m3d::anmTexSrt_c fogSRT; + + m3d::anmChr_c fog2Chr; + m3d::anmTexSrt_c fog2SRT; + + + char isFire; + char goingUp; + int timer; + float dying; + int damage; + float Baseline; + char isInvulnerable; + int countdown; + + dEn_c *Kameck; + + static daPodouble *build(); + + // void spriteCollision(ActivePhysics *apThis, ActivePhysics *apOther); + void playerCollision(ActivePhysics *apThis, ActivePhysics *apOther); + void yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther); + + void collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCatD_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat7_WMWaggleWater(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat7_WMWaggleWaterYoshi(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther); + bool collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther); + + + USING_STATES(daPodouble); + DECLARE_STATE(Bounce); + DECLARE_STATE(Spit); + DECLARE_STATE(Damage); + + DECLARE_STATE(Grow); + DECLARE_STATE(Outro); + DECLARE_STATE(SyncDie); + +}; + +daPodouble *daPodouble::build() { + void *buffer = AllocFromGameHeap1(sizeof(daPodouble)); + return new(buffer) daPodouble; +} + +/////////////////////// +// Externs and States +/////////////////////// + extern "C" void *PlaySound(dStageActor_c *, int soundID); + extern "C" void *PlaySoundAsync(dStageActor_c *, int soundID); + + extern "C" u32 GenerateRandomNumber(int max); + extern "C" dStageActor_c *GetSpecificPlayerActor(int num); + extern "C" int SmoothRotation(short* rot, u16 amt, int unk2); + extern "C" void* WaterManager; + extern "C" u32 CheckforLiquid(void*, Vec, int, int, int, int layer); + + extern "C" void *StopBGMMusic(); + extern "C" void *StartBGMMusic(); + + extern "C" void *MakeMarioEnterDemoMode(); + extern "C" void *MakeMarioExitDemoMode(); + extern "C" void *UpdateGameMgr(); + + + CREATE_STATE(daPodouble, Bounce); + CREATE_STATE(daPodouble, Spit); + CREATE_STATE(daPodouble, Damage); + + CREATE_STATE(daPodouble, Grow); + CREATE_STATE(daPodouble, Outro); + CREATE_STATE(daPodouble, SyncDie); + + +//////////////////////// +// Collision Functions +//////////////////////// + + void daPodouble::playerCollision(ActivePhysics *apThis, ActivePhysics *apOther) { + this->dEn_c::playerCollision(apThis, apOther); + this->_vf220(apOther->owner); + + // fix multiple player collisions via megazig + this->isDead = 0; + this->flags_4FC |= (1<<(31-7)); + if(apOther->owner->which_player < 3) { + this->counter_504[apOther->owner->which_player] = 0; + } + } + + void daPodouble::yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther) { this->playerCollision(apThis, apOther); } + void daPodouble::collisionCat7_WMWaggleWater(ActivePhysics *apThis, ActivePhysics *apOther) { this->playerCollision(apThis, apOther); } + void daPodouble::collisionCat7_WMWaggleWaterYoshi(ActivePhysics *apThis, ActivePhysics *apOther) { this->playerCollision(apThis, apOther); } + void daPodouble::collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther) { this->playerCollision(apThis, apOther); } + + void daPodouble::collisionCatD_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther) { return; } + void daPodouble::collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther) { return; } + void daPodouble::collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther) { return; } + + void daPodouble::collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther) { + apOther->owner->kill(); + if (this->isInvulnerable) { return; } + + this->damage += 2; + + if (this->damage < 12) { doStateChange(&StateID_Damage); } + else { doStateChange(&StateID_Outro); } + } + + void daPodouble::collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther){ + apOther->owner->Delete(1); + if (this->isInvulnerable) { return; } + + if (this->isFire == 0) { + this->damage += 3; + + if (this->damage < 12) { doStateChange(&StateID_Damage); } + else { doStateChange(&StateID_Outro); } + } + } + + void daPodouble::collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther) { + if (this->isInvulnerable) { return; } + + if (this->isFire == 0) { + this->damage += 2; + + if (this->damage < 12) { doStateChange(&StateID_Damage); } + else { doStateChange(&StateID_Outro); } + } + } + + bool daPodouble::collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther) { + apOther->owner->Delete(1); + if (this->isInvulnerable) { return true; } + + if (this->isFire == 1) { + if (apOther->owner->name == 104) { this->damage += 2; } + else { this->damage += 3; } + + if (this->damage < 12) { doStateChange(&StateID_Damage); } + else { doStateChange(&StateID_Outro); } + + return true; + } + else { return false; } + } + + +int daPodouble::onCreate() { + + this->isFire = this->settings >> 28; + this->Baseline = this->pos.y - (float)((this->settings & 0xFF) * 0.8); + + + OSReport("Creating the Podouble Model\n"); + allocator.link(-1, GameHeaps[0], 0, 0x20); + + // Fire or Ice + if (this->isFire == 1) { + this->resFile.data = getResource("bubble", "g3d/t00.brres"); + } + else { + this->resFile.data = getResource("bubble", "g3d/t05.brres"); + } + + // Body and anms + nw4r::g3d::ResMdl mdl = this->resFile.GetResMdl("bubble"); + bodyModel.setup(mdl, &allocator, 0x224, 1, 0); + + nw4r::g3d::ResAnmTexSrt anmRes = this->resFile.GetResAnmTexSrt("bubble"); + this->body.setup(mdl, anmRes, &this->allocator, 0, 1); + this->body.bindEntry(&this->bodyModel, anmRes, 0, 0); + this->bodyModel.bindAnim(&this->body, 0.0); + + + // Fog up and anms + mdl = this->resFile.GetResMdl("bubble_fog"); + fogModel.setup(mdl, &allocator, 0x124, 1, 0); + + nw4r::g3d::ResAnmChr anmChr = this->resFile.GetResAnmChr("bubble_fog"); + this->fogChr.setup(mdl, anmChr, &this->allocator, 0); + this->fogChr.bind(&this->fogModel, anmChr, 1); + this->fogModel.bindAnim(&this->fogChr, 0.0); + this->fogChr.setUpdateRate(1.0); + + anmRes = this->resFile.GetResAnmTexSrt("bubble_fog"); + this->fogSRT.setup(mdl, anmRes, &this->allocator, 0, 1); + this->fogSRT.bindEntry(&this->fogModel, anmRes, 0, 0); + this->fogModel.bindAnim(&this->fogSRT, 0.0); + + + // Fog down and anms + mdl = this->resFile.GetResMdl("bubble_fog2"); + fog2Model.setup(mdl, &allocator, 0x124, 1, 0); + + anmChr = this->resFile.GetResAnmChr("bubble_fog2"); + this->fog2Chr.setup(mdl, anmChr, &this->allocator, 0); + this->fog2Chr.bind(&this->fog2Model, anmChr, 1); + this->fogModel.bindAnim(&this->fog2Chr, 0.0); + this->fog2Chr.setUpdateRate(1.0); + + anmRes = this->resFile.GetResAnmTexSrt("bubble_fog"); + this->fog2SRT.setup(mdl, anmRes, &this->allocator, 0, 1); + this->fog2SRT.bindEntry(&this->fog2Model, anmRes, 0, 0); + this->fog2Model.bindAnim(&this->fog2SRT, 0.0); + + + + allocator.unlink(); + + + // Stuff I do understand + OSReport("Setting Podouble's Size to 1.0\n"); + this->scale = (Vec){1.0, 1.0, 1.0}; + + + this->direction = (this->isFire) ? 0 : 1; + this->countdown = (this->isFire) ? 90 : 0; + + this->rot.x = 0; // X is vertical axis + this->rot.y = (direction) ? 0xD800 : 0x2800; + this->rot.z = 0; // Z is ... an axis >.> + + this->speed.x = 0.0; + this->speed.y = 0.0; + this->max_speed.x = 0.0; + this->x_speed_inc = 0.0; + + this->goingUp = 0; + + + OSReport("Creating Podouble's Physics Struct\n"); + + ActivePhysics::Info HitMeBaby; + + HitMeBaby.xDistToCenter = 0.0; + HitMeBaby.yDistToCenter = 0.0; + + HitMeBaby.xDistToEdge = 40.0; + HitMeBaby.yDistToEdge = 40.0; + + HitMeBaby.category1 = 0x3; + HitMeBaby.category2 = 0x0; + HitMeBaby.bitfield1 = 0x4F; + HitMeBaby.bitfield2 = (this->isFire) ? 0x388626 : 0x388626; + HitMeBaby.unkShort1C = 0; + HitMeBaby.callback = &poodleCollisionCallback; + + OSReport("Making the Physics Class and adding to the list\n"); + this->aPhysics.initWithStruct(this, &HitMeBaby); + this->aPhysics.addToList(); + + this->disableEatIn(); + + doStateChange(&StateID_Grow); + + OSReport("Going to Execute Podouble\n"); + this->onExecute(); + return true; +} + +int daPodouble::onDelete() { + return true; +} + +int daPodouble::onExecute() { + acState.execute(); + + return true; +} + +int daPodouble::onDraw() { + if (this->speed.y >= 0) { + matrix.translation(pos.x, pos.y, pos.z); + + fogModel.setDrawMatrix(matrix); + fogModel.setScale(&scale); + fogModel.calcWorld(false); + + fogModel.scheduleForDrawing(); + fogModel._vf1C(); + + if(this->fogChr.isAnimationDone()) + this->fogChr.setCurrentFrame(0.0); + + this->fogSRT.process(); + } + else { + matrix.translation(pos.x, pos.y, pos.z); + + fog2Model.setDrawMatrix(matrix); + fog2Model.setScale(&scale); + fog2Model.calcWorld(false); + + fog2Model.scheduleForDrawing(); + fog2Model._vf1C(); + + if(this->fog2Chr.isAnimationDone()) + this->fog2Chr.setCurrentFrame(0.0); + + this->fog2SRT.process(); + } + + matrix.translation(pos.x, pos.y, pos.z); + matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z); + + bodyModel.setDrawMatrix(matrix); + bodyModel.setScale(&scale); + bodyModel.calcWorld(false); + + bodyModel.scheduleForDrawing(); + this->body.process(); + + return true; +} + + +/////////////// +// Grow State +/////////////// + void daPodouble::beginState_Grow() { + this->timer = 0; + if (isFire) { return; } + + // Stop the BGM Music + StopBGMMusic(); + + // Set the necessary Flags and make Mario enter Demo Mode + dStage32C_c::instance->freezeMarioBossFlag = 1; + WLClass::instance->_4 = 4; + WLClass::instance->_8 = 0; + + MakeMarioEnterDemoMode(); + + // Make sure to use the correct position + Vec pos = (Vec){this->pos.x - 124.0, this->pos.y + 104.0, 3564.0}; + S16Vec rot = (S16Vec){0, 0, 0}; + + // Create And use Kameck + Kameck = (daKameckDemo*)createChild(KAMECK_FOR_CASTLE_DEMO, (dStageActor_c*)this, 0, &pos, &rot, 0); + Kameck->doStateChange(&daKameckDemo::StateID_DemoWait); + + this->scale = (Vec){1.0, 1.0, 1.0}; + } + + void daPodouble::executeState_Grow() { + + this->timer = this->timer + 1; + + float scaleSpeed, yPosScaling; + + + if ((this->timer > 150) && (this->timer < 230)) { + + scaleSpeed = 0.03125; + yPosScaling = 18; + + float modifier; + + modifier = 1.0 + ((this->timer - 150) * scaleSpeed); + + this->scale = (Vec){modifier, modifier, modifier}; + this->pos.y = this->pos.y + (yPosScaling/80); + + } + if (this->timer > 420) { + PlaySound(this, SE_EMY_CS_MOVE_W8_BUBBLE_APP); + doStateChange(&StateID_Bounce); + } + + if (isFire) { return; } + if (this->timer == 130) { Kameck->doStateChange(&daKameckDemo::StateID_DemoSt); } + if (this->timer == 150) { PlaySound(this, SE_BOSS_IGGY_WANWAN_TO_L); } + if (this->timer == 400) { Kameck->doStateChange(&daKameckDemo::StateID_DemoSt2); } + if (this->timer == 360) { + Vec tempPos = (Vec){this->pos.x - 40.0, this->pos.y + 120.0, 3564.0}; + CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 175); // 400 & 401 // 564 // 583 // 754 // 958 + CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 400); // 400 & 401 // 564 // 583 // 754 // 958 + CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 401); // 400 & 401 // 564 // 583 // 754 // 958 + CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 564); // 400 & 401 // 564 // 583 // 754 // 958 + CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 583); // 400 & 401 // 564 // 583 // 754 // 958 + CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 754); // 400 & 401 // 564 // 583 // 754 // 958 + CreateEffect(&tempPos, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}, 958); // 400 & 401 // 564 // 583 // 754 // 958 + } + } + void daPodouble::endState_Grow() { + this->Baseline = this->pos.y; + if (isFire) { return; } + + // Clean up the flags and Kameck + dStage32C_c::instance->freezeMarioBossFlag = 0; + WLClass::instance->_8 = 1; + + MakeMarioExitDemoMode(); + StartBGMMusic(); + + Kameck->Delete(1); + } + + +/////////////// +// Bounce State +/////////////// + void daPodouble::beginState_Bounce() { + this->rot.y = (direction) ? 0xD800 : 0x2800; + this->rot.x = 0; + + this->max_speed.y = -5.0; + this->speed.y = -1.0; + this->y_speed_inc = -0.1875; + + this->goingUp = 0; + } + void daPodouble::executeState_Bounce() { + + if (this->countdown) { + this->countdown--; + return; } + + HandleYSpeed(); + doSpriteMovement(); + + if (this->pos.y < this->Baseline) { + this->speed.y = 8.0; + this->goingUp = 1; } + + if (-0.1 < this->speed.y < 0.1) { + if (this->goingUp == 1) { doStateChange(&StateID_Spit); } } + + + // Check for stupid liquid junk + float ydest; + ydest = (this->pos.y > this->last_pos.y) ? this->last_pos.y : this->pos.y; + + int liquid = CheckforLiquid(WaterManager, this->pos, 0, 0, 0, this->currentLayerID); + + OSReport("Liquid type %d", liquid); + + if (liquid == 1) { + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){3.0, 3.0, 3.0}, 415); + PlaySoundAsync(this, SE_EMY_BUBBLE_SPLASH); + } + if (liquid == 0) { + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){3.0, 3.0, 3.0}, 422); + PlaySoundAsync(this, SE_OBJ_CMN_SPLASH); + } + + } + void daPodouble::endState_Bounce() { + this->speed.y = 0.0; + this->y_speed_inc = 0.0; + } + + +/////////////// +// Spit State +/////////////// + void daPodouble::beginState_Spit() { this->timer = 0; } + void daPodouble::executeState_Spit() { + + if (this->timer < 0x40) { + this->rot.x -= 0x80; + } + + else if (this->timer < 0x48) { + this->rot.x += 0x400; + } + + else if (this->timer == 0x48) { + if (this->isFire == 0) { + dStageActor_c *spawner = create(BROS_ICEBALL, 0x10, &this->pos, &(S16Vec){0,0,0}, 0); + *((u32 *) (((char *) spawner) + 0x3DC)) = this->id; + PlaySoundAsync(this, SE_EMY_ICE_BROS_ICE); + doStateChange(&StateID_Bounce); + } + else { + create(BROS_FIREBALL, 0, &this->pos, &(S16Vec){0,0,0}, 0); + PlaySoundAsync(this, SE_EMY_FIRE_BROS_FIRE); + doStateChange(&StateID_Bounce); + } + } + + this->timer += 1; + } + void daPodouble::endState_Spit() { + this->speed.y = -1.0; + this->y_speed_inc = -0.1875; + } + + +/////////////// +// Damage State +/////////////// + void daPodouble::beginState_Damage() { + this->timer = 0; + this->isInvulnerable = 1; + + if (this->isFire == 0) { + PlaySoundAsync(this, SE_OBJ_PNGN_ICE_THAW); + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 243); } + else { + PlaySoundAsync(this, SE_EMY_FIRE_SNAKE_EXTINCT); + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){3.0, 3.0, 3.0}, 252); } + } + void daPodouble::executeState_Damage() { + + int amt; + amt = sin(this->timer * 3.14 / 4.0) * 0x2000; + + this->rot.y = amt; + this->rot.y += (direction) ? 0xD800 : 0x2800; + + + if (this->timer > 180) { + doStateChange(&StateID_Bounce); + } + + if ((this->timer == 60) || (this->timer == 80) || (this->timer == 100)) { + if (this->isFire == 0) { + dStageActor_c *spawner = create(BROS_ICEBALL, 0x10, &this->pos, &(S16Vec){0,0,0}, 0); + *((u32 *) (((char *) spawner) + 0x3DC)) = this->id; + PlaySoundAsync(this, SE_EMY_ICE_BROS_ICE); + } + else { + create(BROS_FIREBALL, 0, &this->pos, &(S16Vec){0,0,0}, 0); + PlaySoundAsync(this, SE_EMY_FIRE_BROS_FIRE); + } + } + + this->timer += 1; + + } + void daPodouble::endState_Damage() { + this->isInvulnerable = 0; + } + + +/////////////// +// Outro State +/////////////// + void daPodouble::beginState_Outro() { + + daPodouble *other = (daPodouble*)FindActorByType(SHIP_WINDOW, (Actor*)this); + if (other != 0) { other->doStateChange(&StateID_SyncDie); } + + WLClass::instance->_4 = 5; + WLClass::instance->_8 = 0; + + this->removeMyActivePhysics(); + this->timer = 0; + StopBGMMusic(); + + dStage32C_c::instance->freezeMarioBossFlag = 1; + + } + void daPodouble::executeState_Outro() { + + if (this->dying == 1) { + if (this->timer > 180) { + ExitStage(WORLD_MAP, 0, BEAT_LEVEL, MARIO_WIPE); + } + + if (this->timer == 60) { + + UpdateGameMgr(); + + if (GetSpecificPlayerActor(0) != 0) { + PlaySound(this, SE_VOC_MA_CLEAR_BOSS); + // Send PlBase into DemoGoal State here, kthxbai + } + + if (GetSpecificPlayerActor(1) != 0) { + PlaySound(this, SE_VOC_LU_CLEAR_BOSS); + // Send PlBase into DemoGoal State here, kthxbai + } + + if (GetSpecificPlayerActor(2) != 0) { + PlaySound(this, SE_VOC_KO_CLEAR_BOSS); + // Send PlBase into DemoGoal State here, kthxbai + } + + if (GetSpecificPlayerActor(3) != 0) { + PlaySound(this, SE_VOC_KO2_CLEAR_BOSS); + // Send PlBase into DemoGoal State here, kthxbai + } + } + + this->timer += 1; + return; + } + + if (this->scale.x > 0.1) { + + PlaySound(this, SE_EMY_BUBBLE_EXTINCT); + + // Adjust this to equal the scale of your boss / 80. + this->scale.x -= 0.04375; + this->scale.y -= 0.04375; + this->scale.z -= 0.04375; + + if (this->timer == 30) { + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 756); + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 801); + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 957); + this->timer = 0; + } + + this->timer += 1; + } + else { + this->scale.x = 0.0; + this->scale.y = 0.0; + this->scale.z = 0.0; + + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 588); + this->dying = 1; + this->timer = 0; + + PlaySound(this, STRM_BGM_SHIRO_BOSS_CLEAR); + MakeMarioEnterDemoMode(); + } + } + void daPodouble::endState_Outro() { } + + + +/////////////// +// SyncDie State +/////////////// + void daPodouble::beginState_SyncDie() { + + this->removeMyActivePhysics(); + this->timer = 0; + } + void daPodouble::executeState_SyncDie() { + + if (this->dying == 1) { return; } + + if (this->scale.x > 0.1) { + + PlaySound(this, SE_EMY_BUBBLE_EXTINCT); + + // Adjust this to equal the scale of your boss / 80. + this->scale.x -= 0.04375; + this->scale.y -= 0.04375; + this->scale.z -= 0.04375; + + if (this->timer == 30) { + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 756); + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 801); + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 957); + this->timer = 0; + } + + this->timer += 1; + } + else { + this->scale.x = 0.0; + this->scale.y = 0.0; + this->scale.z = 0.0; + + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 588); + this->dying = 1; + this->timer = 0; + } + } + void daPodouble::endState_SyncDie() { } diff --git a/src/bossThwompaDomp.cpp b/src/bossThwompaDomp.cpp index 3a1b0c7..fb8d59e 100644 --- a/src/bossThwompaDomp.cpp +++ b/src/bossThwompaDomp.cpp @@ -5,26 +5,26 @@ #include #include "effects.h" +// Externs + extern "C" int posIsInZone(Vec,float*,float*,u8 zone); + extern "C" void* ScreenPositionClass; + extern "C" void ShakeScreen(void*,int,int,int,int); // (ScreenPositionClass, some other ints - set the second one to 1 to shake it) + extern "C" int SpawnThwompEffects(dEn_c *); -extern "C" int posIsInZone(Vec,float*,float*,u8 zone); -extern "C" void* ScreenPositionClass; -extern "C" void ShakeScreen(void*,int,int,int,int); // (ScreenPositionClass, some other ints - set the second one to 1 to shake it) -extern "C" int SpawnThwompEffects(dEn_c *); + extern "C" void* SoundRelatedClass; + extern "C" Vec ConvertStagePositionIntoScreenPosition__Maybe(Vec); + extern "C" void AnotherSoundRelatedFunction(void*,SFX,Vec,int); -extern "C" void* SoundRelatedClass; -extern "C" Vec ConvertStagePositionIntoScreenPosition__Maybe(Vec); -extern "C" void AnotherSoundRelatedFunction(void*,SFX,Vec,int); + extern "C" void *PlaySound(dEn_c *, int soundID); + extern "C" void *PlaySoundAsync(dEn_c *, int soundID); + extern "C" dStageActor_c *GetSpecificPlayerActor(int number); -extern "C" void *PlaySound(dEn_c *, int soundID); -extern "C" void *PlaySoundAsync(dEn_c *, int soundID); -extern "C" dStageActor_c *GetSpecificPlayerActor(int number); + extern "C" void *StopBGMMusic(); + extern "C" void *StartBGMMusic(); -extern "C" void *StopBGMMusic(); -extern "C" void *StartBGMMusic(); - -extern "C" void *MakeMarioEnterDemoMode(); -extern "C" void *MakeMarioExitDemoMode(); -extern "C" void *UpdateGameMgr(); + extern "C" void *MakeMarioEnterDemoMode(); + extern "C" void *MakeMarioExitDemoMode(); + extern "C" void *UpdateGameMgr(); class daEnMegaDosun_c : public dEn_c { @@ -53,6 +53,8 @@ class daEnMegaDosun_c : public dEn_c { float leftBuffer; float rightBuffer; float topBuffer; + bool isOutofScreen; + Vec OutOfScreenPosition; dEn_c *Kameck; @@ -77,14 +79,15 @@ class daEnMegaDosun_c : public dEn_c { DECLARE_STATE(Outro); }; -CREATE_STATE(daEnMegaDosun_c, UpWait); -CREATE_STATE(daEnMegaDosun_c, DownMoveWait); -CREATE_STATE(daEnMegaDosun_c, PuruMove); -CREATE_STATE(daEnMegaDosun_c, DownMove); -CREATE_STATE(daEnMegaDosun_c, DownWait); -CREATE_STATE(daEnMegaDosun_c, UpMove); -CREATE_STATE(daEnMegaDosun_c, Grow); -CREATE_STATE(daEnMegaDosun_c, Outro); +// States + CREATE_STATE(daEnMegaDosun_c, UpWait); + CREATE_STATE(daEnMegaDosun_c, DownMoveWait); + CREATE_STATE(daEnMegaDosun_c, PuruMove); + CREATE_STATE(daEnMegaDosun_c, DownMove); + CREATE_STATE(daEnMegaDosun_c, DownWait); + CREATE_STATE(daEnMegaDosun_c, UpMove); + CREATE_STATE(daEnMegaDosun_c, Grow); + CREATE_STATE(daEnMegaDosun_c, Outro); daEnMegaDosun_c *daEnMegaDosun_c::build() { void *buffer = AllocFromGameHeap1(sizeof(daEnMegaDosun_c)); @@ -102,18 +105,17 @@ daEnMegaDosun_c *daEnMegaDosun_c::build() { void daEnMegaDosun_c::collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther) { } - void daEnMegaDosun_c::setupBodyModel() { allocator.link(-1, GameHeaps[0], 0, 0x20); - this->resFile.data = getResource("dossun", "g3d/dossun.brres"); + this->resFile.data = getResource("dossun", "g3d/t00.brres"); nw4r::g3d::ResMdl mdl = this->resFile.GetResMdl("dossun_big"); bodyModel.setup(mdl, &allocator, 0x60, 1, 0); SetupTextures_Enemy(&bodyModel, 0); - // nw4r::g3d::ResAnmVis anmRes = this->resFile.GetResAnmVis("dossun_big"); - // this->anmVis.setup(mdl, anmRes, &this->allocator, 0); - // this->anmVis.bind(&bodyModel, anmRes, 1); + nw4r::g3d::ResAnmVis anmRes = this->resFile.GetResAnmVis("dossun_big"); + this->anmVis.setup(mdl, anmRes, &this->allocator, 0); + this->anmVis.bind(&bodyModel, anmRes, 1); allocator.unlink(); } @@ -153,9 +155,9 @@ int daEnMegaDosun_c::onCreate() { OSReport("this->collMgr.Init(this,(u8*)&this->collision_struct,(u8*)&s3,0);\n"); this->collMgr.Init(this,(u8*)&this->collision_struct,(u8*)&s3,0); - // this->pos_delta2.x = 0.0; - // this->pos_delta2.y = 36.0; - // this->pos_delta2.z = 0.0; + this->pos_delta2.x = 0.0; + this->pos_delta2.y = 36.0; + this->pos_delta2.z = 0.0; this->_320 = 0.0; this->_324 = 48.0; @@ -175,11 +177,20 @@ int daEnMegaDosun_c::onCreate() { this->notFalling = 0; this->direction = 0; this->countdownTimer = 0; + this->isOutofScreen = false; // Measured in half tiles - this->leftBuffer = this->pos.x - ((float)((this->settings >> 24) & 0xFF) * 8.0); //nyb 5-6 LEFT - this->rightBuffer = this->pos.x + ((float)((this->settings >> 16) & 0xFF) * 8.0); //nyb 7-8 RIGHT - this->topBuffer = this->pos.y + ((float)((this->settings >> 8) & 0xFF) * 8.0); //nyb 9-10 TOP + this->leftBuffer = this->pos.x - (((float)((this->settings >> 24) & 0xFF) - 5.0) * 8.0); //nyb 5-6 LEFT + this->rightBuffer = this->pos.x + (((float)((this->settings >> 16) & 0xFF) - 3.0) * 8.0); //nyb 7-8 RIGHT + this->topBuffer = this->pos.y + (((float)((this->settings >> 8) & 0xFF) - 8.0) * 8.0); //nyb 9-10 TOP + + + // Boss Thwomp settings + // + // nybble 5-6 - Left Buffer in half tiles (minimum is 5 due to thwomp width) + // nybble 7-8 - Left Buffer in half tiles (minimum is 3 due to thwomp width) + // nybble 9-10 - Top Buffer in half tiles (minimum is 8 due to thwomp height) + // this->doStateChange(&StateID_Grow); @@ -188,14 +199,19 @@ int daEnMegaDosun_c::onCreate() { return true; } - int daEnMegaDosun_c::onExecute() { acState.execute(); - int ret = this->checkZoneBoundaries(0); - if(ret) { - OSReport("daEnMegaDosun_c has left the building\n"); - doStateChange(&StateID_Outro); + if (this->isOutofScreen == false) { + float rect[] = {this->_320, this->_324, this->spriteSomeRectX, this->spriteSomeRectY}; + int ret = this->outOfZone(this->pos, (float*)&rect, this->currentZoneID); + if(ret) { + OSReport("daEnMegaDosun_c has left the building\n"); + this->OutOfScreenPosition = this->pos; + + this->isOutofScreen = true; + doStateChange(&StateID_Outro); + } } return true; @@ -214,6 +230,7 @@ int daEnMegaDosun_c::onDraw() { } int daEnMegaDosun_c::onDelete() { + OSReport("Deleting Thwompy\n"); return true; } @@ -307,14 +324,20 @@ int daEnMegaDosun_c::onDelete() { } if (this->pos.x > this->rightBuffer) { + CreateEffect(&(Vec){this->pos.x + 38.0, this->pos.y + 32.0, 5500.0}, &(S16Vec){0,0,0x4000}, &(Vec){1.0, 1.0, 1.0}, 364); + PlaySoundAsync(this, SE_OBJ_TEKKYU_G_CRASH); + this->direction = 0; } if (this->pos.x < this->leftBuffer) { + CreateEffect(&(Vec){this->pos.x - 40.0, this->pos.y + 32.0, 5500.0}, &(S16Vec){0,0,0xC000}, &(Vec){1.0, 1.0, 1.0}, 364); + PlaySoundAsync(this, SE_OBJ_TEKKYU_G_CRASH); + this->direction = 1; } - this->pos.x += (direction) ? -0.5 : 0.5; + this->pos.x += (direction) ? 0.9 : -0.9; if (this->notFalling == 0) { if(this->CheckIfPlayerBelow(40.0, 256.0)) { @@ -336,13 +359,13 @@ int daEnMegaDosun_c::onDelete() { // StateID_DownMoveWait void daEnMegaDosun_c::beginState_DownMoveWait() { - // this->anmVis.playState = 1; + this->anmVis.playState = 1; this->bodyModel.bindAnim(&this->anmVis, 0.5); } void daEnMegaDosun_c::executeState_DownMoveWait() { - // if(this->anmVis.isAnimationDone()) - // this->doStateChange(&StateID_PuruMove); - // this->anmVis.process(); + if(this->anmVis.isAnimationDone()) + this->doStateChange(&StateID_PuruMove); + this->anmVis.process(); } void daEnMegaDosun_c::endState_DownMoveWait() { return; @@ -421,13 +444,14 @@ int daEnMegaDosun_c::onDelete() { if(this->countdownTimer == 0) { this->doStateChange(&StateID_UpMove); } - else{ + else { this->countdownTimer--; - // if(this->countdownTimer & 0xff == 0x20) - // this->anmVis.playState = 3; + if(this->countdownTimer == 0x20) { + this->anmVis.playState = 3; + } } - // this->anmVis.process(); + this->anmVis.process(); } void daEnMegaDosun_c::endState_DownWait() { return; @@ -443,10 +467,11 @@ int daEnMegaDosun_c::onDelete() { if (this->pos.y > this->topBuffer) { this->doStateChange(&StateID_UpWait); + PlaySoundAsync(this, SE_OBJ_TEKKYU_L_CRASH); this->countdownTimer = 0xc; } else { - this->pos.y += 0.5; + this->pos.y += 1.5; } } void daEnMegaDosun_c::endState_UpMove() { @@ -455,6 +480,7 @@ int daEnMegaDosun_c::onDelete() { // Outro void daEnMegaDosun_c::beginState_Outro() { + OSReport("Outro Being\n"); WLClass::instance->_4 = 5; WLClass::instance->_8 = 0; @@ -465,72 +491,59 @@ int daEnMegaDosun_c::onDelete() { dStage32C_c::instance->freezeMarioBossFlag = 1; + this->speed.y = 0.0; + this->y_speed_inc = 0.0; } void daEnMegaDosun_c::executeState_Outro() { - if (this->dying == 1) { - if (this->timer > 180) { - ExitStage(WORLD_MAP, 0, BEAT_LEVEL, MARIO_WIPE); - } - - if (this->timer == 60) { - - UpdateGameMgr(); - - if (GetSpecificPlayerActor(0) != 0) { - PlaySound(this, SE_VOC_MA_CLEAR_BOSS); - // Send PlBase into DemoGoal State here, kthxbai - } - - if (GetSpecificPlayerActor(1) != 0) { - PlaySound(this, SE_VOC_LU_CLEAR_BOSS); - // Send PlBase into DemoGoal State here, kthxbai - } - - if (GetSpecificPlayerActor(2) != 0) { - PlaySound(this, SE_VOC_KO_CLEAR_BOSS); - // Send PlBase into DemoGoal State here, kthxbai - } - - if (GetSpecificPlayerActor(3) != 0) { - PlaySound(this, SE_VOC_KO2_CLEAR_BOSS); - // Send PlBase into DemoGoal State here, kthxbai - } - } - - this->timer += 1; - return; - } + this->pos.y = this->OutOfScreenPosition.y + 280.0; - if (this->scale.x > 0.1) { + if (this->timer == 0) { + OSReport("Outro Play Sound\n"); PlaySound(this, SE_EMY_BIG_DOSSUN_DEAD); - // Adjust this to equal the scale of your boss / 80. - this->scale.x -= 0.015; - this->scale.y -= 0.015; - this->scale.z -= 0.015; - - if (this->timer == 30) { - CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 756); - CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 801); - CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 957); - this->timer = 0; - } - - this->timer += 1; + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 988); + CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 989); } - else { - this->scale.x = 0.0; - this->scale.y = 0.0; - this->scale.z = 0.0; - - CreateEffect(&this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}, 588); - this->dying = 1; - this->timer = 0; + if (this->timer == 60) { + OSReport("Outro Play Fanfare\n"); PlaySound(this, STRM_BGM_SHIRO_BOSS_CLEAR); MakeMarioEnterDemoMode(); } + + if (this->timer == 120) { + OSReport("Outro Play Victory Cry\n"); + + UpdateGameMgr(); + + if (GetSpecificPlayerActor(0) != 0) { + PlaySound(this, SE_VOC_MA_CLEAR_BOSS); + // Send PlBase into DemoGoal State here, kthxbai + } + + if (GetSpecificPlayerActor(1) != 0) { + PlaySound(this, SE_VOC_LU_CLEAR_BOSS); + // Send PlBase into DemoGoal State here, kthxbai + } + + if (GetSpecificPlayerActor(2) != 0) { + PlaySound(this, SE_VOC_KO_CLEAR_BOSS); + // Send PlBase into DemoGoal State here, kthxbai + } + + if (GetSpecificPlayerActor(3) != 0) { + PlaySound(this, SE_VOC_KO2_CLEAR_BOSS); + // Send PlBase into DemoGoal State here, kthxbai + } + } + + if (this->timer > 240) { + OSReport("Outro Out\n"); + ExitStage(WORLD_MAP, 0, BEAT_LEVEL, MARIO_WIPE); + } + + this->timer += 1; } void daEnMegaDosun_c::endState_Outro() { } diff --git a/src/soundPlayer.S b/src/soundPlayer.S index 8866460..1cf7cbd 100644 --- a/src/soundPlayer.S +++ b/src/soundPlayer.S @@ -137,3 +137,31 @@ StopSound: mtlr r0 blr + + + + +# No where else to put this at the time, fuckit +.global KnockMarioBack +KnockMarioBack: + + stwu r1, -0x10(r1) + mflr r0 + stw r0, 0x14(r1) + stw r31, 0xC(r1) + stw r30, 0x8(r1) + + lwz r3, 4(r3) + mr r4, r4 + li r5, 3 + lwz r12, 0x60(r3) + lwz r12, 0x3F4(r12) + mtctr r12 + bctrl + + lwz r0, 0x14(r1) + lwz r4, 0xC(r1) + lwz r3, 0x8(r1) + mtlr r0 + addi r1, r1, 0x10 + blr \ No newline at end of file diff --git a/src/topman.cpp b/src/topman.cpp new file mode 100644 index 0000000..4509272 --- /dev/null +++ b/src/topman.cpp @@ -0,0 +1,480 @@ +#include +#include +#include +#include +#include +#include "effects.h" +#include "player.h" + +class daTopman : public dEn_c { + int onCreate(); + int onDelete(); + int onExecute(); + int onDraw(); + + mHeapAllocator_c allocator; + nw4r::g3d::ResFile resFile; + + m3d::mdl_c bodyModel; + + m3d::anmChr_c chrAnimation; + + int timer; + char damage; + char isDown; + float XSpeed; + u32 cmgr_returnValue; + bool isBouncing; + char isInSpace; + char fromBehind; + + static daTopman *build(); + + void bindAnimChr_and_setUpdateRate(const char* name, int unk, float unk2, float rate); + void updateModelMatrices(); + bool calculateTileCollisions(); + + // void spriteCollision(ActivePhysics *apThis, ActivePhysics *apOther); + void playerCollision(ActivePhysics *apThis, ActivePhysics *apOther); + void yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther); + + void collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCatD_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat7_WMWaggleWater(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat7_WMWaggleWaterYoshi(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther); + // bool collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther); + void collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther); + + void _vf148(); + void _vf14C(); + + USING_STATES(daTopman); + DECLARE_STATE(Walk); + DECLARE_STATE(Turn); + DECLARE_STATE(KnockBack); + DECLARE_STATE(Die); +}; + +daTopman *daTopman::build() { + void *buffer = AllocFromGameHeap1(sizeof(daTopman)); + return new(buffer) daTopman; +} + +/////////////////////// +// Externs and States +/////////////////////// + extern "C" void *PlaySound(dStageActor_c *, int soundID); + extern "C" void *PlaySoundAsync(dStageActor_c *, int soundID); + extern "C" void *EN_LandbarrelPlayerCollision(dEn_c* t, ActivePhysics *apThis, ActivePhysics *apOther); + + extern "C" dStageActor_c *CreateActor(u16 classID, int settings, Vec pos, char rot, char layer); + extern "C" u8 dSprite_c__getXDirectionOfFurthestPlayerRelativeToVEC3(daTopman *, Vec pos); + + //FIXME make this dEn_c->used... + extern "C" char usedForDeterminingStatePress_or_playerCollision(dEn_c* t, ActivePhysics *apThis, ActivePhysics *apOther, int unk1); + extern "C" int SmoothRotation(short* rot, u16 amt, int unk2); + + + CREATE_STATE(daTopman, Walk); + CREATE_STATE(daTopman, Turn); + CREATE_STATE(daTopman, KnockBack); + CREATE_STATE(daTopman, Die); + + // begoman_attack2" // wobble back and forth tilted forwards + // begoman_attack3" // Leaned forward, antennae extended + // begoman_damage" // Bounces back slightly + // begoman_damage2" // Stops spinning and wobbles to the ground like a top + // begoman_stand" // Stands still, waiting + // begoman_wait" // Dizzily Wobbles + // begoman_wait2" // spins around just slightly + // begoman_attack" // Rocks backwards, and then attacks to an upright position, pulsing out his antennae + + +//////////////////////// +// Collision Functions +//////////////////////// + + // Collision callback to help shy guy not die at inappropriate times and ruin the dinner + + void daTopman::playerCollision(ActivePhysics *apThis, ActivePhysics *apOther) { + + char hitType; + hitType = usedForDeterminingStatePress_or_playerCollision(this, apThis, apOther, 0); + + if(hitType == 1) { // regular jump + apOther->someFlagByte |= 2; + this->dEn_c::playerCollision(apThis, apOther); + this->_vf220(apOther->owner); + } + else if(hitType == 3) { // spinning jump or whatever? + apOther->someFlagByte |= 2; + this->dEn_c::playerCollision(apThis, apOther); + this->_vf220(apOther->owner); + } + else if(hitType == 0) { + EN_LandbarrelPlayerCollision(this, apThis, apOther); + if (this->direction == apOther->owner->direction) { + this->direction ^= 1; + this->fromBehind = 1; + } + doStateChange(&StateID_KnockBack); + } + + // fix multiple player collisions via megazig + this->isDead = 0; + this->flags_4FC |= (1<<(31-7)); + if(apOther->owner->which_player < 4) { + this->counter_504[apOther->owner->which_player] = 0; + } + } + + void daTopman::yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther) { + this->playerCollision(apThis, apOther); + } + + void daTopman::collisionCatD_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther) { + this->dEn_c::playerCollision(apThis, apOther); + this->_vf220(apOther->owner); + + this->isDead = 0; + this->flags_4FC |= (1<<(31-7)); + if(apOther->owner->which_player < 4) { + this->counter_504[apOther->owner->which_player] = 0; + } + } + + void daTopman::collisionCat7_WMWaggleWater(ActivePhysics *apThis, ActivePhysics *apOther) { + this->collisionCatD_GroundPound(apThis, apOther); + } + + void daTopman::collisionCat7_WMWaggleWaterYoshi(ActivePhysics *apThis, ActivePhysics *apOther) { + this->collisionCatD_GroundPound(apThis, apOther); + } + + void daTopman::collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther) { + doStateChange(&StateID_KnockBack); + } + + void daTopman::collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther){ + doStateChange(&StateID_Die); + } + + void daTopman::collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther){ + doStateChange(&StateID_KnockBack); + } + + void daTopman::collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther){ + doStateChange(&StateID_KnockBack); + } + + void daTopman::collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther) { + doStateChange(&StateID_KnockBack); + } + + // void daTopman::collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther) { + // doStateChange(&StateID_DieFall); + // } + + // These handle the ice crap + void daTopman::_vf148() { + dEn_c::_vf148(); + doStateChange(&StateID_Die); + } + void daTopman::_vf14C() { + dEn_c::_vf14C(); + doStateChange(&StateID_Die); + } + + void daTopman::collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther) { + doStateChange(&StateID_Die); + } + +bool daTopman::calculateTileCollisions() { + // Returns true if sprite should turn, false if not. + + HandleXSpeed(); + HandleYSpeed(); + doSpriteMovement(); + + cmgr_returnValue = collMgr.CollidedWithTile(); + collMgr.execute(); + + if (isBouncing) { + stuffRelatingToCollisions(0.1875f, 1.0f, 0.5f); + if (speed.y != 0.0f) + isBouncing = false; + } + + float xDelta = pos.x - last_pos.x; + if (xDelta >= 0.0f) + direction = 0; + else + direction = 1; + + if (collMgr.CollidedWithTile()) { + // Walking into a tile branch + + if (cmgr_returnValue == 0) + isBouncing = true; + + if (speed.x != 0.0f) { + //playWmEnIronEffect(); + } + + speed.y = 0.0f; + + // u32 blah = collMgr.s_80070760(); + // u8 one = (blah & 0xFF); + // static const float incs[5] = {0.00390625f, 0.0078125f, 0.015625f, 0.0234375f, 0.03125f}; + // x_speed_inc = incs[one]; + max_speed.x = (direction == 1) ? -1.0f : 1.0f; + } else { + x_speed_inc = 0.0f; + } + + // Bouncing checks + if (_34A & 4) { + Vec v = (Vec){0.0f, 1.0f, 0.0f}; + collMgr.parent_speed_ptr = &v; + + if (collMgr.SomethingSemiImportant(collMgr.bitfield_for_checks)) + speed.y = 0.0f; + + collMgr.parent_speed_ptr = &speed; + + } else { + if (collMgr.SomethingSemiImportant(collMgr.bitfield_for_checks)) + speed.y = 0.0f; + } + + collMgr.s_8006FA40(0); + + // Switch Direction + if (collMgr.bitfield_for_checks & (0x15 << direction)) { + if (collMgr.CollidedWithTile()) { + isBouncing = true; + } + return true; + } + return false; +} + +void daTopman::bindAnimChr_and_setUpdateRate(const char* name, int unk, float unk2, float rate) { + nw4r::g3d::ResAnmChr anmChr = this->resFile.GetResAnmChr(name); + this->chrAnimation.bind(&this->bodyModel, anmChr, unk); + this->bodyModel.bindAnim(&this->chrAnimation, unk2); + this->chrAnimation.setUpdateRate(rate); +} + +int daTopman::onCreate() { + + // Model creation + allocator.link(-1, GameHeaps[0], 0, 0x20); + + this->resFile.data = getResource("ben", "g3d/begoman_spike.brres"); + nw4r::g3d::ResMdl mdl = this->resFile.GetResMdl("begoman"); + bodyModel.setup(mdl, &allocator, 0x224, 1, 0); + SetupTextures_Map(&bodyModel, 0); + + + // Animations start here + nw4r::g3d::ResAnmChr anmChr = this->resFile.GetResAnmChr("begoman_wait"); + this->chrAnimation.setup(mdl, anmChr, &this->allocator, 0); + + allocator.unlink(); + + // Stuff I do understand + this->scale = (Vec){0.2, 0.2, 0.2}; + + // this->pos.y = this->pos.y + 30.0; // X is vertical axis + this->rot.x = 0; // X is vertical axis + this->rot.y = 0xD800; // Y is horizontal axis + this->rot.z = 0; // Z is ... an axis >.> + this->direction = 1; // Heading left. + + this->speed.x = 0.0; + this->speed.y = 0.0; + this->max_speed.x = 0.8; + this->x_speed_inc = 0.0; + this->XSpeed = 0.8; + + this->isInSpace = this->settings & 0xF; + this->fromBehind = 0; + + ActivePhysics::Info HitMeBaby; + + HitMeBaby.xDistToCenter = 0.0; + HitMeBaby.yDistToCenter = 12.0; + + HitMeBaby.xDistToEdge = 14.0; + HitMeBaby.yDistToEdge = 12.0; + + HitMeBaby.category1 = 0x3; + HitMeBaby.category2 = 0x0; + HitMeBaby.bitfield1 = 0x4F; + HitMeBaby.bitfield2 = 0xffbafffe; + HitMeBaby.unkShort1C = 0; + HitMeBaby.callback = &dEn_c::collisionCallback; + + OSReport("Making the Physics Class and adding to the list\n"); + this->aPhysics.initWithStruct(this, &HitMeBaby); + this->aPhysics.addToList(); + + + // Tile collider + OSReport("Making the Tile collider Class\n"); + + // These fucking rects do something for the tile rect + spriteSomeRectX = 28.0f; + spriteSomeRectY = 32.0f; + _320 = 0.0f; + _324 = 16.0f; + + // These structs tell stupid collider what to collide with - these are from koopa troopa + static const u8 one[16] = {0,0,0,1, 0,0,0xC0,0, 0,0,0x40,0, 0,0,0,0}; + static const u8 two[12] = {0,0,0,0, 0,0,0,0, 0,0,0xC0,0}; + static const u8 three[16] = {0,0,0,1, 0,0,0x60,0, 0,0,0x90,0, 0,0,0x60,0}; + + collMgr.Init(this, one, two, three); + collMgr.execute(); + + cmgr_returnValue = collMgr.CollidedWithTile(); + + if (collMgr.CollidedWithTile()) + isBouncing = false; + else + isBouncing = true; + + + // State Changers + bindAnimChr_and_setUpdateRate("begoman_wait2", 1, 0.0, 1.0); + doStateChange(&StateID_Walk); + + this->onExecute(); + return true; +} + +int daTopman::onDelete() { + return true; +} + +int daTopman::onExecute() { + acState.execute(); + updateModelMatrices(); + + return true; +} + +int daTopman::onDraw() { + bodyModel.scheduleForDrawing(); + bodyModel._vf1C(); + + return true; +} + +void daTopman::updateModelMatrices() { + matrix.translation(pos.x, pos.y - 2.0, pos.z); + matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z); + + bodyModel.setDrawMatrix(matrix); + bodyModel.setScale(&scale); + bodyModel.calcWorld(false); +} + + +/////////////// +// Walk State +/////////////// + void daTopman::beginState_Walk() { + this->max_speed.x = (this->direction) ? -this->XSpeed : this->XSpeed; + this->speed.x = (direction) ? -0.8f : 0.8f; + + this->max_speed.y = (this->isInSpace) ? -2.0 : -4.0; + this->speed.y = (this->isInSpace) ? -2.0 : -4.0; + this->y_speed_inc = (this->isInSpace) ? -0.09375 : -0.1875; + } + void daTopman::executeState_Walk() { + + bool ret = calculateTileCollisions(); + if (ret) { + doStateChange(&StateID_Turn); + } + + if(this->chrAnimation.isAnimationDone()) { + this->chrAnimation.setCurrentFrame(0.0); + } + } + void daTopman::endState_Walk() { } + +/////////////// +// Turn State +/////////////// + void daTopman::beginState_Turn() { + this->direction ^= 1; + this->speed.x = 0.0; + } + void daTopman::executeState_Turn() { + + if(this->chrAnimation.isAnimationDone()) { + this->chrAnimation.setCurrentFrame(0.0); + } + + u16 amt = (this->direction == 0) ? 0x2800 : 0xD800; + int done = SmoothRotation(&this->rot.y, amt, 0x800); + + if(done) { + this->doStateChange(&StateID_Walk); + } + } + void daTopman::endState_Turn() { } + + +/////////////// +// Die State +/////////////// + void daTopman::beginState_Die() { + dEn_c::dieFall_Begin(); + + bindAnimChr_and_setUpdateRate("begoman_damage2", 1, 0.0, 1.0); + this->timer = 0; + } + void daTopman::executeState_Die() { + + if(this->chrAnimation.isAnimationDone()) { + this->kill(); + this->Delete(1); + } + } + void daTopman::endState_Die() { } + + +/////////////// +// Knockback State +/////////////// + void daTopman::beginState_KnockBack() { + bindAnimChr_and_setUpdateRate("begoman_damage", 1, 0.0, 0.75); + this->timer = 0; + this->max_speed.x = (this->direction) ? this->XSpeed*5.0 : -this->XSpeed*5.0; + this->speed.x = (direction) ? 4.0f : -4.0f; + } + void daTopman::executeState_KnockBack() { + + bool ret = calculateTileCollisions(); + this->speed.x = this->speed.x / 1.1; + + if(this->chrAnimation.isAnimationDone()) { + doStateChange(&StateID_Walk); + } + + } + void daTopman::endState_KnockBack() { + if (this->fromBehind == 0) { + this->direction ^= 1; } + this->fromBehind = 0; + bindAnimChr_and_setUpdateRate("begoman_wait2", 1, 0.0, 1.0); + } + \ No newline at end of file diff --git a/topman.yaml b/topman.yaml new file mode 100644 index 0000000..1802ebb --- /dev/null +++ b/topman.yaml @@ -0,0 +1,10 @@ +--- +# Replaces TARZAN_ROPE + +source_files: [../src/topman.cpp] +hooks: + - name: TopmanBuild + type: add_func_pointer + src_addr_pal: 0x8097CFC8 + target_func: 'daTopman::build(void)' + -- cgit v1.2.3