#include #include #include #include #include #include "boss.h" // Externs extern "C" int posIsInZone(Vec,float*,float*,u8 zone); extern "C" void* ScreenPositionClass; extern "C" int SpawnThwompEffects(dEn_c *); extern "C" void* SoundRelatedClass; extern "C" Vec ConvertStagePositionIntoScreenPosition__Maybe(Vec); extern "C" void AnotherSoundRelatedFunction(void*,SFX,Vec,int); class daEnMegaDosun_c : public daBoss { int onCreate(); int onDelete(); int onExecute(); int onDraw(); static daEnMegaDosun_c *build(); mHeapAllocator_c allocator; // _524 nw4r::g3d::ResFile resFile; // _540 m3d::mdl_c bodyModel; // _544 m3d::anmVis_c anmVis; // _584 lineSensor_s belowSensor; float shakePosXoffset; // _5CC shakePosXoffset u16 puruMoveCounter; // _5D8 u16 shakeIndex; // _5DA 0=shake,1=normal u32 countdownTimer; // _5DC int timer; char notFalling; char dying; float leftBuffer; float rightBuffer; float topBuffer; bool isOutofScreen; Vec OutOfScreenPosition; void setupBodyModel(); void playerCollision(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat7_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther); bool collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther); void powBlockActivated(bool isNotMPGP); USING_STATES(daEnMegaDosun_c); DECLARE_STATE(UpWait); DECLARE_STATE(DownMoveWait); DECLARE_STATE(PuruMove); DECLARE_STATE(DownMove); DECLARE_STATE(DownWait); DECLARE_STATE(UpMove); DECLARE_STATE(Grow); DECLARE_STATE(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)); return new(buffer) daEnMegaDosun_c; } void daEnMegaDosun_c::powBlockActivated(bool isNotMPGP) { } // Collisions void daEnMegaDosun_c::playerCollision(ActivePhysics *apThis, ActivePhysics *apOther) { DamagePlayer(this, apThis, apOther); } bool daEnMegaDosun_c::collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther) { return true; } bool daEnMegaDosun_c::collisionCat2_IceBall_15_YoshiIce(ActivePhysics *apThis, ActivePhysics *apOther) { return false; } bool daEnMegaDosun_c::collisionCat7_GroundPound(ActivePhysics *apThis, ActivePhysics *apOther) { DamagePlayer(this, apThis, apOther); return true; } bool daEnMegaDosun_c::collisionCat9_RollingObject(ActivePhysics *apThis, ActivePhysics *apOther) { return true; } bool daEnMegaDosun_c::collisionCat13_Hammer(ActivePhysics *apThis, ActivePhysics *apOther) { return true; } bool daEnMegaDosun_c::collisionCat14_YoshiFire(ActivePhysics *apThis, ActivePhysics *apOther) { return true; } bool daEnMegaDosun_c::collisionCatA_PenguinMario(ActivePhysics *apThis, ActivePhysics *apOther) { DamagePlayer(this, apThis, apOther); return true; } void daEnMegaDosun_c::setupBodyModel() { allocator.link(-1, GameHeaps[0], 0, 0x20); 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); allocator.unlink(); } int daEnMegaDosun_c::onCreate() { this->setupBodyModel(); this->_36D = 0; // byte this->frzMgr.setSomething(1,1,1); //@0x809f5c5c this->pos.y -= 21.0; this->pos.z = -280.0; // behind layer1 (hides spikes) belowSensor.flags = SENSOR_10000000 | SENSOR_1000000 | SENSOR_BREAK_BRICK | SENSOR_BREAK_BLOCK | SENSOR_100 | SENSOR_LINE; belowSensor.lineA = -31 << 12; belowSensor.lineB = 31 << 12; belowSensor.distanceFromCenter = 5 << 12; ActivePhysics::Info hm; hm.xDistToCenter = 0.0; hm.yDistToCenter = 41.0; hm.xDistToEdge = 36.0; hm.yDistToEdge = 38.0; hm.category1 = 0x03; hm.category2 = 0x00; hm.bitfield1 = 0x0000004F; hm.bitfield2 = 0x0008820E; hm.unkShort1C = 0x0100; hm.callback = &dEn_c::collisionCallback; this->aPhysics.initWithStruct(this, &hm); lineSensor_s aboveSensor(-31 << 12, 31 << 12, -31 << 12); this->collMgr.init(this, &belowSensor, &aboveSensor, 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; this->aPhysics.addToList(); this->scale.x = 1.0; this->scale.y = 1.0; this->scale.z = 1.0; this->max_speed.x = 0.0; this->max_speed.y = -8.0; this->max_speed.z = 0.0; this->y_speed_inc = -0.25; this->rot.x = 0; this->rot.y = 0; this->rot.z = 0; 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) - 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); this->onExecute(); return true; } int daEnMegaDosun_c::onExecute() { acState.execute(); 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) { this->OutOfScreenPosition = this->pos; this->isOutofScreen = true; doStateChange(&StateID_Outro); } } return true; } int daEnMegaDosun_c::onDraw() { 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(); return true; } int daEnMegaDosun_c::onDelete() { return true; } // Grow State void daEnMegaDosun_c::beginState_Grow() { this->scale = (Vec){0.5, 0.5, 0.5}; this->timer = 0; SetupKameck(this, Kameck); } void daEnMegaDosun_c::executeState_Grow() { bool ret; ret = GrowBoss(this, Kameck, 0.5, 1.0, 0, this->timer); if (ret) { PlaySound(this, SE_EMY_BIG_DOSSUN); doStateChange(&StateID_UpMove); } this->timer += 1; } void daEnMegaDosun_c::endState_Grow() { CleanupKameck(this, Kameck); } // StateID_UpWait void daEnMegaDosun_c::beginState_UpWait() { belowSensor.flags = SENSOR_10000000 | SENSOR_1000000 | SENSOR_BREAK_BRICK | SENSOR_BREAK_BLOCK | SENSOR_100 | SENSOR_LINE; this->timer = 0; } void daEnMegaDosun_c::executeState_UpWait() { if(this->countdownTimer != 0) { this->countdownTimer--; return; } if (this->pos.x > this->rightBuffer) { SpawnEffect("Wm_en_dossunfall02", 0, &(Vec){this->pos.x + 38.0, this->pos.y + 32.0, 5500.0}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); PlaySoundAsync(this, SE_OBJ_TEKKYU_G_CRASH); this->direction = 0; } if (this->pos.x < this->leftBuffer) { SpawnEffect("Wm_en_dossunfall02", 0, &(Vec){this->pos.x - 40.0, this->pos.y + 32.0, 5500.0}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); PlaySoundAsync(this, SE_OBJ_TEKKYU_G_CRASH); this->direction = 1; } this->pos.x += (direction) ? 1.2 : -1.2; if (this->notFalling == 0) { if(this->CheckIfPlayerBelow(40.0, 256.0)) { this->doStateChange(&StateID_DownMoveWait); this->speed.y = 0.0; } } if (this->timer == 30) { this->notFalling = 0; } this->timer += 1; } void daEnMegaDosun_c::endState_UpWait() { this->notFalling = 1; return; } // StateID_DownMoveWait void daEnMegaDosun_c::beginState_DownMoveWait() { 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(); } void daEnMegaDosun_c::endState_DownMoveWait() { return; } // StateID_PuruMove void daEnMegaDosun_c::beginState_PuruMove() { this->puruMoveCounter = 8; this->shakeIndex = 0; } void daEnMegaDosun_c::executeState_PuruMove() { if(this->puruMoveCounter == 0) { this->shakePosXoffset = 0.0; this->doStateChange(&StateID_DownMove); return; } this->puruMoveCounter--; if((this->puruMoveCounter & 2) == 0) return; float _array[] = {2.0, 0.0}; this->shakeIndex ^= 1; this->shakePosXoffset = _array[this->shakeIndex]; } void daEnMegaDosun_c::endState_PuruMove() { return; } // StateID_DownMove void daEnMegaDosun_c::beginState_DownMove() { this->speed.y = 0.0; } void daEnMegaDosun_c::executeState_DownMove() { this->HandleYSpeed(); this->UpdateObjectPosBasedOnSpeedValuesReal(); //FIXME what do I do? - bottom detection int ret = this->collMgr.calculateBelowCollisionWithSmokeEffect(); if(!ret) return; if(!(ret & 0x400000)) { this->doStateChange(&StateID_DownWait); this->countdownTimer = 0x40; this->speed.y = 0.0; ShakeScreen(ScreenPositionClass, 0, 1, 0, 0); PlaySoundAsync(this, SE_EMY_BIG_DOSSUN); } else { belowSensor.flags = SENSOR_LINE; this->speed.y = 0.0; ShakeScreen(ScreenPositionClass, 0, 1, 0, 0); this->collMgr.clear2(); PlaySoundAsync(this, SE_EMY_BIG_DOSSUN); } SpawnThwompEffects(this); Vec p = ConvertStagePositionIntoScreenPosition__Maybe(this->pos); AnotherSoundRelatedFunction(SoundRelatedClass, SE_EMY_BIG_DOSSUN, p, 0); //SoundRelatedClass.AnotherSoundRelatedFunction(SE_EMY_BIG_DOSSUN, p, 0); } void daEnMegaDosun_c::endState_DownMove() { return; } // StateID_DownWait void daEnMegaDosun_c::beginState_DownWait() { return; } void daEnMegaDosun_c::executeState_DownWait() { if(this->countdownTimer == 0) { this->doStateChange(&StateID_UpMove); } else { this->countdownTimer--; if(this->countdownTimer == 0x20) { this->anmVis.playState = 3; } } this->anmVis.process(); } void daEnMegaDosun_c::endState_DownWait() { return; } // StateID_UpMove void daEnMegaDosun_c::beginState_UpMove() { this->collMgr.clear2(); } void daEnMegaDosun_c::executeState_UpMove() { // this->speed.y = 0.0; // this->UpdateObjectPosBasedOnSpeedValuesReal(); if (this->pos.y > this->topBuffer) { this->doStateChange(&StateID_UpWait); PlaySoundAsync(this, SE_OBJ_TEKKYU_L_CRASH); this->countdownTimer = 0xc; } else { this->pos.y += 1.5; } } void daEnMegaDosun_c::endState_UpMove() { return; } // Outro void daEnMegaDosun_c::beginState_Outro() { OutroSetup(this); this->timer = 0; this->speed.y = 0.0; this->y_speed_inc = 0.0; } void daEnMegaDosun_c::executeState_Outro() { this->pos.y = this->OutOfScreenPosition.y + 280.0; if (this->timer == 0) { nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_EMY_BIG_DOSSUN_DEAD, 1); SpawnEffect("Wm_mr_stockitemuse_b", 0, &this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}); SpawnEffect("Wm_mr_stockitemuse_c", 0, &this->pos, &(S16Vec){0,0,0}, &(Vec){2.0, 2.0, 2.0}); } if (this->timer == 60) { nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, STRM_BGM_SHIRO_BOSS_CLEAR, 1); BossGoalForAllPlayers(); } if (this->timer == 120) { PlayerVictoryCries(this); } if (this->timer > 240) { ExitStage(WORLD_MAP, 0, BEAT_LEVEL, MARIO_WIPE); } this->timer += 1; } void daEnMegaDosun_c::endState_Outro() { }