summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Noga <Tempus@chronometry.ca>2012-03-06 21:50:10 -0600
committerColin Noga <Tempus@chronometry.ca>2012-03-06 21:50:10 -0600
commit19632e9b183402bb9a05030e12d0f1003765c31a (patch)
tree36fd2cd8141539e2811ed016f3e2f85de6055eb4
parent31fa0c0911000444af0e3b668caf51f061517689 (diff)
downloadkamek-19632e9b183402bb9a05030e12d0f1003765c31a.tar.gz
kamek-19632e9b183402bb9a05030e12d0f1003765c31a.zip
Improvements to ThwompaDomp, game.h, added Poodle, topman sprite
-rw-r--r--NewerProject.yaml4
-rw-r--r--bossPodouble.yaml10
-rw-r--r--bossThwompaDomp.yaml8
-rwxr-xr-xinclude/game.h4
-rw-r--r--kamek_pal.x5
-rw-r--r--src/bossPodouble.cpp706
-rw-r--r--src/bossThwompaDomp.cpp223
-rw-r--r--src/soundPlayer.S28
-rw-r--r--src/topman.cpp480
-rw-r--r--topman.yaml10
10 files changed, 1369 insertions, 109 deletions
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 <common.h>
+#include <game.h>
+#include <g3dhax.h>
+#include <sfx.h>
+#include <stage.h>
+#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 <stage.h>
#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 <common.h>
+#include <game.h>
+#include <g3dhax.h>
+#include <sfx.h>
+#include <stage.h>
+#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)'
+