Path: blob/master/SonicMania/Objects/MMZ/MatryoshkaBom.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: MatryoshkaBom Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectMatryoshkaBom *MatryoshkaBom;1011void MatryoshkaBom_Update(void)12{13RSDK_THIS(MatryoshkaBom);1415StateMachine_Run(self->state);16}1718void MatryoshkaBom_LateUpdate(void) {}1920void MatryoshkaBom_StaticUpdate(void) {}2122void MatryoshkaBom_Draw(void)23{24RSDK_THIS(MatryoshkaBom);2526if (self->state == MatryoshkaBom_State_FuseLit) {27Vector2 drawPos;28drawPos.x = self->position.x;29drawPos.y = self->position.y + self->fusePos;30RSDK.DrawSprite(&self->fuseAnimator, &drawPos, false);31}3233RSDK.DrawSprite(&self->bodyAnimator, NULL, false);34RSDK.DrawSprite(&self->legsAnimator, NULL, false);35}3637void MatryoshkaBom_Create(void *data)38{39RSDK_THIS(MatryoshkaBom);4041self->visible = true;4243if (self->planeFilter > 0 && ((uint8)(self->planeFilter - 1) & 2))44self->drawGroup = Zone->objectDrawGroup[1] + 2;45else46self->drawGroup = Zone->objectDrawGroup[0] + 2;4748self->updateRange.x = 0x800000;49self->updateRange.y = 0x800000;5051int32 size = VOID_TO_INT(data);52if (size < MATRYOSHKA_SIZE_SHRAPNEL) {53self->active = ACTIVE_BOUNDS;54if (size)55self->size = size;5657self->startDir = self->direction;58self->startPos = self->position;5960self->velocity.x = size ? 0xC000 : -0xC000;61self->drawFX |= FX_FLIP;62self->timer = 0x600;6364switch (self->size) {65default: break;66case MATRYOSHKA_SIZE_BIG:67RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 0, &self->bodyAnimator, true, 0);68RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 13, &self->fuseAnimator, true, 0);69RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 2, &self->legsAnimator, true, 0);7071self->offsetX = 0x140000;72self->offsetY = 0x1B0000;73self->canExplode = true;74break;7576case MATRYOSHKA_SIZE_MED:77RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 4, &self->bodyAnimator, true, 0);78RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 14, &self->fuseAnimator, true, 0);79RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 6, &self->legsAnimator, true, 0);8081self->offsetX = 0xD0000;82self->offsetY = 0x140000;83self->canExplode = true;84break;8586case MATRYOSHKA_SIZE_SMALL:87RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 9, &self->bodyAnimator, true, 0);88RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 15, &self->fuseAnimator, true, 0);89RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 10, &self->legsAnimator, true, 0);9091self->offsetX = 0x90000;92self->offsetY = 0xE0000;93self->canExplode = false;94break;95}9697self->state = MatryoshkaBom_State_Init;98}99else {100self->active = ACTIVE_NORMAL;101RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 16, &self->bodyAnimator, true, 0);102self->state = MatryoshkaBom_State_Shrapnel;103}104}105106void MatryoshkaBom_StageLoad(void)107{108if (RSDK.CheckSceneFolder("MMZ"))109MatryoshkaBom->aniFrames = RSDK.LoadSpriteAnimation("MMZ/MatryoshkaBom.bin", SCOPE_STAGE);110111MatryoshkaBom->hitboxHurt.left = -12;112MatryoshkaBom->hitboxHurt.top = -18;113MatryoshkaBom->hitboxHurt.right = 12;114MatryoshkaBom->hitboxHurt.bottom = 18;115116MatryoshkaBom->hitboxExplode.left = -96;117MatryoshkaBom->hitboxExplode.top = -96;118MatryoshkaBom->hitboxExplode.right = 96;119MatryoshkaBom->hitboxExplode.bottom = 96;120121MatryoshkaBom->hitboxShrapnel.left = -6;122MatryoshkaBom->hitboxShrapnel.top = -6;123MatryoshkaBom->hitboxShrapnel.right = 6;124MatryoshkaBom->hitboxShrapnel.bottom = 6;125126DEBUGMODE_ADD_OBJ(MatryoshkaBom);127128MatryoshkaBom->sfxExplosion = RSDK.GetSfx("Stage/Explosion.wav");129MatryoshkaBom->sfxButton = RSDK.GetSfx("Stage/Button2.wav");130MatryoshkaBom->sfxPon = RSDK.GetSfx("Stage/Pon.wav");131}132133void MatryoshkaBom_DebugSpawn(void)134{135RSDK_THIS(DebugMode);136137CREATE_ENTITY(MatryoshkaBom, NULL, self->position.x, self->position.y);138}139140void MatryoshkaBom_DebugDraw(void)141{142RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 0, &DebugMode->animator, true, 0);143RSDK.DrawSprite(&DebugMode->animator, NULL, false);144}145146void MatryoshkaBom_CheckPlayerCollisions(void)147{148RSDK_THIS(MatryoshkaBom);149150foreach_active(Player, player)151{152if (self->planeFilter <= 0 || player->collisionPlane == ((uint8)(self->planeFilter - 1) & 1)) {153if (self->state != MatryoshkaBom_State_Hatched) {154if (self->canExplode) {155if (self->state != MatryoshkaBom_State_ReleaseSmallerBuddy) {156if (Player_CheckCollisionTouch(player, self, &MatryoshkaBom->hitboxExplode)) {157RSDK.PlaySfx(MatryoshkaBom->sfxButton, false, 255);158159switch (self->size) {160default: break;161case MATRYOSHKA_SIZE_BIG: RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 1, &self->bodyAnimator, true, 0); break;162case MATRYOSHKA_SIZE_MED: RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 5, &self->bodyAnimator, true, 0); break;163case MATRYOSHKA_SIZE_SMALL: RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 9, &self->bodyAnimator, true, 0); break;164}165166self->timer = 21;167self->state = MatryoshkaBom_State_ReleaseSmallerBuddy;168}169}170}171else if (self->state != MatryoshkaBom_State_FuseLit) {172if (Player_CheckCollisionTouch(player, self, &MatryoshkaBom->hitboxExplode)) {173self->timer = 144;174self->state = MatryoshkaBom_State_FuseLit;175}176}177}178179if (Player_CheckCollisionTouch(player, self, &MatryoshkaBom->hitboxHurt)) {180#if MANIA_USE_PLUS181if (!Player_CheckMightyUnspin(player, 0x300, 2, &player->uncurlTimer))182#endif183Player_Hurt(player, self);184}185}186}187}188189void MatryoshkaBom_CheckOffScreen(void)190{191RSDK_THIS(MatryoshkaBom);192193if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {194if (self->destroyOffscreen) {195destroyEntity(self);196}197else {198self->position = self->startPos;199self->direction = self->startDir;200MatryoshkaBom_Create(NULL);201}202}203}204205void MatryoshkaBom_State_Init(void)206{207RSDK_THIS(MatryoshkaBom);208209self->active = ACTIVE_NORMAL;210211self->state = MatryoshkaBom_State_Walk;212MatryoshkaBom_State_Walk();213}214215void MatryoshkaBom_State_Walk(void)216{217RSDK_THIS(MatryoshkaBom);218219self->position.x += self->velocity.x;220221if (!--self->timer) {222self->timer = 60;223self->state = MatryoshkaBom_State_Stopped;224}225else {226bool32 shouldTurn = false;227if (self->velocity.x <= 0)228shouldTurn = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -self->offsetX, 0, true);229else230shouldTurn = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, self->offsetX, 0, true);231232if (!shouldTurn) {233if (self->direction & FLIP_Y)234shouldTurn = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_ROOF, 0, 0, -self->offsetY, 8) == false;235else236shouldTurn = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, self->offsetY, 8) == false;237}238239if (shouldTurn) {240self->timer = 60;241self->state = MatryoshkaBom_State_Stopped;242243switch (self->size) {244default: break;245case MATRYOSHKA_SIZE_BIG: RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 0, &self->bodyAnimator, true, 0); break;246case MATRYOSHKA_SIZE_MED: RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 4, &self->bodyAnimator, true, 0); break;247case MATRYOSHKA_SIZE_SMALL: RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 9, &self->bodyAnimator, true, 0); break;248}249}250}251252RSDK.ProcessAnimation(&self->bodyAnimator);253RSDK.ProcessAnimation(&self->legsAnimator);254255MatryoshkaBom_CheckPlayerCollisions();256MatryoshkaBom_CheckOffScreen();257}258259void MatryoshkaBom_State_Stopped(void)260{261RSDK_THIS(MatryoshkaBom);262263if (!--self->timer) {264switch (self->size) {265default: break;266case MATRYOSHKA_SIZE_BIG: RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 3, &self->bodyAnimator, true, 0); break;267case MATRYOSHKA_SIZE_MED: RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 7, &self->bodyAnimator, true, 0); break;268case MATRYOSHKA_SIZE_SMALL: RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 11, &self->bodyAnimator, true, 0); break;269}270271RSDK.SetSpriteAnimation(-1, 0, &self->legsAnimator, true, 0);272self->state = MatryoshkaBom_State_Turn;273}274275RSDK.ProcessAnimation(&self->bodyAnimator);276277MatryoshkaBom_CheckPlayerCollisions();278MatryoshkaBom_CheckOffScreen();279}280281void MatryoshkaBom_State_Turn(void)282{283RSDK_THIS(MatryoshkaBom);284285RSDK.ProcessAnimation(&self->bodyAnimator);286287if (self->bodyAnimator.frameID == self->bodyAnimator.frameCount - 1) {288self->direction ^= FLIP_X;289self->velocity.x = -self->velocity.x;290self->timer = 0x600;291self->state = MatryoshkaBom_State_Walk;292293switch (self->size) {294default: break;295case MATRYOSHKA_SIZE_BIG:296RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 0, &self->bodyAnimator, true, 0);297RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 2, &self->legsAnimator, true, 0);298break;299300case MATRYOSHKA_SIZE_MED:301RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 4, &self->bodyAnimator, true, 0);302RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 6, &self->legsAnimator, true, 0);303break;304305case MATRYOSHKA_SIZE_SMALL:306RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 9, &self->bodyAnimator, true, 0);307RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 10, &self->legsAnimator, true, 0);308break;309}310}311312MatryoshkaBom_CheckPlayerCollisions();313MatryoshkaBom_CheckOffScreen();314}315316void MatryoshkaBom_State_FuseLit(void)317{318RSDK_THIS(MatryoshkaBom);319320self->fusePos += (self->direction & FLIP_Y) ? -0x1000 : 0x1000;321322if (--self->timer > 0) {323RSDK.ProcessAnimation(&self->bodyAnimator);324RSDK.ProcessAnimation(&self->fuseAnimator);325326MatryoshkaBom_CheckPlayerCollisions();327MatryoshkaBom_CheckOffScreen();328}329else {330RSDK.PlaySfx(MatryoshkaBom->sfxExplosion, false, 255);331332EntityMatryoshkaBom *shrapnel = CREATE_ENTITY(MatryoshkaBom, INT_TO_VOID(MATRYOSHKA_SIZE_SHRAPNEL), self->position.x, self->position.y);333shrapnel->velocity.x = -0x20000;334shrapnel->velocity.y = -0x30000;335shrapnel->planeFilter = self->planeFilter;336shrapnel->drawGroup = self->drawGroup;337338shrapnel = CREATE_ENTITY(MatryoshkaBom, INT_TO_VOID(MATRYOSHKA_SIZE_SHRAPNEL), self->position.x, self->position.y);339shrapnel->velocity.x = -0x10000;340shrapnel->velocity.y = -0x20000;341shrapnel->planeFilter = self->planeFilter;342shrapnel->drawGroup = self->drawGroup;343344shrapnel = CREATE_ENTITY(MatryoshkaBom, INT_TO_VOID(MATRYOSHKA_SIZE_SHRAPNEL), self->position.x, self->position.y);345shrapnel->velocity.x = 0x20000;346shrapnel->velocity.y = -0x30000;347shrapnel->planeFilter = self->planeFilter;348shrapnel->drawGroup = self->drawGroup;349350shrapnel = CREATE_ENTITY(MatryoshkaBom, INT_TO_VOID(MATRYOSHKA_SIZE_SHRAPNEL), self->position.x, self->position.y);351shrapnel->velocity.x = 0x10000;352shrapnel->velocity.y = -0x20000;353shrapnel->planeFilter = self->planeFilter;354shrapnel->drawGroup = self->drawGroup;355356EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), self->position.x, self->position.y);357explosion->drawGroup = self->drawGroup + 1;358explosion->planeFilter = self->planeFilter;359360destroyEntity(self);361}362}363364void MatryoshkaBom_State_ReleaseSmallerBuddy(void)365{366RSDK_THIS(MatryoshkaBom);367368RSDK.ProcessAnimation(&self->bodyAnimator);369370if (!--self->timer) {371RSDK.PlaySfx(MatryoshkaBom->sfxPon, false, 255);372373EntityMatryoshkaBom *child = CREATE_ENTITY(MatryoshkaBom, INT_TO_VOID(self->size + 1), self->position.x, self->position.y);374375child->velocity.x = self->direction == FLIP_NONE ? -0x18000 : 0x18000;376child->velocity.y = -0x40000;377378child->planeFilter = self->planeFilter;379child->drawGroup = self->drawGroup - 1;380child->active = ACTIVE_NORMAL;381child->direction = self->direction;382child->destroyOffscreen = true;383child->state = MatryoshkaBom_State_Hatched;384self->canExplode = false;385}386387if (self->bodyAnimator.frameID >= self->bodyAnimator.frameDuration - 1)388self->state = MatryoshkaBom_State_Walk;389390MatryoshkaBom_CheckPlayerCollisions();391MatryoshkaBom_CheckOffScreen();392}393394void MatryoshkaBom_State_Hatched(void)395{396RSDK_THIS(MatryoshkaBom);397398self->position.x += self->velocity.x;399self->position.y += self->velocity.y;400self->velocity.y += 0x3800;401402if (self->velocity.x) {403bool32 collided = false;404if (self->velocity.x <= 0)405collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -self->offsetX, 0, true);406else407collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, self->offsetX, 0, true);408409if (collided)410self->velocity.x = 0;411}412413bool32 collided = false;414if (self->direction & FLIP_Y)415collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_ROOF, 0, 0, -self->offsetY, true);416else417collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, self->offsetY, true);418419if (collided) {420self->timer = 0x600;421self->velocity.x = self->direction == FLIP_NONE ? -0xC000 : 0xC000;422self->state = MatryoshkaBom_State_Walk;423}424425RSDK.ProcessAnimation(&self->bodyAnimator);426427MatryoshkaBom_CheckPlayerCollisions();428MatryoshkaBom_CheckOffScreen();429}430431void MatryoshkaBom_State_Shrapnel(void)432{433RSDK_THIS(MatryoshkaBom);434435self->position.x += self->velocity.x;436self->position.y += self->velocity.y;437self->velocity.y += 0x1800;438439if (RSDK.CheckOnScreen(self, &self->updateRange)) {440RSDK.ProcessAnimation(&self->bodyAnimator);441442foreach_active(Player, player)443{444if (self->planeFilter <= 0 || player->collisionPlane == ((uint8)(self->planeFilter - 1) & 1)) {445if (Player_CheckCollisionTouch(player, self, &MatryoshkaBom->hitboxShrapnel)) {446Player_Hurt(player, self);447}448}449}450}451else {452destroyEntity(self);453}454}455456#if GAME_INCLUDE_EDITOR457void MatryoshkaBom_EditorDraw(void)458{459RSDK_THIS(MatryoshkaBom);460461self->drawFX |= FX_FLIP;462463switch (self->size) {464default: break;465case MATRYOSHKA_SIZE_BIG:466RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 0, &self->bodyAnimator, false, 0);467RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 13, &self->fuseAnimator, false, 0);468RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 2, &self->legsAnimator, false, 0);469break;470471case MATRYOSHKA_SIZE_MED:472RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 4, &self->bodyAnimator, false, 0);473RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 14, &self->fuseAnimator, false, 0);474RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 6, &self->legsAnimator, false, 0);475break;476477case MATRYOSHKA_SIZE_SMALL:478RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 9, &self->bodyAnimator, false, 0);479RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 15, &self->fuseAnimator, false, 0);480RSDK.SetSpriteAnimation(MatryoshkaBom->aniFrames, 10, &self->legsAnimator, false, 0);481break;482}483484MatryoshkaBom_Draw();485}486487void MatryoshkaBom_EditorLoad(void)488{489MatryoshkaBom->aniFrames = RSDK.LoadSpriteAnimation("MMZ/MatryoshkaBom.bin", SCOPE_STAGE);490491RSDK_ACTIVE_VAR(MatryoshkaBom, direction);492RSDK_ENUM_VAR("Left (Rightside Up)", FLIP_NONE);493RSDK_ENUM_VAR("Right (Rightside Up)", FLIP_X);494RSDK_ENUM_VAR("Left (Upside down)", FLIP_Y);495RSDK_ENUM_VAR("Right (Upside down)", FLIP_XY);496497RSDK_ACTIVE_VAR(MatryoshkaBom, planeFilter);498RSDK_ENUM_VAR("None", PLANEFILTER_NONE);499RSDK_ENUM_VAR("AL", PLANEFILTER_AL);500RSDK_ENUM_VAR("BL", PLANEFILTER_BL);501RSDK_ENUM_VAR("AH", PLANEFILTER_AH);502RSDK_ENUM_VAR("BH", PLANEFILTER_BH);503504RSDK_ACTIVE_VAR(MatryoshkaBom, size);505RSDK_ENUM_VAR("Big", MATRYOSHKA_SIZE_BIG);506RSDK_ENUM_VAR("Medium", MATRYOSHKA_SIZE_MED);507RSDK_ENUM_VAR("Small", MATRYOSHKA_SIZE_SMALL);508}509#endif510511void MatryoshkaBom_Serialize(void)512{513RSDK_EDITABLE_VAR(MatryoshkaBom, VAR_UINT8, direction);514RSDK_EDITABLE_VAR(MatryoshkaBom, VAR_ENUM, planeFilter);515RSDK_EDITABLE_VAR(MatryoshkaBom, VAR_ENUM, size);516}517518519