Path: blob/master/SonicMania/Objects/SSZ/HotaruHiWatt.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: HotaruHiWatt Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectHotaruHiWatt *HotaruHiWatt;1011void HotaruHiWatt_Update(void)12{13RSDK_THIS(HotaruHiWatt);1415if (self->invincibilityTimer > 0)16self->invincibilityTimer--;1718StateMachine_Run(self->state);19}2021void HotaruHiWatt_LateUpdate(void) {}2223void HotaruHiWatt_StaticUpdate(void) {}2425void HotaruHiWatt_Draw(void)26{27RSDK_THIS(HotaruHiWatt);2829if (self->stateDraw) {30StateMachine_Run(self->stateDraw);31}32else {33RSDK.DrawSprite(&self->mainAnimator, NULL, false);34}35}3637void HotaruHiWatt_Create(void *data)38{39RSDK_THIS(HotaruHiWatt);4041if (!SceneInfo->inEditor) {42if (globals->gameMode < MODE_TIMEATTACK) {43self->active = ACTIVE_XBOUNDS;44self->updateRange.x = 0xC00000;45self->updateRange.y = 0xC00000;46self->type = VOID_TO_INT(data);47self->drawGroup = Zone->objectDrawGroup[0];4849switch (self->type) {50case HHW_BOSS:51self->visible = false;52self->drawFX = FX_FLIP;53self->health = 6;54RSDK.SetSpriteAnimation(HotaruHiWatt->aniFrames, 0, &self->headAnimator, true, 0);55RSDK.SetSpriteAnimation(HotaruHiWatt->aniFrames, 1, &self->bulbAnimator, true, 0);5657self->alpha = 0x100;58self->state = HotaruHiWatt_StateBoss_SetupArena;59self->hitbox.left = -24;60self->hitbox.top = -24;61self->hitbox.right = 24;62self->hitbox.bottom = 24;63break;6465case HHW_SINGLE_HOTARU:66RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 1, &self->mainAnimator, true, 3);67++self->drawGroup;6869self->inkEffect = INK_ADD;70self->visible = true;71self->health = 3;72self->position.x += RSDK.Rand(-0x500000, 0x500000);73self->position.y += RSDK.Rand(-0x800000, 0x800000);74self->state = HotaruHiWatt_StateHotaru_DimScreen;75self->hitbox.left = -6;76self->hitbox.top = -6;77self->hitbox.right = 6;78self->hitbox.bottom = 6;79break;8081case HHW_PAIR_HOTARU:82RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 1, &self->mainAnimator, true, 3);8384self->originPos = self->position;85self->inkEffect = INK_ADD;86self->visible = true;87self->health = 3;88self->formationCircleRadius = 0x800;89self->alpha = -0x200;90self->state = HotaruHiWatt_StateHotaruPair_DimScreen;91self->hitbox.left = -6;92self->hitbox.top = -6;93self->hitbox.right = 6;94self->hitbox.bottom = 6;95break;9697case HHW_SMALL_HOTARU:98RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 1, &self->mainAnimator, true, 3);99100self->targetPos = self->position;101self->inkEffect = INK_ADD;102self->visible = true;103self->health = 3;104self->alpha = 0x100;105self->state = HotaruHiWatt_StateHotaru_MoveToTarget;106break;107108case HHW_FLASH:109RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 1, &self->mainAnimator, true, 0);110111self->inkEffect = INK_ADD;112self->visible = true;113self->health = 3;114self->alpha = 0x100;115self->state = HotaruHiWatt_StateBoss_FlashFadeOut;116break;117118case HHW_UNUSED2: break;119120case HHW_MINILASER:121RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 2, &self->mainAnimator, true, 1);122self->state = HotaruHiWatt_State_MiniLaser;123self->visible = true;124self->hitbox.left = -4;125self->hitbox.top = -8;126self->hitbox.right = 4;127self->hitbox.bottom = 8;128break;129130case HHW_ELECTRICORB:131RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 4, &self->mainAnimator, true, 0);132self->state = HotaruHiWatt_State_SparkyOrb;133self->visible = true;134self->hitbox.left = -8;135self->hitbox.top = -8;136self->hitbox.right = 8;137self->hitbox.bottom = 8;138break;139140default: break;141}142}143else {144destroyEntity(self);145}146}147}148149void HotaruHiWatt_StageLoad(void)150{151HotaruHiWatt->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/HotaruHiWatt.bin", SCOPE_STAGE);152HotaruHiWatt->hotaruFrames = RSDK.LoadSpriteAnimation("SSZ1/HotaruMKII.bin", SCOPE_STAGE);153154HotaruHiWatt->spawnedLaserStrike = false;155RSDK.CopyPalette(1, 128, 0, 128, 64);156157HotaruHiWatt->sfxHit = RSDK.GetSfx("Stage/BossHit.wav");158HotaruHiWatt->sfxExplosion = RSDK.GetSfx("Stage/Explosion2.wav");159HotaruHiWatt->sfxHHWAppear = RSDK.GetSfx("SSZ1/HHWAppear.wav");160HotaruHiWatt->sfxFlash = RSDK.GetSfx("SSZ1/HHWFlash.wav");161HotaruHiWatt->sfxLaser = RSDK.GetSfx("SSZ1/HotaruLaser.wav");162HotaruHiWatt->sfxAppear = RSDK.GetSfx("SSZ1/HotaruAppear.wav");163HotaruHiWatt->sfxFly = RSDK.GetSfx("SSZ1/HotaruFly.wav");164HotaruHiWatt->sfxFlyUp = RSDK.GetSfx("SSZ1/HHWFlyUp.wav");165HotaruHiWatt->sfxCharge = RSDK.GetSfx("SSZ1/HHWCharge.wav");166167Soundboard_LoadSfx("Stage/Zap.wav", true, HotaruHiWatt_SfxCheck_Zap, StateMachine_None);168Soundboard_LoadSfx("SSZ1/HHWLaser.wav", 32606, HotaruHiWatt_SfxCheck_HHWLaser, HotaruHiWatt_SfxUpdate_HHWLaser);169}170171bool32 HotaruHiWatt_SfxCheck_Zap(void)172{173int32 count = 0;174foreach_active(HotaruHiWatt, boss)175{176if (boss->state == HotaruHiWatt_StateHotaruPair_AttackDelay || boss->state == HotaruHiWatt_StateHotaruPair_AttackMovingDown177|| boss->state == HotaruHiWatt_StateHotaruPair_AttackMovingUp)178++count;179}180return count > 1;181}182183bool32 HotaruHiWatt_SfxCheck_HHWLaser(void)184{185int32 count = 0;186foreach_active(HotaruHiWatt, boss)187{188if (boss->state == HotaruHiWatt_StateBoss_LaserAttack_Right || boss->state == HotaruHiWatt_StateBoss_LaserAttack_Left)189++count;190}191return count > 0;192}193194void HotaruHiWatt_SfxUpdate_HHWLaser(int32 sfx)195{196if (!(Soundboard->sfxPlayingTimer[sfx] % 6))197Camera_ShakeScreen(0, 0, 2);198}199200void HotaruHiWatt_Hit(void)201{202RSDK_THIS(HotaruHiWatt);203204if (--self->health <= 0) {205self->stateDraw = HotaruHiWatt_Draw_Boss;206self->state = HotaruHiWatt_StateBoss_Destroyed;207self->timer = 0;208SceneInfo->timeEnabled = false;209Player_GiveScore(RSDK_GET_ENTITY(SLOT_PLAYER1, Player), 1000);210}211else {212self->invincibilityTimer = 48;213RSDK.PlaySfx(HotaruHiWatt->sfxHit, false, 255);214}215}216217void HotaruHiWatt_Explode(void)218{219RSDK_THIS(HotaruHiWatt);220221if (!(Zone->timer % 3)) {222RSDK.PlaySfx(HotaruHiWatt->sfxExplosion, false, 255);223224if (Zone->timer & 4) {225int32 x = self->position.x + (RSDK.Rand(self->hitbox.left, self->hitbox.right) << 16);226int32 y = self->position.y + (RSDK.Rand(self->hitbox.top, self->hitbox.bottom) << 16);227CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y)->drawGroup = Zone->objectDrawGroup[1];228}229}230}231232void HotaruHiWatt_CheckPlayerCollisions_Hotaru(void)233{234RSDK_THIS(HotaruHiWatt);235236foreach_active(Player, player)237{238if (Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBadnikBreak(player, self, false)) {239if (self->type == HHW_SINGLE_HOTARU) {240HotaruHiWatt_SpawnPairHotarus();241}242else {243int32 hotaruPairCount = 0;244foreach_active(HotaruHiWatt, boss)245{246if (boss->type == HHW_PAIR_HOTARU)247hotaruPairCount++;248}249250if (hotaruPairCount == 1)251HotaruHiWatt_SetupHHWReappear();252}253254destroyEntity(self);255}256}257}258259void HotaruHiWatt_CheckPlayerCollisions_Boss(void)260{261RSDK_THIS(HotaruHiWatt);262263foreach_active(Player, player)264{265if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self))266HotaruHiWatt_Hit();267}268}269270void HotaruHiWatt_CheckPlayerCollisions_MiniLaser(void)271{272RSDK_THIS(HotaruHiWatt);273274foreach_active(Player, player)275{276if (!self->invincibilityTimer) {277if (Player_CheckCollisionTouch(player, self, &self->hitbox))278Player_Hurt(player, self);279}280}281}282283void HotaruHiWatt_CheckPlayerCollisions_BossLaser(void)284{285RSDK_THIS(HotaruHiWatt);286287foreach_active(Player, player)288{289Hitbox hitbox = self->hitbox;290if (!player->invincibleTimer && !player->blinkTimer)291hitbox.bottom += 0x80;292293if (Player_CheckBadnikTouch(player, self, &hitbox)) {294if (self->invincibilityTimer) {295if (player->position.y > self->position.y)296Player_Hurt(player, self);297}298else if (player->position.y < self->position.y || player->invincibleTimer || player->blinkTimer) {299if (Player_CheckBossHit(player, self))300HotaruHiWatt_Hit();301}302else {303Player_Hurt(player, self);304}305}306}307}308309void HotaruHiWatt_Draw_Hotaru(void)310{311RSDK_THIS(HotaruHiWatt);312313self->inkEffect = INK_ADD;314315if (!(self->timer & 2))316RSDK.DrawSprite(&self->mainAnimator, NULL, false);317318int32 alpha = self->alpha;319self->alpha = self->bulbAlpha;320RSDK.DrawSprite(&self->bulbAnimator, NULL, false);321322self->alpha = alpha;323}324325void HotaruHiWatt_Draw_HotaruAttacking(void)326{327RSDK_THIS(HotaruHiWatt);328329self->inkEffect = INK_NONE;330RSDK.DrawSprite(&self->mainAnimator, NULL, false);331332self->inkEffect = INK_ADD;333RSDK.DrawSprite(&self->bulbAnimator, NULL, false);334}335336void HotaruHiWatt_Draw_Boss(void)337{338RSDK_THIS(HotaruHiWatt);339340if (RSDK.GetFrameID(&self->headAnimator) == 'b')341self->direction = FLIP_X;342343if (self->invincibilityTimer & 1) {344RSDK.CopyPalette(2, 240, 0, 240, 16);345346RSDK.DrawSprite(&self->headAnimator, NULL, false);347348self->direction = FLIP_NONE;349RSDK.DrawSprite(&self->bulbAnimator, NULL, false);350351RSDK.CopyPalette(1, 240, 0, 240, 16);352}353else {354RSDK.DrawSprite(&self->headAnimator, NULL, false);355356self->direction = FLIP_NONE;357RSDK.DrawSprite(&self->bulbAnimator, NULL, false);358}359}360361void HotaruHiWatt_Draw_BossLaserCharging(void)362{363RSDK_THIS(HotaruHiWatt);364365if (RSDK.GetFrameID(&self->headAnimator) == 'b')366self->direction = FLIP_X;367368if (self->invincibilityTimer & 1) {369RSDK.CopyPalette(2, 240, 0, 240, 16);370RSDK.DrawSprite(&self->headAnimator, NULL, false);371372self->direction = FLIP_NONE;373RSDK.DrawSprite(&self->bulbAnimator, NULL, false);374375RSDK.CopyPalette(1, 240, 0, 240, 16);376}377else {378RSDK.DrawSprite(&self->headAnimator, NULL, false);379380self->direction = FLIP_NONE;381RSDK.DrawSprite(&self->bulbAnimator, NULL, false);382}383384self->inkEffect = INK_ADD;385RSDK.DrawSprite(&self->mainAnimator, NULL, false);386387self->inkEffect = INK_ALPHA;388RSDK.DrawSprite(&self->bulbFlashAnimator, NULL, false);389390self->inkEffect = INK_NONE;391}392393void HotaruHiWatt_Draw_BossLaser(void)394{395RSDK_THIS(HotaruHiWatt);396397Vector2 drawPos;398if (RSDK.GetFrameID(&self->headAnimator) == 'b')399self->direction = FLIP_X;400401if (self->invincibilityTimer & 1) {402RSDK.CopyPalette(2, 240, 0, 240, 16);403RSDK.DrawSprite(&self->headAnimator, NULL, false);404405self->direction = FLIP_NONE;406RSDK.DrawSprite(&self->bulbAnimator, NULL, false);407408RSDK.CopyPalette(1, 240, 0, 240, 16);409}410else {411RSDK.DrawSprite(&self->headAnimator, NULL, false);412413self->direction = FLIP_NONE;414RSDK.DrawSprite(&self->bulbAnimator, NULL, false);415}416417self->inkEffect = INK_ALPHA;418self->bulbFlashAnimator.frameID = 0;419RSDK.DrawSprite(&self->bulbFlashAnimator, NULL, false);420421self->bulbFlashAnimator.frameID = 1;422RSDK.DrawSprite(&self->bulbFlashAnimator, NULL, false);423424drawPos = self->position;425drawPos.y += 0x180000 + ((Zone->timer & 7) << 20);426self->direction = (Zone->timer >> 2) & 1;427RSDK.DrawSprite(&self->mainAnimator, &drawPos, false);428429self->direction = FLIP_NONE;430RSDK.DrawSprite(&self->laserImpactAnimator, &self->laserImpactPos, false);431432self->inkEffect = INK_NONE;433}434435void HotaruHiWatt_Draw_FormingHHW(void)436{437RSDK_THIS(HotaruHiWatt);438439RSDK.DrawCircle(self->position.x, self->position.y, self->formationCircleRadius >> 16, 0xF0F0F0, 128, INK_ADD, false);440RSDK.DrawCircle(self->position.x, self->position.y, self->formationCircleRadius / 0xCCCC, 0xF0F0F0, 128, INK_ADD, false);441}442443void HotaruHiWatt_Draw_FlashAppear(void)444{445RSDK_THIS(HotaruHiWatt);446447if (RSDK.GetFrameID(&self->headAnimator) == 'b')448self->direction = FLIP_X;449450RSDK.DrawSprite(&self->headAnimator, NULL, false);451452self->direction = FLIP_NONE;453RSDK.DrawSprite(&self->bulbAnimator, NULL, false);454455RSDK.DrawCircle(self->position.x, self->position.y, self->formationCircleRadius >> 16, 0xF0F0F0, self->alpha >> 1, INK_ADD, false);456RSDK.DrawCircle(self->position.x, self->position.y, self->formationCircleRadius / 0xCCCC, 0xF0F0F0, self->alpha >> 1, INK_ADD, false);457}458459void HotaruHiWatt_SpawnPairHotarus(void)460{461RSDK_THIS(HotaruHiWatt);462463EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);464465EntityHotaruHiWatt *boss = self->parents[0];466467if (boss->state != HotaruHiWatt_StateBoss_HiddenDimScreen)468boss->state = HotaruHiWatt_StateBoss_HiddenDimScreen;469470EntityHotaruHiWatt *pairHotaru1 = CREATE_ENTITY(HotaruHiWatt, INT_TO_VOID(HHW_PAIR_HOTARU), player1->position.x, HotaruHiWatt->startY + 0x200000);471pairHotaru1->isPermanent = true;472pairHotaru1->parents[0] = boss;473474EntityHotaruHiWatt *pairHotaru2 = CREATE_ENTITY(HotaruHiWatt, INT_TO_VOID(HHW_PAIR_HOTARU), player1->position.x, HotaruHiWatt->startY + 0x200000);475pairHotaru2->angle += 0x800000;476pairHotaru2->isPermanent = true;477pairHotaru2->parents[0] = boss;478pairHotaru1->parents[1] = pairHotaru2;479}480481void HotaruHiWatt_SetupHHWReappear(void)482{483RSDK_THIS(HotaruHiWatt);484485EntityHotaruHiWatt *boss = self->parents[0];486487if (RSDK_GET_ENTITY(SLOT_PLAYER1, Player)->position.x <= HotaruHiWatt->boundsM)488boss->position.x = HotaruHiWatt->boundsR;489else490boss->position.x = HotaruHiWatt->boundsL;491492boss->position.y = HotaruHiWatt->startY;493494boss->nextState = HotaruHiWatt_StateBoss_LaserAttackDelay;495boss->state = HotaruHiWatt_StateBoss_DimScreen;496}497498void HotaruHiWatt_StateBoss_SetupArena(void)499{500RSDK_THIS(HotaruHiWatt);501502if (++self->timer >= 8) {503self->timer = 0;504505Zone->playerBoundActiveL[0] = true;506Zone->playerBoundActiveR[0] = true;507508Zone->cameraBoundsL[0] = (self->position.x >> 16) - ScreenInfo->center.x;509Zone->cameraBoundsR[0] = (self->position.x >> 16) + ScreenInfo->center.x;510Zone->cameraBoundsT[0] = (self->position.y >> 16) - ScreenInfo->size.y;511Zone->cameraBoundsB[0] = (self->position.y >> 16);512513HotaruHiWatt->boundsL = (Zone->cameraBoundsL[0] + 64) << 16;514HotaruHiWatt->boundsR = (Zone->cameraBoundsR[0] - 64) << 16;515HotaruHiWatt->boundsM = self->position.x;516HotaruHiWatt->boundsT = (Zone->cameraBoundsT[0] + 48) << 16;517HotaruHiWatt->boundsB = (Zone->cameraBoundsB[0] - 8) << 16;518519foreach_active(Fireflies, fireflies)520{521if (fireflies->state == Fireflies_State_Spawner)522destroyEntity(fireflies);523}524525self->state = HotaruHiWatt_StateBoss_AwaitPlayer;526}527}528529void HotaruHiWatt_StateBoss_AwaitPlayer(void)530{531RSDK_THIS(HotaruHiWatt);532533if (RSDK_GET_ENTITY(SLOT_PLAYER1, Player)->position.x > self->position.x) {534self->position.y += -0x100000 - (ScreenInfo->center.y << 16);535HotaruHiWatt->startY = self->position.y;536537self->state = HotaruHiWatt_StateBoss_DimScreen;538self->nextState = HotaruHiWatt_StateBoss_Appear;539}540}541542void HotaruHiWatt_StateBoss_Appear(void)543{544RSDK_THIS(HotaruHiWatt);545546RSDK.ProcessAnimation(&self->headAnimator);547548self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);549550if (++self->timer == 60) {551self->timer = 0;552RSDK.PlaySfx(HotaruHiWatt->sfxFlyUp, false, 255);553self->state = HotaruHiWatt_StateBoss_FlyUp;554}555556HotaruHiWatt_CheckPlayerCollisions_Boss();557}558559void HotaruHiWatt_StateBoss_FlyUp(void)560{561RSDK_THIS(HotaruHiWatt);562563self->velocity.y -= 0x3800;564self->originPos.y += self->velocity.y;565566RSDK.ProcessAnimation(&self->headAnimator);567568self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);569570HotaruHiWatt_CheckPlayerCollisions_Boss();571572if (!RSDK.CheckOnScreen(self, NULL)) {573self->position.x = HotaruHiWatt->boundsM;574self->position.y = HotaruHiWatt->startY;575self->state = self->nextState;576self->visible = false;577578EntityHotaruHiWatt *hotaru = CREATE_ENTITY(HotaruHiWatt, INT_TO_VOID(HHW_SINGLE_HOTARU), self->position.x, self->position.y);579hotaru->isPermanent = true;580hotaru->parents[0] = self;581}582}583584void HotaruHiWatt_StateHotaru_MoveToTarget(void)585{586RSDK_THIS(HotaruHiWatt);587588self->position.x += self->velocity.x;589self->position.y += self->velocity.y;590591if (!(Zone->timer & 3))592CREATE_ENTITY(HotaruHiWatt, INT_TO_VOID(HHW_FLASH), self->position.x, self->position.y);593594if (!((self->position.x ^ self->targetPos.x) & 0xFFF80000)) {595if (!((self->position.y ^ self->targetPos.y) & 0xFFF80000)) {596self->position.x = self->targetPos.x;597self->position.y = self->targetPos.y;598self->velocity.x = 0;599self->velocity.y = 0;600601if (!self->nextState) {602destroyEntity(self);603}604else {605RSDK.PlaySfx(HotaruHiWatt->sfxAppear, false, 0xFF);606self->state = self->nextState;607}608}609}610}611612void HotaruHiWatt_StateBoss_FlashFadeOut(void)613{614RSDK_THIS(HotaruHiWatt);615616RSDK.ProcessAnimation(&self->mainAnimator);617618self->alpha -= 8;619if (self->alpha <= 0)620destroyEntity(self);621}622623void HotaruHiWatt_StateBoss_HiddenDimScreen(void)624{625RSDK_THIS(HotaruHiWatt);626627if (self->timer >= 192)628self->state = StateMachine_None;629else630self->timer += 8;631632RSDK.SetLimitedFade(0, 1, 2, self->timer, 128, 192);633}634635void HotaruHiWatt_StateBoss_HiddenUndimScreen(void)636{637RSDK_THIS(HotaruHiWatt);638639if (self->timer <= 0)640self->state = StateMachine_None;641else642self->timer -= 8;643644RSDK.SetLimitedFade(0, 1, 2, self->timer, 128, 192);645}646647void HotaruHiWatt_StateHotaru_DimScreen(void)648{649RSDK_THIS(HotaruHiWatt);650651EntityHotaruHiWatt *boss = self->parents[0];652653if (boss->state != HotaruHiWatt_StateBoss_HiddenDimScreen)654boss->state = HotaruHiWatt_StateBoss_HiddenDimScreen;655656if (self->bulbAlpha >= 256) {657self->targetPos.x = HotaruHiWatt->boundsM + RSDK.Rand(-0x800000, 0x800000);658self->targetPos.y = HotaruHiWatt->startY + RSDK.Rand(-0x500000, 0x500000);659self->stateDraw = HotaruHiWatt_Draw_Hotaru;660self->velocity.x = (self->targetPos.x - self->position.x) / 48;661self->velocity.y = (self->targetPos.y - self->position.y) / 48;662663RSDK.PlaySfx(HotaruHiWatt->sfxFly, false, 255);664665self->nextState = HotaruHiWatt_StateHotaru_Charging;666self->state = HotaruHiWatt_StateHotaru_MoveToTarget;667}668else {669self->bulbAlpha += 16;670}671}672673void HotaruHiWatt_StateHotaru_Charging(void)674{675RSDK_THIS(HotaruHiWatt);676677EntityHotaruHiWatt *boss = self->parents[0];678679if (boss->state != HotaruHiWatt_StateBoss_HiddenUndimScreen)680boss->state = HotaruHiWatt_StateBoss_HiddenUndimScreen;681682RSDK.ProcessAnimation(&self->bulbAnimator);683684if (!self->timer) {685RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 0, &self->mainAnimator, true, 0);686RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 1, &self->bulbAnimator, true, 0);687}688689self->alpha = 8 * ++self->timer;690691if (self->timer == 32) {692self->timer = 0;693self->state = HotaruHiWatt_StateHotaru_Attacking;694self->stateDraw = HotaruHiWatt_Draw_HotaruAttacking;695696RSDK.PlaySfx(HotaruHiWatt->sfxLaser, false, 255);697}698699HotaruHiWatt_CheckPlayerCollisions_Hotaru();700}701702void HotaruHiWatt_StateHotaru_Attacking(void)703{704RSDK_THIS(HotaruHiWatt);705706RSDK.ProcessAnimation(&self->bulbAnimator);707708++self->timer;709if (!(self->timer & 1))710CREATE_ENTITY(HotaruHiWatt, INT_TO_VOID(HHW_MINILASER), self->position.x, self->position.y + 0x40000);711712if (self->timer == 24) {713self->timer = 0;714self->stateDraw = HotaruHiWatt_Draw_Hotaru;715self->state = HotaruHiWatt_StateHotaru_FinishedAttack;716}717718HotaruHiWatt_CheckPlayerCollisions_Hotaru();719}720721void HotaruHiWatt_StateHotaru_FinishedAttack(void)722{723RSDK_THIS(HotaruHiWatt);724725EntityHotaruHiWatt *boss = self->parents[0];726727if (boss->state != HotaruHiWatt_StateBoss_HiddenDimScreen)728boss->state = HotaruHiWatt_StateBoss_HiddenDimScreen;729730++self->timer;731732if (self->alpha <= 0) {733// health prolly should be named "remainingAttacks" here734if (self->health >= 1) {735self->timer = 0;736self->health--;737RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 1, &self->mainAnimator, true, 3);738self->stateDraw = StateMachine_None;739self->state = HotaruHiWatt_StateHotaru_DimScreen;740}741else {742self->state = HotaruHiWatt_StateHotaru_EndAttackSequence;743}744}745else {746self->alpha -= 8;747}748749HotaruHiWatt_CheckPlayerCollisions_Hotaru();750}751752void HotaruHiWatt_StateHotaru_EndAttackSequence(void)753{754RSDK_THIS(HotaruHiWatt);755756if (self->bulbAlpha <= 0) {757HotaruHiWatt_SpawnPairHotarus();758destroyEntity(self);759}760else {761self->bulbAlpha -= 32;762HotaruHiWatt_CheckPlayerCollisions_Hotaru();763}764}765766void HotaruHiWatt_State_MiniLaser(void)767{768RSDK_THIS(HotaruHiWatt);769770self->position.y += 0x80000;771772if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x80000, true)) {773if (HotaruHiWatt->spawnedLaserStrike) {774destroyEntity(self);775}776else {777RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 3, &self->mainAnimator, true, 0);778self->position.y += 0x80000;779self->drawGroup = Zone->objectDrawGroup[1];780self->state = HotaruHiWatt_State_MiniLaserStrike;781HotaruHiWatt->spawnedLaserStrike = true;782}783}784785if (self->classID == HotaruHiWatt->classID)786HotaruHiWatt_CheckPlayerCollisions_MiniLaser();787}788789void HotaruHiWatt_State_MiniLaserStrike(void)790{791RSDK_THIS(HotaruHiWatt);792793RSDK.ProcessAnimation(&self->mainAnimator);794795if (self->mainAnimator.frameID == 2)796HotaruHiWatt->spawnedLaserStrike = false;797798if (self->mainAnimator.frameID == self->mainAnimator.frameCount - 1)799destroyEntity(self);800}801802void HotaruHiWatt_StateHotaruPair_DimScreen(void)803{804RSDK_THIS(HotaruHiWatt);805806EntityHotaruHiWatt *boss = self->parents[0];807808if (boss->state != HotaruHiWatt_StateBoss_HiddenDimScreen)809boss->state = HotaruHiWatt_StateBoss_HiddenDimScreen;810811self->position.x = self->formationCircleRadius * RSDK.Cos1024(self->angle >> 14) + self->originPos.x;812self->position.y = self->formationCircleRadius * RSDK.Sin1024(self->angle >> 14) + self->originPos.y;813814if (self->alpha >= 0x100)815self->state = HotaruHiWatt_StateHotaruPair_PrepareAttack;816else817self->alpha += 0x10;818}819820void HotaruHiWatt_StateHotaruPair_PrepareAttack(void)821{822RSDK_THIS(HotaruHiWatt);823824if (self->timer >= 64) {825if (self->velocity.x > 0)826self->velocity.x -= 0x2000;827}828else {829if (self->velocity.x < 0x80000)830self->velocity.x += 0x2000;831}832833if (self->originPos.x < HotaruHiWatt->boundsM - 0x600000)834self->originPos.x += 0x20000;835else if (self->originPos.x > HotaruHiWatt->boundsM + 0x600000)836self->originPos.x -= 0x20000;837838self->originPos.y -= self->velocity.x >> 2;839self->formationCircleRadius += self->velocity.x >> 13;840841if (!(self->timer % 30) && self->timer < 120)842RSDK.PlaySfx(HotaruHiWatt->sfxFly, (self->timer % 30), 0xFF);843844self->angle += self->velocity.x;845846++self->timer;847self->position.x = self->formationCircleRadius * RSDK.Cos1024(self->angle >> 14) + self->originPos.x;848self->position.y = self->formationCircleRadius * RSDK.Sin1024(self->angle >> 14) + self->originPos.y;849850if (!(Zone->timer & 3))851CREATE_ENTITY(HotaruHiWatt, INT_TO_VOID(HHW_FLASH), self->position.x, self->position.y);852853if (self->timer == 128) {854self->timer = 0;855RSDK.PlaySfx(HotaruHiWatt->sfxAppear, false, 255);856self->state = HotaruHiWatt_StateHotaruPair_Charging;857}858}859860void HotaruHiWatt_StateHotaruPair_Charging(void)861{862RSDK_THIS(HotaruHiWatt);863864EntityHotaruHiWatt *boss = self->parents[0];865866if (boss->state != HotaruHiWatt_StateBoss_HiddenUndimScreen)867boss->state = HotaruHiWatt_StateBoss_HiddenUndimScreen;868869RSDK.ProcessAnimation(&self->bulbAnimator);870871if (!self->timer) {872RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 0, &self->mainAnimator, true, 0);873RSDK.SetSpriteAnimation(HotaruHiWatt->hotaruFrames, 1, &self->bulbAnimator, true, 0);874}875876self->alpha = 8 * ++self->timer;877if (self->timer == 32) {878self->timer = 0;879self->velocity.y = 0;880881self->stateDraw = HotaruHiWatt_Draw_HotaruAttacking;882self->state = HotaruHiWatt_StateHotaruPair_AttackDelay;883884if (self->parents[1]) {885for (int32 i = 30; i < 254; i += 28) {886EntityHotaruHiWatt *orb = CREATE_ENTITY(HotaruHiWatt, INT_TO_VOID(HHW_ELECTRICORB), self->position.x, self->position.y);887orb->scale.x = i;888orb->angle = RSDK.Rand(0, 256);889orb->parents[1] = self;890orb->parents[2] = self->parents[1];891}892}893}894}895896void HotaruHiWatt_StateHotaruPair_AttackDelay(void)897{898RSDK_THIS(HotaruHiWatt);899900if (++self->timer == 32) {901self->timer = 0;902self->state = HotaruHiWatt_StateHotaruPair_AttackMovingDown;903}904}905906void HotaruHiWatt_StateHotaruPair_AttackMovingDown(void)907{908RSDK_THIS(HotaruHiWatt);909910RSDK.ProcessAnimation(&self->bulbAnimator);911912self->velocity.y += 0x800;913914if (self->velocity.y > 0x20000) {915self->velocity.y = 0x20000;916if (self->position.y > HotaruHiWatt->startY + 0x140000)917self->state = HotaruHiWatt_StateHotaruPair_AttackMovingUp;918}919920self->position.y += self->velocity.y;921922HotaruHiWatt_CheckPlayerCollisions_Hotaru();923}924925void HotaruHiWatt_StateHotaruPair_AttackMovingUp(void)926{927RSDK_THIS(HotaruHiWatt);928929RSDK.ProcessAnimation(&self->bulbAnimator);930931self->velocity.y -= 0x1000;932if (self->velocity.y < -0x20000)933self->velocity.y = -0x20000;934935self->position.y += self->velocity.y;936937if (self->position.y < HotaruHiWatt->startY - 0xC00000) {938HotaruHiWatt_SetupHHWReappear();939destroyEntity(self);940}941942HotaruHiWatt_CheckPlayerCollisions_Hotaru();943}944945void HotaruHiWatt_State_SparkyOrb(void)946{947RSDK_THIS(HotaruHiWatt);948949RSDK.ProcessAnimation(&self->mainAnimator);950951EntityHotaruHiWatt *hotaruPair1 = self->parents[1];952EntityHotaruHiWatt *hotaruPair2 = self->parents[2];953954if (hotaruPair1->classID == HotaruHiWatt->classID && hotaruPair2->classID == HotaruHiWatt->classID) {955int32 scale = (RSDK.Sin256(self->angle + 4 * Zone->timer) >> 7) + self->scale.x;956957self->position.x = hotaruPair1->position.x + scale * ((hotaruPair2->position.x - hotaruPair1->position.x) >> 8);958self->position.y = hotaruPair1->position.y + 0xC0000 + scale * ((hotaruPair2->position.y - hotaruPair1->position.y) >> 8);959self->position.y += RSDK.Sin256(self->angle + 4 * Zone->timer) << 9;960961HotaruHiWatt_CheckPlayerCollisions_MiniLaser();962}963else {964self->alpha = 0x100;965self->inkEffect = INK_ALPHA;966self->state = HotaruHiWatt_State_SparkyOrb_FadeOut;967968self->velocity.x = RSDK.Rand(-0x20000, 0x20000);969self->velocity.y = RSDK.Rand(-0x20000, 0x20000);970}971}972973void HotaruHiWatt_State_SparkyOrb_FadeOut(void)974{975RSDK_THIS(HotaruHiWatt);976977RSDK.ProcessAnimation(&self->mainAnimator);978979self->velocity.y += 0x3800;980self->position.x += self->velocity.x;981self->position.y += self->velocity.y;982983if (self->alpha <= 0)984destroyEntity(self);985else986self->alpha -= 8;987}988989void HotaruHiWatt_StateBoss_DimScreen(void)990{991RSDK_THIS(HotaruHiWatt);992993EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);994995if (player1->onGround) {996if (self->timer >= 192) {997if (!self->playingBossTrack) {998Music_TransitionTrack(TRACK_MINIBOSS, 0.0125);999self->playingBossTrack = true;1000}1001self->state = HotaruHiWatt_StateBoss_CreateSmallHHWs;1002RSDK.PlaySfx(HotaruHiWatt->sfxHHWAppear, false, 255);1003}1004else {1005self->timer += 8;1006}10071008RSDK.SetLimitedFade(0, 1, 2, self->timer, 128, 192);1009}1010}10111012void HotaruHiWatt_StateBoss_CreateSmallHHWs(void)1013{1014RSDK_THIS(HotaruHiWatt);10151016if (++self->timer == 224) {1017for (int32 angle = 0x20; angle < 0x120; angle += 0x40) {1018EntityHotaruHiWatt *hotaru = CREATE_ENTITY(HotaruHiWatt, INT_TO_VOID(HHW_SMALL_HOTARU), self->position.x, self->position.y - 0xC0000);1019hotaru->position.x += RSDK.Cos256(angle) << 16;1020hotaru->position.y += RSDK.Sin256(angle) << 16;1021hotaru->velocity.x = (hotaru->targetPos.x - hotaru->position.x) >> 6;1022hotaru->velocity.y = (hotaru->targetPos.y - hotaru->position.y) >> 6;1023}10241025self->timer = 0;1026self->velocity.x = 0x50000;1027self->stateDraw = HotaruHiWatt_Draw_FormingHHW;1028self->visible = true;1029self->state = HotaruHiWatt_StateBoss_FormingHHW;1030}1031}10321033void HotaruHiWatt_StateBoss_FormingHHW(void)1034{1035RSDK_THIS(HotaruHiWatt);10361037if (++self->timer >= 60) {1038self->velocity.x -= 0x3800;1039self->formationCircleRadius += self->velocity.x;10401041if (self->velocity.x <= 0) {1042self->originPos = self->position;1043self->timer = 192;1044self->stateDraw = HotaruHiWatt_Draw_FlashAppear;1045self->state = HotaruHiWatt_StateBoss_FlashAppear;10461047RSDK.StopSfx(HotaruHiWatt->sfxHHWAppear);1048RSDK.PlaySfx(HotaruHiWatt->sfxFlash, false, 255);10491050EntityFXFade *fxFade = CREATE_ENTITY(FXFade, INT_TO_VOID(0xF0F0F0), self->position.x, self->position.y);1051fxFade->speedIn = 128;1052fxFade->speedOut = 16;1053}1054}1055}10561057void HotaruHiWatt_StateBoss_FlashAppear(void)1058{1059RSDK_THIS(HotaruHiWatt);10601061RSDK.ProcessAnimation(&self->headAnimator);10621063self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);10641065self->velocity.x -= 0x3800;1066self->formationCircleRadius += self->velocity.x;10671068if (self->timer > 0)1069self->timer -= 8;10701071RSDK.SetLimitedFade(0, 1, 2, self->timer, 128, 192);10721073if (self->alpha > 0) {1074self->alpha -= 8;1075}10761077if (self->formationCircleRadius <= 0) {1078self->stateDraw = HotaruHiWatt_Draw_Boss;1079self->state = self->nextState;1080}1081}10821083void HotaruHiWatt_StateBoss_LaserAttackDelay(void)1084{1085RSDK_THIS(HotaruHiWatt);10861087RSDK.ProcessAnimation(&self->headAnimator);10881089self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);10901091if (++self->timer >= 24) {1092self->timer = 0;1093self->alpha = 0;1094self->stateDraw = HotaruHiWatt_Draw_BossLaserCharging;1095RSDK.SetSpriteAnimation(HotaruHiWatt->aniFrames, 2, &self->bulbFlashAnimator, true, 0);1096RSDK.SetSpriteAnimation(HotaruHiWatt->aniFrames, 7, &self->mainAnimator, true, 0);10971098RSDK.PlaySfx(HotaruHiWatt->sfxCharge, false, 255);1099self->state = HotaruHiWatt_StateBoss_ChargingLaser;1100}11011102HotaruHiWatt_CheckPlayerCollisions_Boss();1103}11041105void HotaruHiWatt_StateBoss_ChargingLaser(void)1106{1107RSDK_THIS(HotaruHiWatt);11081109RSDK.ProcessAnimation(&self->headAnimator);11101111self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);11121113HotaruHiWatt_CheckPlayerCollisions_Boss();11141115if (self->state == HotaruHiWatt_StateBoss_ChargingLaser) {1116if (self->alpha < 0x100)1117self->alpha += 4;11181119if (++self->timer >= 64) {1120self->timer = 0;1121self->velocity.x = 0;1122RSDK.SetSpriteAnimation(HotaruHiWatt->aniFrames, 3, &self->bulbFlashAnimator, true, 0);1123RSDK.SetSpriteAnimation(HotaruHiWatt->aniFrames, 3, &self->mainAnimator, true, 2);1124RSDK.SetSpriteAnimation(HotaruHiWatt->aniFrames, 4, &self->laserImpactAnimator, true, 0);11251126self->stateDraw = HotaruHiWatt_Draw_BossLaser;1127RSDK.StopSfx(HotaruHiWatt->sfxCharge);11281129if (self->position.x < HotaruHiWatt->boundsM)1130self->state = HotaruHiWatt_StateBoss_LaserAttack_Left;1131else1132self->state = HotaruHiWatt_StateBoss_LaserAttack_Right;1133}1134}1135}11361137// Right -> Left1138void HotaruHiWatt_StateBoss_LaserAttack_Right(void)1139{1140RSDK_THIS(HotaruHiWatt);11411142RSDK.ProcessAnimation(&self->headAnimator);1143RSDK.ProcessAnimation(&self->laserImpactAnimator);11441145self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);11461147self->velocity.x -= 0x1000;1148if (self->velocity.x < -0x20000)1149self->velocity.x = -0x20000;11501151self->position.x += self->velocity.x;11521153if (self->position.x <= HotaruHiWatt->boundsL) {1154self->position.x = HotaruHiWatt->boundsL;1155self->state = HotaruHiWatt_StateBoss_FinishedLaserAttack;1156}11571158int32 x = self->position.x;1159int32 y = self->position.y;1160self->position.y += 0x800000;1161RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0, 32);11621163self->laserImpactPos.x = self->position.x;1164self->laserImpactPos.y = self->position.y;11651166self->position.x = x;1167self->position.y = y;1168HotaruHiWatt_CheckPlayerCollisions_BossLaser();1169}11701171// Left -> Right1172void HotaruHiWatt_StateBoss_LaserAttack_Left(void)1173{1174RSDK_THIS(HotaruHiWatt);11751176RSDK.ProcessAnimation(&self->headAnimator);1177RSDK.ProcessAnimation(&self->laserImpactAnimator);11781179self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);11801181self->velocity.x += 4096;1182if (self->velocity.x > 0x20000)1183self->velocity.x = 0x20000;1184self->position.x += self->velocity.x;11851186if (self->position.x >= HotaruHiWatt->boundsR) {1187self->position.x = HotaruHiWatt->boundsR;1188self->state = HotaruHiWatt_StateBoss_FinishedLaserAttack;1189}11901191int32 x = self->position.x;1192int32 y = self->position.y;1193self->position.y += 0x800000;1194RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0, 32);11951196self->laserImpactPos.x = self->position.x;1197self->laserImpactPos.y = self->position.y;11981199self->position.x = x;1200self->position.y = y;1201HotaruHiWatt_CheckPlayerCollisions_BossLaser();1202}12031204void HotaruHiWatt_StateBoss_FinishedLaserAttack(void)1205{1206RSDK_THIS(HotaruHiWatt);12071208RSDK.ProcessAnimation(&self->headAnimator);12091210self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 2, 10);12111212if (self->alpha > 0)1213self->alpha -= 4;12141215if (++self->timer >= 64) {1216self->laserImpactPos.y += 0x800000;1217self->timer = 0;1218self->stateDraw = HotaruHiWatt_Draw_Boss;1219self->velocity.y = 0;12201221RSDK.PlaySfx(HotaruHiWatt->sfxFlyUp, false, 255);1222self->state = HotaruHiWatt_StateBoss_FlyUp;1223}12241225HotaruHiWatt_CheckPlayerCollisions_Boss();1226}12271228void HotaruHiWatt_StateBoss_Destroyed(void)1229{1230RSDK_THIS(HotaruHiWatt);12311232HotaruHiWatt_Explode();12331234if (++self->timer == 60) {1235Debris_CreateFromEntries(HotaruHiWatt->aniFrames, HotaruHiWatt->debrisInfo, 8);1236self->visible = false;1237}1238else if (self->timer == 90) {1239Music_TransitionTrack(TRACK_STAGE, 0.0125);12401241self->timer = 0;1242self->state = HotaruHiWatt_StateBoss_Finished;1243self->visible = false;1244}1245}12461247void HotaruHiWatt_StateBoss_Finished(void)1248{1249RSDK_THIS(HotaruHiWatt);12501251if (++self->timer == 60) {1252foreach_all(SignPost, signPost)1253{1254signPost->position.x = self->position.x;1255signPost->active = ACTIVE_NORMAL;1256signPost->state = SignPost_State_Falling;1257RSDK.PlaySfx(SignPost->sfxTwinkle, false, 255);1258}12591260destroyEntity(self);1261}1262}12631264#if GAME_INCLUDE_EDITOR1265void HotaruHiWatt_EditorDraw(void)1266{1267RSDK_THIS(HotaruHiWatt);12681269self->drawFX = FX_FLIP;1270RSDK.SetSpriteAnimation(HotaruHiWatt->aniFrames, 0, &self->headAnimator, false, 0);1271RSDK.SetSpriteAnimation(HotaruHiWatt->aniFrames, 1, &self->bulbAnimator, false, 0);12721273self->direction = FLIP_NONE;1274RSDK.DrawSprite(&self->headAnimator, NULL, false);1275RSDK.DrawSprite(&self->bulbAnimator, NULL, false);12761277if (showGizmos()) {1278RSDK_DRAWING_OVERLAY(true);12791280DrawHelpers_DrawArenaBounds(-WIDE_SCR_XCENTER, -SCREEN_YSIZE, WIDE_SCR_XCENTER, 0, 1 | 2 | 4 | 8, 0x00C0F0);12811282RSDK_DRAWING_OVERLAY(false);1283}1284}12851286void HotaruHiWatt_EditorLoad(void)1287{1288HotaruHiWatt->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/HotaruHiWatt.bin", SCOPE_STAGE);1289HotaruHiWatt->hotaruFrames = RSDK.LoadSpriteAnimation("SSZ1/HotaruMKII.bin", SCOPE_STAGE);1290}1291#endif12921293void HotaruHiWatt_Serialize(void) {}129412951296