Path: blob/master/SonicMania/Objects/OOZ/Hatch.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Hatch Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectHatch *Hatch;1011void Hatch_Update(void)12{13RSDK_THIS(Hatch);1415int32 storeX = self->position.x;16int32 storeY = self->position.y;1718self->position.x = self->startPos.x;19self->position.y = self->startPos.y;2021if (self->useMoveLayer) {22foreach_all(Player, player)23{24if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {25TileLayer *moveLayer = RSDK.GetTileLayer(Zone->moveLayer);26if (!player->sidekick) {27moveLayer->scrollPos = -self->vScrollPos;28moveLayer->scrollInfo[0].scrollPos = -self->hScrollPos;29}3031player->collisionLayers |= Zone->moveLayerMask;32player->moveLayerPosition.x = moveLayer->scrollInfo[0].scrollPos;33player->moveLayerPosition.y = moveLayer->scrollPos;34}35}36}3738self->position.x = storeX;39self->position.y = storeY;4041StateMachine_Run(self->state);42}4344void Hatch_LateUpdate(void) {}4546void Hatch_StaticUpdate(void)47{48foreach_all(Hatch, hatch) { RSDK.AddDrawListRef(Zone->objectDrawGroup[1], RSDK.GetEntitySlot(hatch)); }49}5051void Hatch_Draw(void)52{53RSDK_THIS(Hatch);5455if (SceneInfo->currentDrawGroup == self->drawGroup) {56RSDK.DrawSprite(&self->hatchAnimator, NULL, false);57}58else {59if (self->hatchAnimator.animationID == 2 && self->hatchAnimator.frameID >= 3)60RSDK.DrawSprite(&self->hatchAnimator, NULL, false);6162RSDK.DrawSprite(&self->baseAnimator, NULL, false);63}64}6566void Hatch_Create(void *data)67{68RSDK_THIS(Hatch);6970self->drawFX = FX_FLIP;71if (!SceneInfo->inEditor) {72self->active = ACTIVE_BOUNDS;73self->drawGroup = Zone->objectDrawGroup[0] + 1;7475self->updateRange.x = 16 * MAX(abs(self->subOff1.x), abs(self->subOff2.x));76self->updateRange.y = 16 * MAX(abs(self->subOff1.y), abs(self->subOff2.y));7778RSDK.SetSpriteAnimation(Hatch->aniFrames, 0, &self->baseAnimator, true, 0);79RSDK.SetSpriteAnimation(Hatch->aniFrames, 2, &self->hatchAnimator, true, 4);8081self->hitbox.left = (self->subOff1.x >> 12) - ((self->position.x >> 16) & 0xF) + 16;82self->hitbox.top = (self->subOff1.y >> 12) - ((self->position.y >> 16) & 0xF) + 16;83self->hitbox.right = (self->subOff2.x >> 12) - ((self->position.x >> 16) & 0xF) + 16;84self->hitbox.bottom = (self->subOff2.y >> 12) - ((self->position.y >> 16) & 0xF) + 16;85self->startPos = self->position;8687EntityWarpDoor *warpDoor = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor);88if (warpDoor->classID == WarpDoor->classID) {89self->hitboxWarpDoor = warpDoor->hitbox;90warpDoor->hitbox.left = 0;91warpDoor->hitbox.top = 0x7FFF;92warpDoor->hitbox.right = 0;93warpDoor->hitbox.bottom = 0x7FFF;94}9596switch (self->go) {97case HATCH_GO_SUBENTRYHATCH_SMOGONLY:98if (!OOZSetup->useSmogEffect) {99self->vScrollPos += self->depth << 16;100self->position.y += self->depth << 16;101destroyEntity(RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor));102self->useMoveLayer = true;103break;104}105// [[fallthrough]]106case HATCH_GO_SUBENTRYHATCH:107self->visible = true;108self->state = Hatch_State_SubEntryHatch;109self->useMoveLayer = true;110break;111112case HATCH_GO_SUBEXITHATCH_COPYTILES:113// Copies the Hatch Tiles from the move layer114RSDK.CopyTileLayer(Zone->moveLayer, (self->position.x >> 20) - 2, (self->position.y >> 20) - 1, Zone->moveLayer, 1, 7, 4,1152); // Copy Hatch Tiles116RSDK.CopyTileLayer(Zone->fgLayer[1], (self->position.x >> 20) - 3, (self->position.y >> 20) + 1, Zone->moveLayer, 16, 1, 6,1172); // Copy [???] Tiles (There's nothing there in the scene)118// [[fallthrough]]119case HATCH_GO_SUBEXITHATCH_NOCOPY:120self->visible = false;121self->useMoveLayer = false;122self->state = Hatch_State_SubExitHatch;123break;124125case HATCH_GO_SUBEXIT:126self->visible = false;127self->state = Hatch_State_SubExit;128self->useMoveLayer = true;129break;130131default: break;132}133}134}135136void Hatch_StageLoad(void)137{138// OOZ1 Check...? why? its never used in OOZ1...139if (RSDK.CheckSceneFolder("OOZ1") || RSDK.CheckSceneFolder("OOZ2"))140Hatch->aniFrames = RSDK.LoadSpriteAnimation("OOZ/Hatch.bin", SCOPE_STAGE);141142Hatch->hitboxSubExit.left = -16;143Hatch->hitboxSubExit.top = -16;144Hatch->hitboxSubExit.right = 16;145Hatch->hitboxSubExit.bottom = 16;146147Hatch->hitboxRange.left = -128;148Hatch->hitboxRange.top = -128;149Hatch->hitboxRange.right = 128;150Hatch->hitboxRange.bottom = 128;151152Hatch->hitboxL.left = -24;153Hatch->hitboxL.top = 0;154Hatch->hitboxL.right = -12;155Hatch->hitboxL.bottom = 8;156157Hatch->hitboxR.left = 12;158Hatch->hitboxR.top = 0;159Hatch->hitboxR.right = 24;160Hatch->hitboxR.bottom = 8;161162Hatch->hitboxEntry.left = -12;163Hatch->hitboxEntry.top = 8;164Hatch->hitboxEntry.right = 12;165Hatch->hitboxEntry.bottom = 24;166167Hatch->active = ACTIVE_ALWAYS;168169Hatch->sfxHatchOpen = RSDK.GetSfx("OOZ/SubHatchOpen.wav");170Hatch->sfxHatchClose = RSDK.GetSfx("OOZ/SubHatchClose.wav");171Hatch->sfxDescend = RSDK.GetSfx("OOZ/SubDescend.wav");172Hatch->sfxSurface = RSDK.GetSfx("OOZ/SubSurface.wav");173Hatch->sfxGasPop = RSDK.GetSfx("OOZ/GasPop.wav");174}175176void Hatch_State_SubEntryHatch(void)177{178RSDK_THIS(Hatch);179180RSDK.ProcessAnimation(&self->hatchAnimator);181182int32 entered = 0;183foreach_all(Player, player)184{185// Bug Details:186// this does foreach_all, instead of foreach_active187// meaning that even killed players are included188// Fix:189// this entire block of code should have a Player_CheckValidState call to make sure the player isn't dead or some other "invalid" state190191// Extra notes: if you manage to die and fall into the hatch, you'll be brought back (sorta, this is because it changes your state from192// Player_State_Death to Player_State_Static) though the death state stuff will still be applied so you'll be on the highest layer (until its193// changed) and the player->active var will be set to ACTIVE_ALWAYS this means you can do really weird stuff such as move during the pause194// menu195196if (Player_CheckCollisionBox(player, self, &Hatch->hitboxL) == C_TOP) {197entered = 1;198}199else if (Player_CheckCollisionBox(player, self, &Hatch->hitboxR) == C_TOP) {200entered = 1;201}202else if (Player_CheckCollisionBox(player, self, &Hatch->hitboxEntry) == C_TOP) {203if (player->onGround) {204if (!player->sidekick) {205self->active = ACTIVE_NORMAL;206self->playerPtr = player;207player->velocity.x = 0;208player->velocity.y = 0;209player->groundVel = 0;210player->nextAirState = StateMachine_None;211player->nextGroundState = StateMachine_None;212player->interaction = false;213214if (player->animator.animationID != ANI_JUMP)215RSDK.PlaySfx(Player->sfxRoll, false, 0xFF);216217RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);218player->state = Player_State_Static;219RSDK.SetSpriteAnimation(Hatch->aniFrames, 2, &self->hatchAnimator, false, 0);220self->state = Hatch_State_PlayerEntered;221entered = 2;222foreach_break;223}224}225else {226entered = 1;227}228}229else {230if (Player_CheckCollisionTouch(player, self, &Hatch->hitboxRange))231entered = 1;232}233}234235if (entered == 1) {236if (self->hatchAnimator.animationID == 2)237RSDK.PlaySfx(Hatch->sfxHatchOpen, false, 0xFF);238239RSDK.SetSpriteAnimation(Hatch->aniFrames, 1, &self->hatchAnimator, false, 0);240}241else if (!entered) {242if (self->hatchAnimator.animationID == 1)243RSDK.PlaySfx(Hatch->sfxHatchClose, false, 0xFF);244245RSDK.SetSpriteAnimation(Hatch->aniFrames, 2, &self->hatchAnimator, false, 0);246}247}248249void Hatch_State_PlayerEntered(void)250{251RSDK_THIS(Hatch);252253RSDK.ProcessAnimation(&self->hatchAnimator);254255if (self->hatchAnimator.frameID == 4) {256EntityPlayer *player = self->playerPtr;257258self->visible = false;259player->visible = false;260player->blinkTimer = 0;261player->tileCollisions = TILECOLLISION_NONE;262263RSDK.CopyTileLayer(Zone->moveLayer, (self->position.x >> 20) - 2, (self->position.y >> 20) - 1, Zone->moveLayer, 1, 7, 4, 2);264RSDK.CopyTileLayer(Zone->fgLayer[1], (self->position.x >> 20) - 3, (self->position.y >> 20) + 1, Zone->moveLayer, 16, 1, 6, 2);265266Zone->deathBoundary[0] = 0x7FFF0000;267Zone->deathBoundary[1] = 0x7FFF0000;268Zone->deathBoundary[2] = 0x7FFF0000;269Zone->deathBoundary[3] = 0x7FFF0000;270271RSDK.PlaySfx(Hatch->sfxDescend, false, 0xFF);272self->state = Hatch_State_Descend;273274EntityZone *zone = RSDK_GET_ENTITY(SLOT_ZONE, Zone);275zone->fadeColor = 0;276zone->timer = 0;277zone->drawGroup = 15;278zone->visible = true;279zone->stateDraw = Zone_Draw_Fade;280}281}282283void Hatch_State_Descend(void)284{285RSDK_THIS(Hatch);286287EntityPlayer *player = self->playerPtr;288EntityZone *zone = RSDK_GET_ENTITY(SLOT_ZONE, Zone);289290++self->timer;291self->vScrollPos += 0x10000;292self->position.y += 0x10000;293player->position.y += 0x10000;294295zone->timer += 2;296297if (self->timer >= self->depth) {298if (self->dest) { // XOffset of where to surface299self->timer = 0;300self->state = Hatch_State_MoveToDestPos;301}302else { // Uses the WarpDoor obj for transport303player->state = Player_State_Air;304EntityWarpDoor *warpDoor = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor);305if (warpDoor->classID == WarpDoor->classID) {306Zone->cameraBoundsB[RSDK.GetEntitySlot(player)] = 0x7FFF;307warpDoor->hitbox = self->hitboxWarpDoor;308warpDoor->position.y = self->position.y;309player->tileCollisions = TILECOLLISION_DOWN;310player->interaction = true;311player->visible = true;312}313314RSDK.GetTileLayer(Zone->moveLayer)->scrollPos = 0;315316self->position.x = self->startPos.x;317self->position.y = self->startPos.y;318319if (self->go != HATCH_GO_SUBENTRYHATCH_SMOGONLY)320self->useMoveLayer = false;321322self->state = Hatch_State_FadeIn;323}324}325}326327void Hatch_State_MoveToDestPos(void)328{329RSDK_THIS(Hatch);330331EntityPlayer *player = self->playerPtr;332333self->hScrollPos += self->dest << 16;334self->position.x += self->dest << 16;335336player->position.x += self->dest << 16;337player->camera->position.x += self->dest << 16;338339ScreenInfo[player->camera->screenID].position.x += self->dest;340341self->timer = 0;342RSDK.PlaySfx(Hatch->sfxSurface, false, 0xFF);343344self->state = Hatch_State_Surfacing;345}346347void Hatch_State_Surfacing(void)348{349RSDK_THIS(Hatch);350351EntityPlayer *player = self->playerPtr;352EntityZone *zone = RSDK_GET_ENTITY(SLOT_ZONE, Zone);353354++self->timer;355356self->vScrollPos -= 0x10000;357self->position.y -= 0x10000;358player->position.y -= 0x10000;359360zone->timer -= 2;361362if (self->timer >= self->depth) {363self->timer = 0;364self->visible = true;365self->position.x = player->position.x;366self->position.y = player->position.y + 0x80000;367368RSDK.SetSpriteAnimation(Hatch->aniFrames, 1, &self->hatchAnimator, false, 0);369self->state = Hatch_State_OpenHatchReleasePlayer;370}371}372373void Hatch_State_OpenHatchReleasePlayer(void)374{375RSDK_THIS(Hatch);376377EntityPlayer *player = self->playerPtr;378EntityZone *zone = RSDK_GET_ENTITY(SLOT_ZONE, Zone);379380RSDK.ProcessAnimation(&self->hatchAnimator);381zone->timer -= 2;382383if (++self->timer == 30) {384player->state = Player_State_Air;385player->velocity.y = -0xA0000;386player->onGround = false;387player->tileCollisions = TILECOLLISION_DOWN;388player->interaction = true;389player->applyJumpCap = false;390player->visible = true;391RSDK.PlaySfx(Hatch->sfxGasPop, false, 255);392}393else if (self->timer == 38) {394RSDK.SetSpriteAnimation(Hatch->aniFrames, 2, &self->hatchAnimator, false, 0);395self->state = Hatch_State_CloseHatch;396}397}398399void Hatch_State_CloseHatch(void)400{401RSDK_THIS(Hatch);402403EntityZone *zone = RSDK_GET_ENTITY(SLOT_ZONE, Zone);404zone->timer -= 2;405406RSDK.ProcessAnimation(&self->hatchAnimator);407408if (self->hatchAnimator.frameID >= self->hatchAnimator.frameCount - 1) {409self->visible = false;410self->state = Hatch_State_FadeIn;411}412}413414void Hatch_State_FadeIn(void)415{416RSDK_THIS(Hatch);417418EntityZone *zone = RSDK_GET_ENTITY(SLOT_ZONE, Zone);419420zone->timer -= 8;421if (zone->timer <= 0) {422self->active = ACTIVE_BOUNDS;423self->state = StateMachine_None;424zone->timer = 0;425}426}427428void Hatch_State_SubExit(void)429{430RSDK_THIS(Hatch);431432foreach_all(Player, player)433{434if (Player_CheckCollisionTouch(player, self, &Hatch->hitboxSubExit) && !player->sidekick) {435self->active = ACTIVE_NORMAL;436self->playerPtr = player;437self->stateStore = player->state;438self->interactionStore = player->interaction;439self->tileColStore = player->tileCollisions;440441player->velocity.x = 0;442player->groundVel = 0;443player->nextAirState = StateMachine_None;444player->nextGroundState = StateMachine_None;445player->interaction = false;446player->tileCollisions = TILECOLLISION_NONE;447player->state = Player_State_Static;448449self->state = Hatch_State_FadeOut;450foreach_break;451}452}453}454455void Hatch_State_FadeOut(void)456{457RSDK_THIS(Hatch);458459EntityZone *zone = RSDK_GET_ENTITY(SLOT_ZONE, Zone);460EntityPlayer *player = self->playerPtr;461462zone->timer += 8;463if (zone->timer >= 512) {464EntityWarpDoor *warpDoor = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor);465466if (warpDoor->classID == WarpDoor->classID) {467Zone->cameraBoundsB[RSDK.GetEntitySlot(player)] = 0x7FFF;468469warpDoor->hitbox = self->hitboxWarpDoor;470warpDoor->position.y = player->position.y;471472player->state = self->stateStore;473player->tileCollisions = self->tileColStore;474player->interaction = self->interactionStore;475player->visible = true;476}477478if (self->depth) {479self->state = Hatch_State_FadeIn;480}481else {482self->active = ACTIVE_BOUNDS;483self->state = StateMachine_None;484}485}486}487488void Hatch_State_SubExitHatch(void)489{490RSDK_THIS(Hatch);491492EntityZone *zone = RSDK_GET_ENTITY(SLOT_ZONE, Zone);493494if (zone->timer) {495foreach_all(Player, player)496{497if (Player_CheckCollisionTouch(player, self, &Hatch->hitboxSubExit) && !player->sidekick) {498self->hScrollPos += self->dest << 16;499self->vScrollPos += self->depth << 16;500self->useMoveLayer = true;501502if (self->go == HATCH_GO_SUBEXITHATCH_NOCOPY) {503self->state = StateMachine_None;504}505else {506self->playerPtr = player;507self->active = ACTIVE_NORMAL;508self->stateStore = player->state;509self->interactionStore = player->interaction;510self->tileColStore = player->tileCollisions;511self->position.x += self->dest << 16;512self->velocity.y = player->velocity.y;513514player->camera->position.x += self->dest << 16;515player->camera->position.y += self->depth << 16;516player->position.x += self->dest << 16;517player->position.y += self->depth << 16;518player->velocity.y = 0;519player->nextAirState = StateMachine_None;520player->nextGroundState = StateMachine_None;521player->interaction = false;522player->tileCollisions = TILECOLLISION_NONE;523player->visible = false;524player->state = Player_State_Static;525526RSDK.PlaySfx(Hatch->sfxSurface, false, 255);527self->state = Hatch_State_Surfacing;528}529foreach_break;530}531}532}533}534535#if GAME_INCLUDE_EDITOR536void Hatch_EditorDraw(void)537{538RSDK_THIS(Hatch);539540self->drawGroup = Zone->objectDrawGroup[0] + 1;541542self->updateRange.x = 16 * MAX(abs(self->subOff1.x), abs(self->subOff2.x));543self->updateRange.y = 16 * MAX(abs(self->subOff1.y), abs(self->subOff2.y));544545RSDK.SetSpriteAnimation(Hatch->aniFrames, 0, &self->baseAnimator, false, 0);546RSDK.SetSpriteAnimation(Hatch->aniFrames, 2, &self->hatchAnimator, false, 4);547548RSDK.DrawSprite(&self->hatchAnimator, NULL, false);549RSDK.DrawSprite(&self->baseAnimator, NULL, false);550551if (showGizmos()) {552RSDK_DRAWING_OVERLAY(true);553554DrawHelpers_DrawArrow(self->position.x, self->position.y, self->position.x, self->position.y + (self->depth << 16), 0x00FF00, INK_NONE, 0xFF);555556self->hitbox.left = (self->subOff1.x >> 12) - ((self->position.x >> 16) & 0xF) + 16;557self->hitbox.top = (self->subOff1.y >> 12) - ((self->position.y >> 16) & 0xF) + 16;558self->hitbox.right = (self->subOff2.x >> 12) - ((self->position.x >> 16) & 0xF) + 16;559self->hitbox.bottom = (self->subOff2.y >> 12) - ((self->position.y >> 16) & 0xF) + 16;560561DrawHelpers_DrawHitboxOutline(self->position.x, self->position.y, &self->hitbox, FLIP_NONE, 0xFF0000);562563RSDK_DRAWING_OVERLAY(false);564}565}566567void Hatch_EditorLoad(void)568{569Hatch->aniFrames = RSDK.LoadSpriteAnimation("OOZ/Hatch.bin", SCOPE_STAGE);570571RSDK_ACTIVE_VAR(Hatch, go);572RSDK_ENUM_VAR("Hatch Entry", HATCH_GO_SUBENTRYHATCH);573RSDK_ENUM_VAR("Hatch Exit (Copy hatch tiles)", HATCH_GO_SUBEXITHATCH_COPYTILES);574RSDK_ENUM_VAR("Hatch Entry (Only When Smog is active)", HATCH_GO_SUBENTRYHATCH_SMOGONLY);575RSDK_ENUM_VAR("Submarine Exit", HATCH_GO_SUBEXIT);576RSDK_ENUM_VAR("Hatch Exit (Don't copy hatch tiles)", HATCH_GO_SUBEXITHATCH_NOCOPY);577}578#endif579580void Hatch_Serialize(void)581{582RSDK_EDITABLE_VAR(Hatch, VAR_UINT8, go);583RSDK_EDITABLE_VAR(Hatch, VAR_VECTOR2, subOff1);584RSDK_EDITABLE_VAR(Hatch, VAR_VECTOR2, subOff2);585RSDK_EDITABLE_VAR(Hatch, VAR_ENUM, depth);586RSDK_EDITABLE_VAR(Hatch, VAR_ENUM, dest);587}588589590