Path: blob/master/SonicMania/Objects/SSZ/HotaruMKII.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: HotaruMKII Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectHotaruMKII *HotaruMKII;1011void HotaruMKII_Update(void)12{13RSDK_THIS(HotaruMKII);14StateMachine_Run(self->state);15}1617void HotaruMKII_LateUpdate(void) {}1819void HotaruMKII_StaticUpdate(void) {}2021void HotaruMKII_Draw(void)22{23RSDK_THIS(HotaruMKII);2425if (self->state != HotaruMKII_State_CheckPlayerInRange) {26RSDK.DrawSprite(&self->mainAnimator, NULL, false);2728if (self->state != HotaruMKII_State_FlyOnScreen && ((Zone->timer & 1) || self->state == HotaruMKII_State_LaserAttack)) {29int32 ink = self->inkEffect;30self->inkEffect = INK_ALPHA;31RSDK.DrawSprite(&self->flashAnimator, NULL, false);3233self->inkEffect = ink;34}35}36}3738void HotaruMKII_Create(void *data)39{40RSDK_THIS(HotaruMKII);4142if (!SceneInfo->inEditor) {43self->drawGroup = Zone->objectDrawGroup[1];44self->startPos = self->position;45self->startDir = self->direction;46self->updateRange.x = 0x1000000;47self->updateRange.y = 0x1000000;48self->drawFX = FX_FLIP;4950if (!self->triggerSize.x) {51self->triggerSize.x = 0x1000000;52self->triggerSize.y = 0x1000000;53}5455self->hitboxTrigger.right = self->triggerSize.x >> 17;56self->hitboxTrigger.left = -self->hitboxTrigger.right;57self->hitboxTrigger.bottom = self->triggerSize.y >> 17;58self->hitboxTrigger.top = -self->hitboxTrigger.bottom;5960self->type = VOID_TO_INT(data);61switch (self->type) {62default: break;63case HOTARUMKII_MAIN:64self->active = ACTIVE_BOUNDS;65self->inkEffect = INK_NONE;66self->visible = true;67RSDK.SetSpriteAnimation(HotaruMKII->aniFrames, 1, &self->flashAnimator, true, 0);68self->state = HotaruMKII_State_Init;69break;7071case HOTARUMKII_FLASH:72self->active = ACTIVE_NORMAL;73self->inkEffect = INK_ALPHA;74self->visible = true;75self->alpha = 0x80;76RSDK.SetSpriteAnimation(HotaruMKII->aniFrames, 1, &self->mainAnimator, true, 0);77self->state = HotaruMKII_State_Flash;78break;7980case HOTARUMKII_LASER:81--self->drawGroup;82self->active = ACTIVE_NORMAL;83self->inkEffect = INK_ALPHA;84self->visible = true;85self->alpha = 0x80;86RSDK.SetSpriteAnimation(HotaruMKII->aniFrames, 2, &self->mainAnimator, true, 0);87self->state = HotaruMKII_State_Laser;88break;89}90}91}9293void HotaruMKII_StageLoad(void)94{95if (RSDK.CheckSceneFolder("SSZ1"))96HotaruMKII->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/HotaruMKII.bin", SCOPE_STAGE);97else if (RSDK.CheckSceneFolder("SSZ2"))98HotaruMKII->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/HotaruMKII.bin", SCOPE_STAGE);99100HotaruMKII->hitboxBadnik.top = -6;101HotaruMKII->hitboxBadnik.left = -6;102HotaruMKII->hitboxBadnik.right = 6;103HotaruMKII->hitboxBadnik.bottom = 6;104105HotaruMKII->hitboxLaser.top = -8;106HotaruMKII->hitboxLaser.left = -8;107HotaruMKII->hitboxLaser.right = 8;108HotaruMKII->hitboxLaser.bottom = 8;109110HotaruMKII->sfxLaser = RSDK.GetSfx("SSZ1/HotaruLaser.wav");111HotaruMKII->sfxAppear = RSDK.GetSfx("SSZ1/HotaruAppear.wav");112HotaruMKII->sfxFly = RSDK.GetSfx("SSZ1/HotaruFly.wav");113HotaruMKII->sfxCharge = RSDK.GetSfx("SSZ1/HotaruCharge.wav");114115DEBUGMODE_ADD_OBJ(HotaruMKII);116}117118void HotaruMKII_DebugSpawn(void)119{120RSDK_THIS(DebugMode);121122EntityHotaruMKII *hotaruMKII = CREATE_ENTITY(HotaruMKII, NULL, self->position.x, self->position.y);123hotaruMKII->origin = RSDK.Rand(0, 0x100);124125hotaruMKII->offset1.x = -0x10000 * RSDK.Rand(0, 2) * RSDK.Rand(0x20, 0x100);126hotaruMKII->offset1.y = -0x10000 * RSDK.Rand(0, 2) * RSDK.Rand(0x20, 0xC0);127hotaruMKII->offset2.x = -0x10000 * RSDK.Rand(0, 2) * RSDK.Rand(0x20, 0xC0);128hotaruMKII->offset2.y = -0x10000 * RSDK.Rand(0, 2) * RSDK.Rand(0x20, 0xC0);129hotaruMKII->offset3.x = -0x10000 * RSDK.Rand(0, 2) * RSDK.Rand(0x20, 0xC0);130hotaruMKII->offset3.y = -0x10000 * RSDK.Rand(0, 2) * RSDK.Rand(0x20, 0xC0);131}132133void HotaruMKII_DebugDraw(void)134{135RSDK.SetSpriteAnimation(HotaruMKII->aniFrames, 0, &DebugMode->animator, true, 0);136RSDK.DrawSprite(&DebugMode->animator, NULL, false);137}138139void HotaruMKII_CheckPlayerCollisions(void)140{141RSDK_THIS(HotaruMKII);142143foreach_active(Player, player)144{145if (Player_CheckBadnikTouch(player, self, &HotaruMKII->hitboxBadnik))146Player_CheckBadnikBreak(player, self, true);147}148}149150void HotaruMKII_CheckOffScreen(void)151{152RSDK_THIS(HotaruMKII);153154if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {155self->position = self->startPos;156self->direction = self->startDir;157self->offsetID = 0;158HotaruMKII_Create(NULL);159}160}161162void HotaruMKII_HandleDistances(EntityPlayer *player)163{164RSDK_THIS(HotaruMKII);165166if (Player_CheckValidState(player)) {167int32 distX = self->curOffset.x;168switch (self->offsetID) {169case 0:170self->curOffset.x = self->offset1.x;171self->curOffset.y = self->offset1.y;172break;173174case 1:175self->curOffset.x = self->offset2.x;176self->curOffset.y = self->offset2.y;177break;178179case 2:180self->curOffset.x = self->offset3.x;181self->curOffset.y = self->offset3.y;182break;183184case 3:185self->curOffset.x = 0;186self->curOffset.y = 0;187break;188189default: break;190}191192self->curOffset.x &= 0xFFFF0000;193self->curOffset.y &= 0xFFFF0000;194if (!self->curOffset.x && !self->curOffset.y) {195self->curOffset.x = distX;196self->curOffset.y = 0xB0010000;197}198199int32 angle =200RSDK.ATan2(self->curOffset.x + player->position.x - self->position.x, self->curOffset.y + player->position.y - self->position.y);201self->moveAcceleration.x = 0x300 * RSDK.Cos256(angle);202self->moveAcceleration.y = 0x300 * RSDK.Sin256(angle);203204self->velocity.x = player->velocity.x + self->moveAcceleration.x;205self->velocity.y = player->velocity.y + self->moveAcceleration.y;206207++self->offsetID;208}209else {210self->playerPtr = NULL;211self->offsetID = 4;212self->velocity.x = 0;213self->velocity.y = -0x30000;214self->state = HotaruMKII_State_FlyAway;215}216}217218void HotaruMKII_State_Init(void)219{220RSDK_THIS(HotaruMKII);221222self->active = ACTIVE_NORMAL;223self->childCount = 0;224225self->state = HotaruMKII_State_CheckPlayerInRange;226HotaruMKII_State_CheckPlayerInRange();227}228229void HotaruMKII_State_CheckPlayerInRange(void)230{231RSDK_THIS(HotaruMKII);232233bool32 foundTargetPlayer = false;234foreach_active(Player, player)235{236if (Player_CheckCollisionTouch(player, self, &self->hitboxTrigger)) {237self->playerPtr = player;238if (!player->sidekick) {239foundTargetPlayer = true;240241int32 screenID = 0;242if (player->camera)243screenID = player->camera->screenID;244245self->position.x = RSDK.Cos256(self->origin) << 17;246self->position.y = RSDK.Sin256(self->origin) << 17;247RSDKScreenInfo *screen = &ScreenInfo[screenID];248249if (self->position.x > (int32)(screen->size.x & 0xFFFFFFFE) << 15)250self->position.x = (int32)(screen->size.x & 0xFFFFFFFE) << 15;251252if (self->position.x < -((int32)(screen->size.x & 0xFFFFFFFE) << 15))253self->position.x = -((int32)(screen->size.x & 0xFFFFFFFE) << 15);254255if (self->position.y > (int32)(screen->size.y & 0xFFFFFFFE) << 15)256self->position.y = (int32)(screen->size.y & 0xFFFFFFFE) << 15;257258if (self->position.y < -((int32)(screen->size.y & 0xFFFFFFFE) << 15))259self->position.y = -((int32)(screen->size.y & 0xFFFFFFFE) << 15);260261if (self->position.x >= 0)262self->position.x += 0x100000;263else264self->position.x -= 0x100000;265266if (self->position.y >= 0)267self->position.y += 0x100000;268else269self->position.y -= 0x100000;270271self->position.x += ((screen->size.x & 0xFFFFFFFE) + 2 * screen->position.x) << 15;272self->position.y += ((screen->size.y & 0xFFFFFFFE) + 2 * screen->position.y) << 15;273HotaruMKII_HandleDistances(player);274275self->inkEffect = INK_ALPHA;276self->visible = true;277self->alpha = 0x80;278RSDK.SetSpriteAnimation(HotaruMKII->aniFrames, 1, &self->mainAnimator, true, 0);279280RSDK.PlaySfx(HotaruMKII->sfxFly, false, 255);281self->state = HotaruMKII_State_FlyOnScreen;282283foreach_break;284}285}286}287288if (!foundTargetPlayer)289HotaruMKII_CheckOffScreen();290}291292void HotaruMKII_State_FlyAway(void)293{294RSDK_THIS(HotaruMKII);295296self->position.x += self->velocity.x;297self->position.y += self->velocity.y;298299HotaruMKII_CheckOffScreen();300}301302void HotaruMKII_State_FlyOnScreen(void)303{304RSDK_THIS(HotaruMKII);305EntityPlayer *player = self->playerPtr;306307self->position.x += self->velocity.x;308self->position.y += self->velocity.y;309310if (player && !Player_CheckValidState(player)) {311HotaruMKII_HandleDistances(player);312}313else {314if (!(Zone->timer & 7)) {315EntityHotaruMKII *flash = CREATE_ENTITY(HotaruMKII, INT_TO_VOID(HOTARUMKII_FLASH), self->position.x, self->position.y);316flash->playerPtr = self->playerPtr;317flash->curOffset.x = self->position.x - player->position.x;318flash->curOffset.y = self->position.y - player->position.y;319}320321int32 moveFinished = 0;322if (self->moveAcceleration.x < 0) {323int32 x = player->position.x + self->curOffset.x;324if (self->position.x <= x) {325moveFinished = 1;326self->position.x = x;327}328} else if (self->moveAcceleration.x >= 1) {329int32 x = player->position.x + self->curOffset.x;330if (self->position.x >= x) {331moveFinished = 1;332self->position.x = x;333}334} else {335moveFinished = 1;336}337338if (self->moveAcceleration.y < 0) {339int32 y = player->position.y + self->curOffset.y;340if (self->position.y <= y) {341moveFinished++;342self->position.y = y;343}344} else if (self->moveAcceleration.y > 0) {345int32 y = player->position.y + self->curOffset.y;346if (self->position.y >= y) {347moveFinished++;348self->position.y = y;349}350} else {351moveFinished++;352}353354if (moveFinished == 2) {355self->inkEffect = INK_NONE;356self->alpha = 0x00;357RSDK.SetSpriteAnimation(HotaruMKII->aniFrames, 0, &self->mainAnimator, true, 0);358359self->timer = 60;360RSDK.PlaySfx(HotaruMKII->sfxAppear, false, 255);361self->state = HotaruMKII_State_AttackDelay;362}363else {364RSDK.ProcessAnimation(&self->mainAnimator);365366int32 angle =367RSDK.ATan2(player->position.x + self->curOffset.x - self->position.x, player->position.y + self->curOffset.y - self->position.y);368self->moveAcceleration.x = 0x300 * RSDK.Cos256(angle);369self->moveAcceleration.y = 0x300 * RSDK.Sin256(angle);370371self->velocity.x = player->velocity.x + self->moveAcceleration.x;372self->velocity.y = player->velocity.y + self->moveAcceleration.y;373}374375HotaruMKII_CheckOffScreen();376}377}378379void HotaruMKII_State_AttackDelay(void)380{381RSDK_THIS(HotaruMKII);382EntityPlayer *player = self->playerPtr;383384RSDK.ProcessAnimation(&self->unusedAnimator);385386if (Player_CheckValidState(player)) {387self->position.x = player->position.x + self->curOffset.x;388self->position.y = player->position.y + self->curOffset.y;389if (--self->timer <= 0) {390RSDK.PlaySfx(HotaruMKII->sfxCharge, false, 255);391self->state = HotaruMKII_State_Charging;392}393HotaruMKII_CheckOffScreen();394}395else {396HotaruMKII_HandleDistances(player);397}398}399400void HotaruMKII_State_Charging(void)401{402RSDK_THIS(HotaruMKII);403EntityPlayer *player = self->playerPtr;404405RSDK.ProcessAnimation(&self->flashAnimator);406407if (Player_CheckValidState(player)) {408self->position.x = player->position.x + self->curOffset.x;409self->position.y = player->position.y + self->curOffset.y;410411self->alpha += 2;412if (self->alpha == 0x100) {413self->timer = 90;414self->alpha = 0x100;415self->inkEffect = INK_ALPHA;416self->state = HotaruMKII_State_LaserAttack;417}418HotaruMKII_CheckPlayerCollisions();419HotaruMKII_CheckOffScreen();420}421else {422HotaruMKII_HandleDistances(player);423}424}425426void HotaruMKII_State_LaserAttack(void)427{428RSDK_THIS(HotaruMKII);429EntityPlayer *player = self->playerPtr;430431RSDK.ProcessAnimation(&self->mainAnimator);432if (Player_CheckValidState(player)) {433if (--self->timer > 0) {434if (self->timer <= 60) {435if (self->timer == 60) {436RSDK.PlaySfx(HotaruMKII->sfxLaser, false, 255);437RSDK.StopSfx(HotaruMKII->sfxCharge);438}439440self->alpha -= 3;441if (!(self->timer & 3)) {442EntityHotaruMKII *laser = CREATE_ENTITY(HotaruMKII, INT_TO_VOID(HOTARUMKII_LASER), self->position.x, self->position.y + 0xE0000);443444if (!self->childCount) {445self->childCount = 1;446laser->mainAnimator.frameID = 1;447}448449if (self->childCount == 1)450laser->childCount = 1;451452if (++self->childCount == 3)453self->childCount = 1;454}455}456457RSDK.ProcessAnimation(&self->flashAnimator);458HotaruMKII_CheckPlayerCollisions();459HotaruMKII_CheckOffScreen();460}461else {462HotaruMKII_HandleDistances(player);463self->childCount = 0;464self->alpha = 0x80;465self->inkEffect = INK_ALPHA;466RSDK.SetSpriteAnimation(HotaruMKII->aniFrames, 1, &self->mainAnimator, true, 0);467self->state = HotaruMKII_State_FlyOnScreen;468}469}470else {471HotaruMKII_HandleDistances(player);472}473}474475void HotaruMKII_State_Flash(void)476{477RSDK_THIS(HotaruMKII);478EntityPlayer *player = self->playerPtr;479480self->position.x = player->position.x + self->curOffset.x;481self->position.y = player->position.y + self->curOffset.y;482483RSDK.ProcessAnimation(&self->mainAnimator);484485self->alpha -= 4;486if (self->alpha <= 0)487destroyEntity(self);488}489490void HotaruMKII_State_Laser(void)491{492RSDK_THIS(HotaruMKII);493494self->position.y += 0x40000;495foreach_active(Player, player)496{497if (Player_CheckCollisionTouch(player, self, &HotaruMKII->hitboxLaser)) {498Player_ElementHurt(player, self, SHIELD_LIGHTNING);499}500}501502if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x80000, true)) {503if (self->childCount == 1) {504++self->drawGroup;505self->position.y += 0x80000;506self->inkEffect = INK_NONE;507RSDK.SetSpriteAnimation(HotaruMKII->aniFrames, 3, &self->mainAnimator, true, 0);508self->state = HotaruMKII_State_LaserStrike;509}510else {511destroyEntity(self);512}513}514}515516void HotaruMKII_State_LaserStrike(void)517{518RSDK_THIS(HotaruMKII);519520RSDK.ProcessAnimation(&self->mainAnimator);521if (self->mainAnimator.frameID >= self->mainAnimator.frameCount - 1)522destroyEntity(self);523}524525#if GAME_INCLUDE_EDITOR526void HotaruMKII_EditorDraw(void)527{528RSDK_THIS(HotaruMKII);529self->drawGroup = Zone->objectDrawGroup[1];530self->updateRange.x = 0x1000000;531self->updateRange.y = 0x1000000;532self->drawFX = FX_FLIP;533self->active = ACTIVE_BOUNDS;534self->inkEffect = INK_NONE;535self->visible = true;536RSDK.SetSpriteAnimation(HotaruMKII->aniFrames, 0, &self->mainAnimator, false, 0);537538RSDK.DrawSprite(&self->mainAnimator, NULL, false);539540if (showGizmos()) {541Vector2 size = self->triggerSize;542if (!self->triggerSize.x) {543self->triggerSize.x = 0x1000000;544self->triggerSize.y = 0x1000000;545}546547RSDK_DRAWING_OVERLAY(true);548549DrawHelpers_DrawRectOutline(self->position.x, self->position.y, self->triggerSize.x, self->triggerSize.y, 0xFF0000);550551RSDK_DRAWING_OVERLAY(false);552553self->triggerSize = size;554}555}556557void HotaruMKII_EditorLoad(void)558{559if (RSDK.CheckSceneFolder("SSZ1"))560HotaruMKII->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/HotaruMKII.bin", SCOPE_STAGE);561else if (RSDK.CheckSceneFolder("SSZ2"))562HotaruMKII->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/HotaruMKII.bin", SCOPE_STAGE);563}564#endif565566void HotaruMKII_Serialize(void)567{568RSDK_EDITABLE_VAR(HotaruMKII, VAR_UINT8, origin);569RSDK_EDITABLE_VAR(HotaruMKII, VAR_VECTOR2, offset1);570RSDK_EDITABLE_VAR(HotaruMKII, VAR_VECTOR2, offset2);571RSDK_EDITABLE_VAR(HotaruMKII, VAR_VECTOR2, offset3);572RSDK_EDITABLE_VAR(HotaruMKII, VAR_VECTOR2, triggerSize);573}574575576