#include #include #include #include #include "player.h" class daMegaGoomba_c : 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 animationChr; nw4r::g3d::ResAnmTexPat resTexPat; m3d::anmTexPat_c animationPat; //mAllocator_c allocator2; //FIXME add this back in ? //EGG::Effect effect; float timer; float dying; HermiteKey keysX[0x10]; unsigned int Xkey_count; HermiteKey keysY[0x10]; unsigned int Ykey_count; char life; //TODO use these for MegaGecko testing of params u32 marker1_start; nw4r::ut::Rect Bounding; u32 marker1_end; u32 marker2_start; int pickedChoice; u32 marker2_end; float XSpeed; float JumpHeight; float JumpDist; float JumpTime; bool takeHit(char count); void bindAnimChr_and_setUpdateRate(const char* name, int unk, float unk2, float rate); void dieFall_Begin(); void dieFall_Execute(); static daMegaGoomba_c *build(); void setupBodyModel(); void updateModelMatrices(); // bool preSpriteCollision(ActivePhysics *apThis, ActivePhysics *apOther); // bool prePlayerCollision(ActivePhysics *apThis, ActivePhysics *apOther); // bool preYoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther); // bool stageActorCollision(ActivePhysics *apThis, ActivePhysics *apOther); // void spriteCollision(ActivePhysics *apThis, ActivePhysics *apOther); // void playerCollision(ActivePhysics *apThis, ActivePhysics *apOther); // void yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther); void collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther); void collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther); void collisionCat5_Mario(ActivePhysics *apThis, ActivePhysics *apOther); void collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther); void collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther); void collisionCatD_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther); void collisionCat11_PipeCannon(ActivePhysics *apThis, ActivePhysics *apOther); void collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther); void collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther); void _vf120(ActivePhysics *apThis, ActivePhysics *apOther); void _vf110(ActivePhysics *apThis, ActivePhysics *apOther); void _vf108(ActivePhysics *apThis, ActivePhysics *apOther); USING_STATES(daMegaGoomba_c); DECLARE_STATE(Grow); DECLARE_STATE(Shrink); DECLARE_STATE(Walk); DECLARE_STATE(Jump); DECLARE_STATE(Launch); }; daMegaGoomba_c *daMegaGoomba_c::build() { void *buffer = AllocFromGameHeap1(sizeof(daMegaGoomba_c)); return new(buffer) daMegaGoomba_c; } extern "C" void *PlaySound(daMegaGoomba_c *, int soundID); //FIXME makes these dEn_c::HandleXSpeed(); extern "C" void *HandleXSpeed(daMegaGoomba_c *); extern "C" void *HandleYSpeed(daMegaGoomba_c *); extern "C" void *UpdateObjectPosBasedOnSpeedValues_real(daMegaGoomba_c *); extern "C" u32 GenerateRandomNumber(int max); extern "C" u8 dSprite_c__getXDirectionOfFurthestPlayerRelativeToVEC3(daMegaGoomba_c *, Vec pos); extern "C" dStageActor_c *CreateActor(u16 classID, int settings, Vec pos, char rot, char layer); extern "C" dStageActor_c *GetSpecificPlayerActor(int number); CREATE_STATE(daMegaGoomba_c, Grow); CREATE_STATE(daMegaGoomba_c, Shrink); CREATE_STATE(daMegaGoomba_c, Walk); CREATE_STATE(daMegaGoomba_c, Jump); CREATE_STATE(daMegaGoomba_c, Launch); //TODO better fix for possible bug with sign (ex. life=120; count=-9;) bool daMegaGoomba_c::takeHit(char count) { int c = count; int l = this->life; if(l - c > 127) { c = 127 - l; } this->life -= c; this->XSpeed += 0.25; this->JumpHeight += 12.0; this->JumpDist += 12.0; this->JumpTime += 5.0; doStateChange(&StateID_Shrink); setNewActivePhysicsRect(this, &this->scale); return (life <= 0) ? true : false; } #define ACTIVATE 1 #define DEACTIVATE 0 //bool daMegaGoomba_c::preSpriteCollision(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("preSpriteCollision\n"); return false; } //bool daMegaGoomba_c::prePlayerCollision(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("prePlayerCollision\n"); return false; } //bool daMegaGoomba_c::preYoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("preYoshiCollision\n"); return false; } //bool daMegaGoomba_c::stageActorCollision(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("stageActorCollision\n"); return true; } //void daMegaGoomba_c::spriteCollision(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("spriteCollision\n"); } /*void daMegaGoomba_c::playerCollision(ActivePhysics *apThis, ActivePhysics *apOther) { this->_vf220(apOther->owner); OSReport("I hit Mario.\n"); }*/ //void daMegaGoomba_c::yoshiCollision(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("yoshiCollision\n"); } void daMegaGoomba_c::collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("Hit Fireball\n"); } bool daMegaGoomba_c::collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("Hit Iceball\n"); return false; } void daMegaGoomba_c::collisionCat3_StarPower(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("Hit StarMario\n"); } void daMegaGoomba_c::collisionCat5_Mario(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("MarioHit\n"); } void daMegaGoomba_c::collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("Hit Rolling Object\n"); if(this->takeHit(1)) doStateChange(&StateID_DieFall); } void daMegaGoomba_c::collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("Penguin Attack\n"); } void daMegaGoomba_c::collisionCatD_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("Groundpound\n"); } void daMegaGoomba_c::collisionCat11_PipeCannon(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("PipeCannon Hit\n"); } void daMegaGoomba_c::collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("Hit Hammer\n"); if(this->takeHit(1)) doStateChange(&StateID_DieFall); } void daMegaGoomba_c::collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("Hit Yoshi Fire\n"); if(this->takeHit(1)) doStateChange(&StateID_DieFall); } void daMegaGoomba_c::_vf120(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("_vf120:\n"); } void daMegaGoomba_c::_vf110(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("_vf110:\n"); } void daMegaGoomba_c::_vf108(ActivePhysics *apThis, ActivePhysics *apOther) { OSReport("_vf108:\n"); } void daMegaGoomba_c::bindAnimChr_and_setUpdateRate(const char* name, int unk, float unk2, float rate) { nw4r::g3d::ResAnmChr anmChr = this->resFile.GetResAnmChr(name); this->animationChr.bind(&this->bodyModel, anmChr, unk); this->bodyModel.bindAnim(&this->animationChr, unk2); this->animationChr.setUpdateRate(rate); } void daMegaGoomba_c::dieFall_Begin() { // DOESN'T LOOK GOOD //this->bindAnimChr_and_setUpdateRate("damage", 0, 0.0, 1.0); //dSprite_c::dieFall_Begin(); } //TODO make this real perty like void daMegaGoomba_c::dieFall_Execute() { this->timer = this->timer + 1.0; this->dying = this->dying + 0.15; this->pos.x = this->pos.x + 0.15; this->pos.y = this->pos.y + ((-0.2 * (this->dying*this->dying)) + 5); this->dEn_c::dieFall_Execute(); } void HexDump(char* address, u32 length) { length = (length + 0x1f) & ~0x1f; char line[0x11] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; for(u32 ii=0; ii < length; ii += 0x10) { for(u32 jj=0; jj < 0x10; jj++) { if((address[ii+jj] < 0x20) || (address[ii+jj] > 0x7e)) { line[jj] = '.'; }else{ line[jj] = address[ii+jj]; } } OSReport("%08x: %04x %04x %04x %04x %04x %04x %04x %04x |%s|\n", (u32)(address+ii), *(u16*)(address+ii+0x00), *(u16*)(address+ii+0x02), *(u16*)(address+ii+0x04), *(u16*)(address+ii+0x06), *(u16*)(address+ii+0x08), *(u16*)(address+ii+0x0a), *(u16*)(address+ii+0x0c), *(u16*)(address+ii+0x0e), line); for(u32 jj=0; jj<0x10; jj++) line[jj] = 0; } } void daMegaGoomba_c::setupBodyModel() { allocator.link(-1, GameHeaps[0], 0, 0x20); this->resFile.data = getResource("kuribo", "g3d/t02.brres"); nw4r::g3d::ResMdl mdl = this->resFile.GetResMdl("kuribo"); bodyModel.setup(mdl, &allocator, 0x224, 1, 0); SetupTextures_Enemy(&bodyModel, 0); bool ret; nw4r::g3d::ResAnmChr anmChr = this->resFile.GetResAnmChr("walk"); ret = this->animationChr.setup(mdl, anmChr, &this->allocator, 0); nw4r::g3d::ResAnmTexPat anmPat = this->resFile.GetResAnmTexPat("walk"); this->resTexPat = anmPat; ret = this->animationPat.setup(mdl, anmPat, &this->allocator, 0, 1); this->animationPat.bindEntry(&this->bodyModel, &anmPat, 0, 0); this->bodyModel.bindAnim(&this->animationPat, 1.0); this->animationPat.setFrameForEntry(1.0, 0); allocator.unlink(); } int daMegaGoomba_c::onCreate() { OSReport("Creating MG's body model\n"); setupBodyModel(); OSReport("Creating MegaGoomba's Physics Struct\n"); //TODO find data for a fun, yet challenging, battle ActivePhysics::Info HitMeBaby; HitMeBaby.xDistToCenter = 0.0; HitMeBaby.yDistToCenter = 18.0; HitMeBaby.xDistToEdge = 24.0; HitMeBaby.yDistToEdge = 24.0; HitMeBaby.category1 = 0x3; HitMeBaby.category2 = 0x0; HitMeBaby.bitfield1 = 0x4f; HitMeBaby.bitfield2 = 0xffba7ffe; HitMeBaby.unkShort1C = 0; HitMeBaby.callback = &dEn_c::collisionCallback; this->aPhysics.initWithStruct(this, &HitMeBaby); this->aPhysics.addToList(); //sub_80034060(); //FIXME move this stuff elsewhere pos.y -= 16.0; pos.z = 3000.0; speed.x = dying = 0.0; rot.x = rot.z = 0; rot.y = 0x2000; // 0x2000 is left. 0xe000 is for right. direction = 0; life = 3; //TODO 1) allow setting bounding rect with settings //TODO 2) don't use bounding rect. use wall/floor/ceiling detection Bounding.left = pos.x - 212.0; Bounding.top = pos.y + 500.0; Bounding.right = pos.x + 212.0; Bounding.bottom = pos.y; //TODO for tests this->marker1_start = 0xaabbcc11; this->marker1_end = 0xaabbff11; this->marker2_start = 0xaabbcc12; this->marker2_end = 0xaabbff12; this->pickedChoice = -1; // 2.0 is good final speed this->XSpeed = 1.5; this->JumpHeight = 48.0; this->JumpDist = 64.0; this->JumpTime = 50.0; OSReport("Setting MegaGoomba's State\n"); doStateChange(&StateID_Grow); OSReport("Going to Execute MegaGoomba\n"); this->onExecute(); return true; } int daMegaGoomba_c::onDelete() { return true; } int daMegaGoomba_c::onExecute() { acState.execute(); updateModelMatrices(); if (this->aPhysics.result1 == 1) { char PlayerID = NearestPlayer(this); if(PlayerID > 0) { dStageActor_c *Player = GetSpecificPlayerActor(PlayerID); this->_vf220(Player); } } return true; } int daMegaGoomba_c::onDraw() { bodyModel.scheduleForDrawing(); bodyModel._vf1C(); animationPat.process(); return true; } void daMegaGoomba_c::updateModelMatrices() { // Bounds checking // move to onExecute(); // TODO possibly change to a state change if(this->life > 0) { if(this->pos.x < this->Bounding.left) { this->direction = !this->direction; rot.y = (this->direction) ? 0xe000 : 0x2000; this->speed.x = -this->speed.x; this->pos.x = this->Bounding.left; } else if (this->pos.x > this->Bounding.right) { this->direction = !this->direction; rot.y = (this->direction) ? 0xe000 : 0x2000; this->speed.x = -this->speed.x; this->pos.x = this->Bounding.right; } if(this->pos.y < this->Bounding.bottom) { this->speed.y = 0.0; this->pos.y = this->Bounding.bottom; } else if (this->pos.y > this->Bounding.top) { this->speed.y = 0.0; this->pos.y = this->Bounding.bottom; } } // This won't work with wrap because I'm lazy. 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); } // Grow State void daMegaGoomba_c::beginState_Grow() { this->timer = 1.0; float start, end, shift1, shift2; start = 59.0; shift1 = 90.0; shift2 = 120.0; end = 139.0; /* keysX[i] = { frame, value, slope }; */ Xkey_count = 7; keysX[0] = (HermiteKey){ start, 1.0, 1.0 }; keysX[1] = (HermiteKey){ (start+shift1)/2, 2.0, 1.0 }; keysX[2] = (HermiteKey){ shift1, 4.0, 1.0 }; keysX[3] = (HermiteKey){ (shift1+shift2)/2, 3.0, 1.0 }; keysX[3] = (HermiteKey){ shift2, 6.0, 1.0 }; keysX[3] = (HermiteKey){ (shift2+end)/2, 5.0, 1.0 }; keysX[6] = (HermiteKey){ end, 7.0, 1.0 }; } void daMegaGoomba_c::executeState_Grow() { this->timer += 1.0; if ((this->timer > 60.0) && (this->timer < 140.0)) { float modifier = GetHermiteCurveValue(this->timer, this->keysX, Xkey_count); this->scale = (Vec){modifier, modifier, modifier}; setNewActivePhysicsRect(this, &this->scale); } if(this->timer == 60.0) PlaySound(this, SE_EMY_KURI_CHANGE_BIG); if (this->timer > 170.0) { doStateChange(&StateID_Walk); } } void daMegaGoomba_c::endState_Grow() { } // Shrink State void daMegaGoomba_c::beginState_Shrink() { this->timer = 1.0; Xkey_count = 4; keysX[0] = (HermiteKey){ 0.0, this->scale.x, 1.0 }; keysX[1] = (HermiteKey){ 20.0, this->scale.x - 2.0, 1.0 }; keysX[2] = (HermiteKey){ 40.0, this->scale.x, 1.0 }; keysX[3] = (HermiteKey){ 59.0, this->scale.x - 2.0, 1.0 }; // using this to stop walk animation this->animationChr.setCurrentFrame(600.0); } void daMegaGoomba_c::executeState_Shrink() { this->timer += 1.0; float modifier = GetHermiteCurveValue(this->timer, this->keysX, Xkey_count); this->scale = (Vec){modifier, modifier, modifier}; setNewActivePhysicsRect(this, &this->scale); if(this->timer == 2.0) PlaySound(this, SE_EMY_KURIBO_L_DAMAGE_02); if (this->timer > 60.0) { doStateChange(&StateID_Walk); } } void daMegaGoomba_c::endState_Shrink() { } // Launch State - Launches some small goombas up in arcs void daMegaGoomba_c::beginState_Launch() { this->timer = 0.0; rot.y = 0x0; // using this to stop walk animation this->animationChr.setCurrentFrame(600.0); } void daMegaGoomba_c::executeState_Launch() { if (this->timer < 120.0) { // 3 shakes per second, exactly 24 shakes overall this->rot.y = sin(this->timer * 3.14 / 5) * 4000; dStageActor_c *spawner = NULL; // 120ticks / 120numbers * 3cases = 3avg kuribo int randChoice = GenerateRandomNumber(120); int randChoiceX = GenerateRandomNumber(12); int randChoiceY = GenerateRandomNumber(7); switch(randChoice) { case 0: case 1: spawner = CreateActor(EN_KURIBO, 0, this->pos, 0, 0); spawner->speed.x = randChoiceX - 6.0; spawner->speed.y = randChoiceY + 3.0; spawner->scale = (Vec){1.0, 1.0, 1.0}; break; case 2: spawner = CreateActor(EN_BEANS_KURIBO, 0, this->pos, 0, 0); spawner->speed.x = randChoiceX - 6.0; spawner->speed.y = randChoiceY + 3.0; spawner->scale = (Vec){1.0, 1.0, 1.0}; break; case 3: spawner = CreateActor(EN_PATA_KURIBO, 0, this->pos, 0, 0); spawner->speed.x = randChoiceX - 6.0; spawner->speed.y = randChoiceY + 3.0; spawner->scale = (Vec){1.0, 1.0, 1.0}; break; default: break; }; } if (this->timer > 150.0) { doStateChange(&StateID_Walk); } this->timer = this->timer + 1.0; } void daMegaGoomba_c::endState_Launch() { rot.y = (this->direction) ? 0xe000 : 0x2000; } // Jump State void daMegaGoomba_c::beginState_Jump() { this->timer = 1.0; //Variables for choosing a curve float jump_height = this->JumpHeight; float delta = (this->direction) ? -JumpDist : JumpDist; float fullTime = this->JumpTime; //Key count Xkey_count = 2; Ykey_count = 3; //Initial Position keysX[0] = (HermiteKey){ 0.0, this->pos.x, 0.0 }; keysY[0] = (HermiteKey){ 0.0, this->pos.y, 0.8 }; //Middle Position keysY[1] = (HermiteKey){ (fullTime/2.0), this->pos.y + jump_height, 0.0 }; //End Position keysX[1] = (HermiteKey){ fullTime, this->pos.x + delta, 0.0 }; keysY[2] = (HermiteKey){ fullTime, this->pos.y, 0.8 }; // using this to stop walk animation this->animationChr.setCurrentFrame(600.0); } void daMegaGoomba_c::executeState_Jump() { this->pos.x = GetHermiteCurveValue(this->timer, this->keysX, Xkey_count); this->pos.y = GetHermiteCurveValue(this->timer, this->keysY, Ykey_count); float TimerMax = JumpTime + 1.0; if (this->timer > TimerMax) { doStateChange(&StateID_Walk); } this->timer = this->timer + 1.0; } void daMegaGoomba_c::endState_Jump() { } // Walk State void daMegaGoomba_c::beginState_Walk() { this->timer = 1.0; this->direction = dSprite_c__getXDirectionOfFurthestPlayerRelativeToVEC3(this, this->pos); rot.y = (this->direction) ? 0xe000 : 0x2000; //SETUP WALK ANIMATION// bindAnimChr_and_setUpdateRate("walk", 1, 0.0, 1.0); this->bodyModel.bindAnim(&this->animationPat, 0.0); this->animationPat.setUpdateRateForEntry(1.0, 0); this->animationPat.setEntryByte34(0, 0); float num = (float)GenerateRandomNumber(0xB4); this->animationPat.setFrameForEntry(num, 0); } void daMegaGoomba_c::executeState_Walk() { /* nw4r::g3d::ResMdl mdl* = this->bodyModel.GetResMdl(); ResNode resNode = mdl->GetResNode("leg_left"); resNode._C; mMtx mtx; this->bodyModel.GetSomeMatrix(resNode._C, &mtx); Vec vctr; ConvertMatrixToTranslationVector(&mtx, &vctr); */ // USE THIS FOR STATE CHANGES if(this->animationChr.isAnimationDone()) this->animationChr.setCurrentFrame(0.0); //HandleAcceleration(this); //HandleXSpeed(this); //UpdateObjectPosBasedOnSpeedValues_real(this); //DoGravityMaybe(); float delta = (this->direction) ? -this->XSpeed : this->XSpeed; this->pos.x += delta; int Choice; float TimerMax = 150.0; if (this->timer > TimerMax) { if(this->pickedChoice != -1) { Choice = this->pickedChoice; } else { Choice = GenerateRandomNumber(4); } switch(Choice) { case 0: doStateChange(&StateID_Jump); break; case 1: doStateChange(&StateID_Launch); break; default: this->direction = dSprite_c__getXDirectionOfFurthestPlayerRelativeToVEC3(this, pos); rot.y = (this->direction) ? 0xe000 : 0x2000; this->timer = 0; break; }; } this->timer = this->timer + 1.0; } void daMegaGoomba_c::endState_Walk() { }