Path: blob/master/SonicMania/Objects/SSZ/Hotaru.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Hotaru Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectHotaru *Hotaru;1011void Hotaru_Update(void)12{13RSDK_THIS(Hotaru);14StateMachine_Run(self->state);15}1617void Hotaru_LateUpdate(void) {}1819void Hotaru_StaticUpdate(void) {}2021void Hotaru_Draw(void)22{23RSDK_THIS(Hotaru);24Vector2 drawPos;2526self->direction = self->hotaruDir;27if (self->attackState == HOTARU_ATTACK_ATTACKING) {28self->inkEffect = INK_ADD;29self->alpha = 0x80;30drawPos.x = self->offset2.x + self->position.x;31drawPos.y = self->offset2.y + self->position.y + 0xC0000;3233drawPos.x += self->electricityOffset.x;34drawPos.y += self->electricityOffset.y;35RSDK.DrawSprite(&self->electricityAnimator, &drawPos, false);3637drawPos.x += self->electricityOffset.x;38drawPos.y += self->electricityOffset.y;39RSDK.DrawSprite(&self->electricityAnimator, &drawPos, false);4041drawPos.x += self->electricityOffset.x;42drawPos.y += self->electricityOffset.y;43RSDK.DrawSprite(&self->electricityAnimator, &drawPos, false);4445self->alpha = 0x100;46self->inkEffect = INK_NONE;47}4849if (!(self->destroyedHotarus & 1)) {50drawPos.x = self->position.x + self->offset1.x;51drawPos.y = self->position.y + self->offset1.y;5253if (self->alpha > 0 && (((Zone->timer & 1) << (self->state == Hotaru_State_FinishedAttacking)) & 0x7FFFFFFF)) {54self->inkEffect = INK_ADD;55RSDK.DrawSprite(&self->bulbAnimator, &drawPos, false);5657self->inkEffect = INK_NONE;58}5960RSDK.DrawSprite(&self->mainAnimator, &drawPos, false);61}6263if (!(self->destroyedHotarus & 2)) {64self->direction ^= FLIP_X;6566drawPos.x = self->position.x + self->offset2.x;67drawPos.y = self->position.y + self->offset2.y;6869if (self->alpha > 0 && (((Zone->timer & 1) << (self->state == Hotaru_State_FinishedAttacking)) & 0x7FFFFFFF)) {70self->inkEffect = INK_ADD;71RSDK.DrawSprite(&self->bulbAnimator, &drawPos, false);7273self->inkEffect = INK_NONE;74}7576RSDK.DrawSprite(&self->mainAnimator, &drawPos, false);77}78}7980void Hotaru_Create(void *data)81{82RSDK_THIS(Hotaru);8384if (!SceneInfo->inEditor) {85self->distX1 <<= 16;86self->distX2 <<= 16;87self->speed <<= 15;8889self->offset2.x = -self->dist.x;90self->offset2.y = -self->dist.y;91self->offset1 = self->dist;92self->visible = true;93self->drawGroup = Zone->objectDrawGroup[0];94self->active = ACTIVE_BOUNDS;95self->updateRange.x = MAX(self->distX1, self->distX2) + 0x400000;96self->updateRange.y = self->dist.y + 0x400000;9798self->drawFX = FX_ROTATE | FX_FLIP;99self->startPos.x = self->position.x;100self->startPos.y = self->position.y;101self->startDir = self->direction;102RSDK.SetSpriteAnimation(Hotaru->aniFrames, self->quality, &self->mainAnimator, true, 0);103RSDK.SetSpriteAnimation(Hotaru->aniFrames, 2, &self->bulbAnimator, true, 0);104RSDK.SetSpriteAnimation(Hotaru->aniFrames, 3, &self->electricityAnimator, true, 0);105106self->state = Hotaru_State_Init;107}108}109110void Hotaru_StageLoad(void)111{112if (RSDK.CheckSceneFolder("SSZ1"))113Hotaru->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Hotaru.bin", SCOPE_STAGE);114else if (RSDK.CheckSceneFolder("SSZ2"))115Hotaru->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/Hotaru.bin", SCOPE_STAGE);116117Hotaru->hitboxBadnik.top = -6;118Hotaru->hitboxBadnik.left = -6;119Hotaru->hitboxBadnik.right = 6;120Hotaru->hitboxBadnik.bottom = 6;121122Hotaru->hitboxTrigger.top = -32;123Hotaru->hitboxTrigger.left = -32;124Hotaru->hitboxTrigger.right = 32;125Hotaru->hitboxTrigger.bottom = 32;126127Hotaru->hitboxElectricity.top = -8;128Hotaru->hitboxElectricity.left = -8;129Hotaru->hitboxElectricity.right = 8;130Hotaru->hitboxElectricity.bottom = 8;131132DEBUGMODE_ADD_OBJ(Hotaru);133}134135void Hotaru_DebugSpawn(void)136{137RSDK_THIS(DebugMode);138139CREATE_ENTITY(Hotaru, NULL, self->position.x, self->position.y);140}141142void Hotaru_DebugDraw(void)143{144RSDK.SetSpriteAnimation(Hotaru->aniFrames, 0, &DebugMode->animator, true, 0);145RSDK.DrawSprite(&DebugMode->animator, NULL, false);146}147148void Hotaru_CheckPlayerCollisions(void)149{150RSDK_THIS(Hotaru);151152int32 storeX = self->position.x;153int32 storeY = self->position.y;154155foreach_active(Player, player)156{157if (!(self->destroyedHotarus & 1)) {158self->position.x += self->offset1.x;159self->position.y += self->offset1.y;160if (Player_CheckBadnikTouch(player, self, &Hotaru->hitboxBadnik) && Player_CheckBadnikBreak(player, self, false)) {161self->destroyedHotarus |= 1;162self->attackState = HOTARU_ATTACK_IDLE;163}164165self->position.x = storeX;166self->position.y = storeY;167}168169if (!(self->destroyedHotarus & 2)) {170self->position.x += self->offset2.x;171self->position.y += self->offset2.y;172if (Player_CheckBadnikTouch(player, self, &Hotaru->hitboxBadnik) && Player_CheckBadnikBreak(player, &self, false)) {173self->destroyedHotarus |= 2;174self->attackState = HOTARU_ATTACK_IDLE;175}176177self->position.x = storeX;178self->position.y = storeY;179}180}181}182183void Hotaru_CheckOffScreen(void)184{185RSDK_THIS(Hotaru);186187if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {188self->speed >>= 15;189self->position = self->startPos;190self->direction = self->startDir;191self->distX1 = self->distX1 >> 16;192self->distX2 = self->distX2 >> 16;193Hotaru_Create(NULL);194}195}196197void Hotaru_State_Init(void)198{199RSDK_THIS(Hotaru);200201self->active = ACTIVE_NORMAL;202self->hotaruDir = FLIP_NONE;203self->alpha = 0x00;204self->attackState = HOTARU_ATTACK_IDLE;205206self->state = Hotaru_State_CheckPlayerInRange;207Hotaru_State_CheckPlayerInRange();208}209210void Hotaru_State_CheckPlayerInRange(void)211{212RSDK_THIS(Hotaru);213214if (self->hotaruDir) {215self->offset2.x -= self->speed;216self->offset1.x += self->speed;217if (self->offset1.x >= self->distX2) {218self->offset2.x = -self->distX2;219self->offset1.x = self->distX2;220self->hotaruDir = FLIP_NONE;221}222}223else {224self->offset2.x += self->speed;225self->offset1.x -= self->speed;226if (self->offset2.x >= self->distX1) {227self->offset2.x = self->distX1;228self->offset1.x = -self->distX1;229self->hotaruDir = FLIP_X;230}231}232233Hotaru_CheckPlayerCollisions();234235int32 storeX = self->position.x;236int32 storeY = self->position.y;237foreach_active(Player, player)238{239bool32 inRange = false;240241if (!(self->destroyedHotarus & 1)) {242self->position.x += self->offset1.x;243self->position.y += self->offset1.y;244245if (Player_CheckCollisionTouch(player, self, &Hotaru->hitboxTrigger))246inRange = true;247}248249self->position.x = storeX;250self->position.y = storeY;251252if (!(self->destroyedHotarus & 2) && !inRange) {253self->position.x += self->offset2.x;254self->position.y += self->offset2.y;255256if (Player_CheckCollisionTouch(player, self, &Hotaru->hitboxTrigger))257inRange = true;258}259260if (inRange) {261self->playerPtr = player;262self->screenID = player->sidekick ? 0 : player->camera->screenID;263264self->position.x = storeX;265self->position.y = storeY;266self->state = Hotaru_State_FoundPlayer;267foreach_break;268}269270self->position.x = storeX;271self->position.y = storeY;272}273}274275void Hotaru_State_FoundPlayer(void)276{277RSDK_THIS(Hotaru);278279self->state = Hotaru_State_FlyOnScreen;280Hotaru_State_FlyOnScreen();281}282283void Hotaru_State_FlyOnScreen(void)284{285RSDK_THIS(Hotaru);286287EntityPlayer *player = self->playerPtr;288RSDKScreenInfo *screen = &ScreenInfo[self->screenID];289290int32 screenX = (screen->position.x + screen->center.x) << 16;291int32 screenY = (screen->position.y + screen->center.y) << 16;292293if (self->position.x <= screenX) {294self->position.x += player->velocity.x + 0x20000;295if (self->position.x > screenX)296self->position.x = screenX;297}298else {299self->position.x -= player->velocity.x - 0x20000;300if (self->position.x < screenX)301self->position.x = screenX;302}303304if (self->position.y <= screenY) {305self->position.y += player->velocity.y + 0x20000;306if (self->position.y > screenY)307self->position.y = screenY;308}309else {310self->position.y -= player->velocity.y - 0x20000;311if (self->position.y < screenY)312self->position.y = screenY;313}314315if (self->position.x == screenX && self->position.y == screenY) {316self->timer = 100;317self->state = Hotaru_State_AttachedToScreen;318}319320Hotaru_CheckPlayerCollisions();321Hotaru_CheckOffScreen();322}323324void Hotaru_State_AttachedToScreen(void)325{326RSDK_THIS(Hotaru);327328RSDKScreenInfo *screen = &ScreenInfo[self->screenID];329330self->position.x = (screen->position.x + screen->center.x) << 16;331self->position.y = (screen->position.y + screen->center.y) << 16;332333if (++self->rotation == 128) {334self->rotation = 0;335self->mainAnimator.frameID = 1;336self->state = Hotaru_State_Charging;337}338339Hotaru_CheckPlayerCollisions();340Hotaru_CheckOffScreen();341}342343void Hotaru_State_Charging(void)344{345RSDK_THIS(Hotaru);346347if (self->alpha >= 0x80) {348Hitbox hitboxCharge;349if (self->offset2.x >= self->offset1.x) {350hitboxCharge.left = self->offset1.x >> 16;351hitboxCharge.right = self->offset2.x >> 16;352}353else {354hitboxCharge.left = self->offset2.x >> 16;355hitboxCharge.right = self->offset1.x >> 16;356}357358if (self->offset2.y >= self->offset1.y) {359hitboxCharge.top = self->offset1.y >> 16;360hitboxCharge.bottom = self->offset2.y >> 16;361}362else {363hitboxCharge.top = self->offset2.y >> 16;364hitboxCharge.bottom = self->offset1.y >> 16;365}366367foreach_active(Player, player)368{369if (Player_CheckCollisionTouch(player, self, &hitboxCharge)) {370self->attackState = HOTARU_ATTACK_CHARGING;371}372}373}374375self->alpha += 2;376if (self->alpha == 0x100) {377self->timer = 128;378379if (!self->destroyedHotarus && !self->quality) {380++self->attackState;381382self->electricityOffset.x = (self->offset1.x - self->offset2.x) >> 2;383self->electricityOffset.y = (self->offset1.y - self->offset2.y) >> 2;384}385386self->state = Hotaru_State_Attacking;387}388389Hotaru_CheckPlayerCollisions();390Hotaru_CheckOffScreen();391}392393void Hotaru_State_Attacking(void)394{395RSDK_THIS(Hotaru);396397RSDK.ProcessAnimation(&self->electricityAnimator);398if (--self->timer <= 0) {399self->attackState = HOTARU_ATTACK_IDLE;400self->alpha = 0xC0;401self->state = Hotaru_State_FinishedAttacking;402}403404Hotaru_CheckPlayerCollisions();405406if (self->attackState == HOTARU_ATTACK_ATTACKING) {407int32 storeX = self->position.x;408int32 storeY = self->position.y;409410foreach_active(Player, player)411{412self->position.x += self->offset2.x;413self->position.y += self->offset2.y;414415for (int32 i = 0; i < 3; ++i) {416self->position.x += self->electricityOffset.x;417self->position.y += self->electricityOffset.y;418419if (Player_CheckCollisionTouch(player, self, &Hotaru->hitboxElectricity))420Player_ElementHurt(player, self, SHIELD_LIGHTNING);421}422423self->position.x = storeX;424self->position.y = storeY;425}426}427428Hotaru_CheckOffScreen();429}430431void Hotaru_State_FinishedAttacking(void)432{433RSDK_THIS(Hotaru);434435self->position.y -= 0x20000;436437Hotaru_CheckPlayerCollisions();438Hotaru_CheckOffScreen();439}440441#if GAME_INCLUDE_EDITOR442void Hotaru_EditorDraw(void)443{444RSDK_THIS(Hotaru);445446self->drawGroup = Zone->objectDrawGroup[0];447self->active = ACTIVE_BOUNDS;448self->updateRange.x = MAX(self->distX1 << 16, self->distX2 << 16) + 0x400000;449self->updateRange.y = self->dist.y + 0x400000;450451self->drawFX = FX_ROTATE | FX_FLIP;452self->offset2.x = -self->dist.x;453self->offset2.y = -self->dist.y;454self->offset1 = self->dist;455456RSDK.SetSpriteAnimation(Hotaru->aniFrames, self->quality, &self->mainAnimator, true, 0);457RSDK.SetSpriteAnimation(Hotaru->aniFrames, 2, &self->bulbAnimator, true, 0);458RSDK.SetSpriteAnimation(Hotaru->aniFrames, 3, &self->electricityAnimator, true, 0);459460Hotaru_Draw();461462if (showGizmos()) {463RSDK_DRAWING_OVERLAY(true);464465// Left Hotaru466self->offset1.x = -(self->distX1 << 16);467self->offset2.x = (self->distX1 << 16);468self->hotaruDir = FLIP_X;469self->inkEffect = INK_BLEND;470Hotaru_Draw();471472// Right Hotaru473self->offset1.x = (self->distX2 << 16);474self->offset2.x = -(self->distX2 << 16);475self->hotaruDir = FLIP_NONE;476self->inkEffect = INK_BLEND;477Hotaru_Draw();478479self->inkEffect = INK_NONE;480481if (self->distX1 && self->distX2) {482// Left Hotaru483DrawHelpers_DrawArrow(self->position.x - (self->distX1 << 16), self->position.y, self->position.x - (self->distX2 << 16),484self->position.y, 0x00FF00, INK_NONE, 0xFF);485DrawHelpers_DrawArrow(self->position.x - (self->distX2 << 16), self->position.y, self->position.x - (self->distX1 << 16),486self->position.y, 0x00FF00, INK_NONE, 0xFF);487488// Right Hotaru489DrawHelpers_DrawArrow(self->position.x + (self->distX1 << 16), self->position.y, self->position.x + (self->distX2 << 16),490self->position.y, 0x00FF00, INK_NONE, 0xFF);491DrawHelpers_DrawArrow(self->position.x + (self->distX2 << 16), self->position.y, self->position.x + (self->distX1 << 16),492self->position.y, 0x00FF00, INK_NONE, 0xFF);493}494495RSDK_DRAWING_OVERLAY(false);496}497}498499void Hotaru_EditorLoad(void)500{501if (RSDK.CheckSceneFolder("SSZ1"))502Hotaru->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Hotaru.bin", SCOPE_STAGE);503else if (RSDK.CheckSceneFolder("SSZ2"))504Hotaru->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/Hotaru.bin", SCOPE_STAGE);505506RSDK_ACTIVE_VAR(Hotaru, quality);507RSDK_ENUM_VAR("Good", HOTARU_GOOD);508RSDK_ENUM_VAR("Bad", HOTARU_BAD);509510RSDK_ACTIVE_VAR(Hotaru, preset);511RSDK_ENUM_VAR("(Unused)", 0);512}513#endif514515void Hotaru_Serialize(void)516{517RSDK_EDITABLE_VAR(Hotaru, VAR_UINT8, quality);518RSDK_EDITABLE_VAR(Hotaru, VAR_VECTOR2, dist);519RSDK_EDITABLE_VAR(Hotaru, VAR_ENUM, distX1);520RSDK_EDITABLE_VAR(Hotaru, VAR_ENUM, distX2);521RSDK_EDITABLE_VAR(Hotaru, VAR_ENUM, speed);522RSDK_EDITABLE_VAR(Hotaru, VAR_UINT8, preset);523}524525526