Path: blob/master/SonicMania/Objects/HCZ/DiveEggman.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: DiveEggman Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectDiveEggman *DiveEggman;1011void DiveEggman_Update(void)12{13RSDK_THIS(DiveEggman);1415StateMachine_Run(self->state);16}1718void DiveEggman_LateUpdate(void) {}1920void DiveEggman_StaticUpdate(void) {}2122void DiveEggman_Draw(void)23{24RSDK_THIS(DiveEggman);2526if (self->invincibilityTimer & 1)27RSDK.SetPaletteEntry(0, 130, 0xE0E0E0);2829RSDK.DrawSprite(&self->animator, NULL, false);3031RSDK.SetPaletteEntry(0, 130, 0x001840);32}3334void DiveEggman_Create(void *data)35{36RSDK_THIS(DiveEggman);3738if (globals->gameMode == MODE_TIMEATTACK) {39destroyEntity(self);40}41else {42self->drawFX = FX_FLIP;43if (!SceneInfo->inEditor) {44self->visible = true;45if (data) {46switch (VOID_TO_INT(data)) {47default: break;4849case DIVEEGGMAN_BOMB:50self->active = ACTIVE_NORMAL;51self->drawGroup = Zone->playerDrawGroup[0] + 1;52self->timer = 480;53RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 5, &self->animator, true, 0);54self->state = DiveEggman_StateBomb_Idle;55break;56}57}58else {59self->active = ACTIVE_BOUNDS;60self->drawGroup = Zone->playerDrawGroup[0] + 2;61self->updateRange.x = 0x800000;62self->startY = self->position.y;63self->updateRange.y = 0x800000;64self->health = 4;65DiveEggman->screwMobile = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, ScrewMobile);66RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 0, &self->animator, true, 0);67self->state = DiveEggman_StateEggman_AwaitPlayer;68}69}70}71}7273void DiveEggman_StageLoad(void)74{75if (RSDK.CheckSceneFolder("HCZ")) {76DiveEggman->diveFrames = RSDK.LoadSpriteAnimation("HCZ/DiveEggman.bin", SCOPE_STAGE);77DiveEggman->aniFrames = RSDK.LoadSpriteAnimation("Eggman/EggmanHCZ1.bin", SCOPE_STAGE);78}7980DiveEggman->unusedHitbox1.left = -8;81DiveEggman->unusedHitbox1.top = -8;82DiveEggman->unusedHitbox1.right = 8;83DiveEggman->unusedHitbox1.bottom = 8;8485DiveEggman->hitboxBomb.left = -8;86DiveEggman->hitboxBomb.top = -8;87DiveEggman->hitboxBomb.right = 8;88DiveEggman->hitboxBomb.bottom = 8;8990DiveEggman->hitboxEggman.left = -26;91DiveEggman->hitboxEggman.top = -22;92DiveEggman->hitboxEggman.right = 7;93DiveEggman->hitboxEggman.bottom = 11;9495DiveEggman->sfxBigFan = RSDK.GetSfx("HCZ/BigFan.wav");96DiveEggman->sfxHit = RSDK.GetSfx("Stage/BossHit.wav");97DiveEggman->sfxExplosion = RSDK.GetSfx("Stage/Explosion2.wav");98DiveEggman->sfxRockemSockem = RSDK.GetSfx("Stage/RockemSockem.wav");99}100101void DiveEggman_Hit(void)102{103RSDK_THIS(DiveEggman);104105RSDK.PlaySfx(DiveEggman->sfxHit, false, 255);106107self->invincibilityTimer = 30;108if (self->health)109self->health--;110111if (!self->health) {112self->timer = 120;113self->drawGroup = Zone->hudDrawGroup - 1;114self->state = DiveEggman_StateEggman_Destroyed;115SceneInfo->timeEnabled = false;116Player_GiveScore(RSDK_GET_ENTITY(SLOT_PLAYER1, Player), 1000);117}118}119120void DiveEggman_Explode(void)121{122RSDK_THIS(DiveEggman);123124if (!(Zone->timer & 7)) {125RSDK.PlaySfx(DiveEggman->sfxExplosion, false, 255);126127if (!(Zone->timer & 0xF)) {128int32 x = self->position.x + (RSDK.Rand(-19, 20) << 16);129int32 y = self->position.y + (RSDK.Rand(-24, 25) << 16);130EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y);131132if (self->timer <= 40)133explosion->drawGroup = self->drawGroup;134else135explosion->drawGroup = self->drawGroup - 1;136}137}138}139140void DiveEggman_StateEggman_AwaitPlayer(void)141{142RSDK_THIS(DiveEggman);143144EntityScrewMobile *screwMobile = DiveEggman->screwMobile;145146RSDK.ProcessAnimation(&self->animator);147148if (self->invincibilityTimer > 0)149self->invincibilityTimer--;150151if (screwMobile->state != ScrewMobile_State_CheckPlayerEnter) {152RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 1, &self->animator, true, 0);153self->velocity.x = -0x10000;154self->active = ACTIVE_NORMAL;155self->state = DiveEggman_StateEggman_Swimming;156}157158if (!RSDK.CheckOnScreen(self, &self->updateRange))159destroyEntity(self);160}161162void DiveEggman_StateEggman_Swimming(void)163{164RSDK_THIS(DiveEggman);165166EntityScrewMobile *screwMobile = DiveEggman->screwMobile;167168RSDK.ProcessAnimation(&self->animator);169if (self->invincibilityTimer > 0)170self->invincibilityTimer--;171172self->position.x += self->velocity.x;173174if (self->velocity.y > 0) {175self->position.y += self->velocity.y;176self->velocity.y -= 0x400;177}178179if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x200000, 0, true)180|| RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x200000, 0, true)) {181self->direction ^= FLIP_X;182self->velocity.x = -self->velocity.x;183}184185if (screwMobile->propellerAnimator.speed >= 0xFF) {186if (self->position.x <= screwMobile->position.x) {187self->direction = FLIP_NONE;188self->velocity.x = 0x8000;189}190else {191self->direction = FLIP_X;192self->velocity.x = -0x8000;193}194195RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 2, &self->animator, false, 0);196self->state = DiveEggman_StateEggman_InWhirlpool;197}198199if (--self->timer <= 0) {200self->timer = 180;201RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 4, &self->animator, false, 0);202self->state = DiveEggman_StateEggman_PlaceBomb;203}204}205206void DiveEggman_StateEggman_InWhirlpool(void)207{208RSDK_THIS(DiveEggman);209210EntityScrewMobile *screwMobile = DiveEggman->screwMobile;211212RSDK.ProcessAnimation(&self->animator);213214if (self->invincibilityTimer > 0)215self->invincibilityTimer--;216217self->position.x += self->velocity.x;218219if (self->position.y >= Water->waterLevel + 0x180000)220self->position.y -= 0x2000;221222if (screwMobile->propellerAnimator.speed >= 0x100) {223if (abs(self->position.x - screwMobile->position.x) < 0x100000) {224int32 x = self->position.x - screwMobile->position.x;225int32 y = MathHelpers_SquareRoot(0x100 - (x >> 16) * (x >> 16)) << 16;226227self->angle = RSDK.ATan2(x, y);228if (self->angle < 0x80)229self->drawGroup = Zone->playerDrawGroup[0] + 2;230else231self->drawGroup = Zone->hudDrawGroup - 1;232RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 3, &self->animator, false, 0);233self->state = DiveEggman_StateEggman_WhirlpoolRise;234}235}236else {237if (self->direction == FLIP_NONE)238self->velocity.x = -0x10000;239else240self->velocity.x = 0x10000;241242RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 1, &self->animator, false, 0);243self->state = DiveEggman_StateEggman_Swimming;244}245}246247void DiveEggman_StateEggman_WhirlpoolRise(void)248{249RSDK_THIS(DiveEggman);250251EntityScrewMobile *screwMobile = DiveEggman->screwMobile;252253RSDK.ProcessAnimation(&self->animator);254255if (self->invincibilityTimer > 0)256self->invincibilityTimer--;257258self->position.x = (RSDK.Cos256(self->angle) << 12) + screwMobile->position.x;259self->position.y -= 0x10000;260261if ((self->angle & 0xFF) < 0x80)262self->drawGroup = Zone->playerDrawGroup[0] + 2;263else264self->drawGroup = Zone->hudDrawGroup - 1;265self->angle += 4;266267if (screwMobile->propellerAnimator.speed >= 0x100) {268if (self->position.y < screwMobile->position.y + 0x280000) {269DiveEggman_Hit();270screwMobile->whirlPoolTimer = 60;271}272}273else {274if (self->position.y < Water->waterLevel - (screwMobile->whirlpoolHeight << 16)) {275self->velocity.y = -0x10000;276self->state = DiveEggman_StateEggman_Falling;277self->velocity.x = RSDK.Cos256(self->angle) << 8;278}279}280}281282void DiveEggman_StateEggman_Falling(void)283{284RSDK_THIS(DiveEggman);285286RSDK.ProcessAnimation(&self->animator);287288if (self->invincibilityTimer > 0)289self->invincibilityTimer--;290291self->position.x += self->velocity.x;292self->position.y += self->velocity.y;293self->velocity.y += 0x2800;294295if (self->position.y >= Water->waterLevel) {296self->velocity.y >>= 2;297CREATE_ENTITY(Water, INT_TO_VOID(WATER_SPLASH), self->position.x, Water->waterLevel);298299RSDK.PlaySfx(Water->sfxSplash, false, 255);300self->velocity.x = self->direction == FLIP_NONE ? -0x10000 : 0x10000;301RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 1, &self->animator, false, 0);302self->state = DiveEggman_StateEggman_Swimming;303}304}305306void DiveEggman_StateEggman_PlaceBomb(void)307{308RSDK_THIS(DiveEggman);309310RSDK.ProcessAnimation(&self->animator);311312if (self->invincibilityTimer > 0)313self->invincibilityTimer--;314315if (self->animator.frameID >= self->animator.frameCount - 1) {316EntityDiveEggman *bomb = CREATE_ENTITY(DiveEggman, INT_TO_VOID(DIVEEGGMAN_BOMB), self->position.x, self->position.y + 0x20000);317bomb->position.x += self->direction ? 0x1A0000 : -0x1A0000;318319RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 1, &self->animator, false, 0);320self->state = DiveEggman_StateEggman_Swimming;321}322}323324void DiveEggman_StateEggman_Destroyed(void)325{326RSDK_THIS(DiveEggman);327328RSDK.ProcessAnimation(&self->animator);329330if (self->invincibilityTimer > 0)331self->invincibilityTimer--;332333DiveEggman_Explode();334335if (--self->timer <= 0) {336Music_TransitionTrack(TRACK_STAGE, 0.0125);337RSDK.SetSpriteAnimation(DiveEggman->aniFrames, 0, &self->animator, true, 0);338self->velocity.y = -0x20000;339self->timer = 0x2000;340self->state = DiveEggman_StateEggman_Finish;341}342}343344void DiveEggman_StateEggman_Finish(void)345{346RSDK_THIS(DiveEggman);347348EntityScrewMobile *screwMobile = DiveEggman->screwMobile;349350RSDK.ProcessAnimation(&self->animator);351352if (self->invincibilityTimer > 0)353self->invincibilityTimer--;354355self->position.x += self->velocity.x;356357self->position.y += self->velocity.y;358self->velocity.y += self->timer;359360if (self->timer == 0x2000 && self->position.y >= Water->waterLevel) {361self->velocity.y >>= 2;362self->timer = 0x1000;363364CREATE_ENTITY(Water, INT_TO_VOID(WATER_SPLASH), self->position.x, Water->waterLevel);365RSDK.PlaySfx(Water->sfxSplash, false, 255);366}367368if (!RSDK.CheckOnScreen(self, NULL)) {369Zone->cameraBoundsT[0] = 0;370screwMobile->state = ScrewMobile_State_BossFinished;371destroyEntity(self);372}373}374375bool32 DiveEggman_CheckNoBombExplode(void)376{377RSDK_THIS(DiveEggman);378379RSDK.ProcessAnimation(&self->animator);380381if (!--self->timer) {382CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSS), self->position.x, self->position.y)->drawGroup = Zone->objectDrawGroup[1];383RSDK.PlaySfx(DiveEggman->sfxExplosion, false, 255);384385EntityWater *water = CREATE_ENTITY(Water, INT_TO_VOID(WATER_BUBBLE), self->position.x, self->position.y);386water->velocity.y = -0x8800;387water->angle = 2 * RSDK.Rand(0, 256);388water->bubbleX = water->position.x;389water->childPtr = 0;390RSDK.SetSpriteAnimation(Water->aniFrames, 3, &water->animator, true, 0);391392destroyEntity(self);393return false;394}395396return true;397}398399void DiveEggman_StateBomb_Idle(void)400{401RSDK_THIS(DiveEggman);402403if (self->velocity.x) {404if (self->velocity.x <= 0)405self->velocity.x += 0x2000;406else407self->velocity.x -= 0x2000;408}409410if (self->velocity.y > 0) {411self->position.y += self->velocity.y;412self->velocity.y -= 0x400;413}414415if (DiveEggman_CheckNoBombExplode()) {416EntityScrewMobile *screwMobile = DiveEggman->screwMobile;417418if (screwMobile->propellerAnimator.speed >= 0xFF) {419self->state = DiveEggman_StateBomb_InWhirlpool;420self->velocity.x = self->position.x > screwMobile->position.x ? -0x10000 : 0x10000;421}422}423}424425void DiveEggman_StateBomb_InWhirlpool(void)426{427RSDK_THIS(DiveEggman);428429EntityScrewMobile *screwMobile = DiveEggman->screwMobile;430431if (DiveEggman_CheckNoBombExplode()) {432self->position.x += self->velocity.x;433434if (self->position.y >= Water->waterLevel + 0x100000)435self->position.y -= 0x2000;436437if (screwMobile->propellerAnimator.speed >= 0x100) {438if (abs(self->position.x - screwMobile->position.x) < 0x100000) {439int32 x = self->position.x - screwMobile->position.x;440int32 y = MathHelpers_SquareRoot(0x100 - (x >> 16) * (x >> 16)) << 16;441442self->angle = RSDK.ATan2(x, y);443if (self->angle < 0x80)444self->drawGroup = Zone->playerDrawGroup[0] + 2;445else446self->drawGroup = Zone->hudDrawGroup - 1;447448self->state = DiveEggman_StateBomb_WhirlpoolRise;449}450}451else {452self->state = DiveEggman_StateBomb_Idle;453}454}455}456457void DiveEggman_StateBomb_WhirlpoolRise(void)458{459RSDK_THIS(DiveEggman);460461EntityScrewMobile *screwMobile = DiveEggman->screwMobile;462463if (DiveEggman_CheckNoBombExplode()) {464self->position.x = (RSDK.Cos256(self->angle) << 12) + screwMobile->position.x;465self->position.y -= 0x10000;466467if ((self->angle & 0xFF) < 0x80)468self->drawGroup = Zone->playerDrawGroup[0] + 2;469else470self->drawGroup = Zone->hudDrawGroup - 1;471self->angle += 4;472473if (screwMobile->propellerAnimator.speed >= 0x100) {474if (self->position.y < screwMobile->position.y + 0x180000) {475self->timer = 1;476--screwMobile->health; // ??? what the...477screwMobile->invincibilityTimer = 30;478screwMobile->whirlPoolTimer = 30;479EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);480481// Hit that player!482if (!player1->blinkTimer && !player1->invincibleTimer) {483if (player1->shield) {484EntityShield *shield = RSDK_GET_ENTITY(Player->playerCount + RSDK.GetEntitySlot(player1), Shield);485if (shield->classID == Shield->classID)486destroyEntity(shield);487488player1->shield = SHIELD_NONE;489player1->blinkTimer = 120;490RSDK.PlaySfx(Player->sfxHurt, false, 255);491}492else {493if (player1->rings <= 0) {494player1->deathType = PLAYER_DEATH_DIE_USESFX;495RSDK.PlaySfx(Player->sfxHurt, false, 255);496ScrewMobile->fanSfxTimer = 0;497}498else {499player1->blinkTimer = 120;500if (!player1->hyperRing)501Ring_LoseRings(player1, player1->rings, player1->collisionPlane);502else503Ring_LoseHyperRings(player1, player1->rings, player1->collisionPlane);504505player1->hyperRing = false;506player1->rings = 0;507player1->ringExtraLife = 100;508RSDK.PlaySfx(Player->sfxLoseRings, false, 255);509}510}511DiveEggman_CheckNoBombExplode();512}513}514}515else {516if (self->position.y < Water->waterLevel - (screwMobile->whirlpoolHeight << 16)) {517self->velocity.y = -0x10000;518self->state = DiveEggman_StateBomb_Falling;519self->velocity.x = (RSDK.Cos256(self->angle) << 8);520}521}522}523}524525void DiveEggman_StateBomb_Falling(void)526{527RSDK_THIS(DiveEggman);528529if (DiveEggman_CheckNoBombExplode()) {530self->position.x += self->velocity.x;531self->position.y += self->velocity.y;532self->velocity.y += 0x2000;533534if (self->position.y >= Water->waterLevel) {535self->velocity.y >>= 2;536537CREATE_ENTITY(Water, INT_TO_VOID(WATER_SPLASH), self->position.x, Water->waterLevel);538RSDK.PlaySfx(Water->sfxSplash, false, 255);539540self->state = DiveEggman_StateBomb_Idle;541}542}543}544545#if GAME_INCLUDE_EDITOR546void DiveEggman_EditorDraw(void)547{548RSDK_THIS(DiveEggman);549550RSDK.SetSpriteAnimation(DiveEggman->diveFrames, 0, &self->animator, true, 0);551552DiveEggman_Draw();553554if (showGizmos()) {555RSDK_DRAWING_OVERLAY(true);556557EntityCollapsingPlatform *screwMobile = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, CollapsingPlatform);558if (ScrewMobile && screwMobile->classID == ScrewMobile->classID)559DrawHelpers_DrawArrow(self->position.x, self->position.y, screwMobile->position.x, screwMobile->position.y, 0xFFFF00, INK_NONE, 0xFF);560561RSDK_DRAWING_OVERLAY(false);562}563}564565void DiveEggman_EditorLoad(void) { DiveEggman->diveFrames = RSDK.LoadSpriteAnimation("HCZ/DiveEggman.bin", SCOPE_STAGE); }566#endif567568void DiveEggman_Serialize(void) {}569570571