Path: blob/master/SonicMania/Objects/ERZ/PhantomShinobi.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: PhantomShinobi Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectPhantomShinobi *PhantomShinobi;1011void PhantomShinobi_Update(void)12{13RSDK_THIS(PhantomShinobi);1415if (self->invincibilityTimer > 0)16self->invincibilityTimer--;1718StateMachine_Run(self->state);1920self->rotStore += self->rotSpeed;21self->rotStore &= 0xFFFF;22}2324void PhantomShinobi_LateUpdate(void) {}2526void PhantomShinobi_StaticUpdate(void) {}2728void PhantomShinobi_Draw(void)29{30RSDK_THIS(PhantomShinobi);3132RSDK.SetActivePalette(4, 0, ScreenInfo[SceneInfo->currentScreenID].size.y);3334if (self->invincibilityTimer & 1)35RSDK.CopyPalette(6, 128, 4, 128, 128);3637self->rotation = self->rotStore >> 7;3839for (int32 i = 0; i < 8; ++i) {40Vector2 drawPos;4142drawPos.x = self->finRadius * RSDK.Sin512(self->rotation) + self->position.x;43drawPos.y = self->position.y - self->finRadius * RSDK.Cos512(self->rotation);44self->finAnimator.frameID = ((self->rotation + 16) >> 5) & 0xF;45RSDK.DrawSprite(&self->finAnimator, &drawPos, false);4647drawPos.x = ((5 * self->finRadius * RSDK.Sin512(self->rotation)) >> 3) + self->position.x;48drawPos.y = self->position.y - ((5 * self->finRadius * RSDK.Cos512(self->rotation)) >> 3);49RSDK.DrawSprite(&self->armAnimator, &drawPos, false);5051self->rotation += 64;52}5354RSDK.DrawSprite(&self->bodyAnimator, NULL, false);5556if (self->invincibilityTimer & 1)57RSDK.CopyPalette(5, 128, 4, 128, 128);5859RSDK.SetActivePalette(0, 0, ScreenInfo[SceneInfo->currentScreenID].size.y);60}6162void PhantomShinobi_Create(void *data)63{64RSDK_THIS(PhantomShinobi);6566if (!SceneInfo->inEditor) {67self->visible = true;68self->drawFX = FX_ROTATE | FX_FLIP;69self->drawGroup = Zone->objectDrawGroup[0];70self->active = ACTIVE_NEVER;71self->updateRange.x = 0x800000;72self->updateRange.y = 0x800000;73self->collisionLayers = Zone->collisionLayers;74self->startPos = self->position;75self->tileCollisions = TILECOLLISION_DOWN;76self->finRadius = 0x1600;7778PhantomShinobi_ResetStates();7980RSDK.SetSpriteAnimation(PhantomShinobi->aniFrames, 0, &self->bodyAnimator, true, 0);81RSDK.SetSpriteAnimation(PhantomShinobi->aniFrames, 0, &self->armAnimator, true, 1);82RSDK.SetSpriteAnimation(PhantomShinobi->aniFrames, 1, &self->finAnimator, true, 0);83}84}8586void PhantomShinobi_StageLoad(void)87{88PhantomShinobi->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomShinobi.bin", SCOPE_STAGE);8990PhantomShinobi->hitbox.left = -24;91PhantomShinobi->hitbox.top = -24;92PhantomShinobi->hitbox.right = 24;93PhantomShinobi->hitbox.bottom = 24;9495PhantomShinobi->sfxBlade = RSDK.GetSfx("TMZ3/ShinobiBlade.wav");96PhantomShinobi->sfxHit = RSDK.GetSfx("TMZ3/ShinobiHit.wav");9798Soundboard_LoadSfx("TMZ3/ShinobiBlade.wav", true, PhantomShinobi_SfxCheck_ShinobiBlade, StateMachine_None);99}100101void PhantomShinobi_CheckPlayerCollisions(void)102{103RSDK_THIS(PhantomShinobi);104105foreach_active(Player, playerLoop)106{107if (!self->invincibilityTimer && Player_CheckBadnikTouch(playerLoop, self, &PhantomShinobi->hitbox)108&& Player_CheckBossHit(playerLoop, self)) {109PhantomShinobi_Hit();110foreach_return;111}112}113114int32 storeX = self->position.x;115int32 storeY = self->position.y;116int32 angle = self->rotStore;117118foreach_active(Player, player)119{120for (int32 f = 0; f < 8; ++f) {121self->position.x = storeX + self->finRadius * RSDK.Sin512(angle);122self->position.y = storeY - self->finRadius * RSDK.Cos512(angle);123if (RSDK.CheckObjectCollisionTouchCircle(player, 0xC0000, self, 0x80000)) {124Player_Hurt(player, self);125}126127angle += 0x40;128}129}130131self->position.x = storeX;132self->position.y = storeY;133}134135void PhantomShinobi_Hit(void)136{137RSDK_THIS(PhantomShinobi);138139self->invincibilityTimer = 48;140RSDK.PlaySfx(PhantomEgg->sfxHit, false, 255);141}142143void PhantomShinobi_HandleTileCollisions(void)144{145RSDK_THIS(PhantomShinobi);146147if (self->onGround) {148self->finRadius += (0x1000 - self->finRadius) >> 3;149if (!self->prevOnGround) {150if (self->numBounces > 0) {151self->velocity.y = -0x30000;152self->numBounces--;153self->onGround = false;154}155}156}157else {158self->velocity.y += 0x3800;159if (self->velocity.y > 0xC0000)160self->velocity.y = 0xC0000;161162self->finRadius += (0x1600 - self->finRadius) >> 3;163}164165int32 size = self->finRadius / 88;166167self->outerBox.left = -size;168self->outerBox.top = -size;169self->outerBox.right = size;170self->outerBox.bottom = size;171172self->innerBox.left = 2 - size;173self->innerBox.top = -size;174self->innerBox.right = size - 2;175self->innerBox.bottom = size;176177self->prevOnGround = self->onGround;178RSDK.ProcessObjectMovement(self, &self->outerBox, &self->innerBox);179}180181void PhantomShinobi_ResetStates(void)182{183RSDK_THIS(PhantomShinobi);184185self->position = self->startPos;186self->position.y -= 0x400000;187self->finRadius = 0;188self->attackCount = 0;189190self->state = PhantomShinobi_State_EnterShinobi;191self->direction = RSDK.Rand(FLIP_NONE, FLIP_X + 1);192}193194void PhantomShinobi_State_EnterShinobi(void)195{196RSDK_THIS(PhantomShinobi);197198if (self->position.y < self->startPos.y) {199self->position.y += 0x8000;200}201202if (++self->timer >= 128) {203self->finRadius += 0x100;204if (self->finRadius >= 0x1600) {205self->timer = 0;206self->finRadius = 0x1600;207self->state = PhantomShinobi_State_AttackDelay;208}209}210}211212void PhantomShinobi_State_AttackDelay(void)213{214RSDK_THIS(PhantomShinobi);215216if (++self->timer == 16) {217self->timer = 0;218self->state = PhantomShinobi_State_SetupAttack;219}220}221222void PhantomShinobi_State_SetupAttack(void)223{224RSDK_THIS(PhantomShinobi);225226if (self->direction) {227if (self->rotSpeed <= -0x600) {228self->velocity.x -= 0x20000;229self->rotSpeed = -0x600;230self->state = PhantomShinobi_State_Moving;231self->onGround = false;232self->numBounces = 1;233self->velocity.y = -0x30000;234}235else {236self->rotSpeed -= 12;237}238}239else {240if (self->rotSpeed >= 0x600) {241self->rotSpeed = 0x600;242self->velocity.x = 0x20000;243self->state = PhantomShinobi_State_Moving;244self->onGround = false;245self->numBounces = 1;246self->velocity.y = -0x30000;247}248else {249self->rotSpeed += 12;250}251}252253PhantomShinobi_CheckPlayerCollisions();254}255256void PhantomShinobi_State_Moving(void)257{258RSDK_THIS(PhantomShinobi);259260PhantomShinobi_HandleTileCollisions();261262if (self->onGround && !self->prevOnGround) {263self->groundVel = self->direction == FLIP_NONE ? 0x80000 : -0x80000;264}265266if (!self->groundVel) {267self->onGround = false;268self->velocity.x = self->direction == FLIP_NONE ? -0x38000 : 0x38000;269self->velocity.y = -0x40000;270271self->numBounces = 1;272self->direction ^= FLIP_X;273self->state = PhantomShinobi_State_PrepareFinAttack;274}275276PhantomShinobi_CheckPlayerCollisions();277}278279void PhantomShinobi_State_PrepareFinAttack(void)280{281RSDK_THIS(PhantomShinobi);282283if (self->velocity.y < 0x20000) {284self->velocity.y += 0x2800;285self->position.x += self->velocity.x;286self->position.y += self->velocity.y;287}288289if (abs(self->rotSpeed) <= 256) {290if (!(self->rotStore & 0x1C00)) {291self->rotSpeed = 0;292self->rotStore = 0;293self->timer = 0;294self->state = PhantomShinobi_State_ExtendFins;295}296}297else {298self->rotSpeed -= (self->rotSpeed >> 5);299}300301PhantomShinobi_CheckPlayerCollisions();302}303304void PhantomShinobi_State_ExtendFins(void)305{306RSDK_THIS(PhantomShinobi);307308self->finRadius -= 128;309if (++self->timer == 24) {310self->timer = 0;311self->velocity.x = 0x400;312313RSDK.PlaySfx(PhantomShinobi->sfxHit, false, 255);314self->state = PhantomShinobi_State_RetractFins;315}316317PhantomShinobi_CheckPlayerCollisions();318}319320void PhantomShinobi_State_RetractFins(void)321{322RSDK_THIS(PhantomShinobi);323324self->velocity.x -= 16;325if (self->velocity.x < -0xC00)326self->velocity.x = -0xC00;327328self->finRadius += self->velocity.x;329330if (self->velocity.x < 0 && self->finRadius < 0x1600) {331self->finRadius = 0x1600;332333if (++self->attackCount == 2) {334PhantomEgg_SetupWarpFX();335self->timer = 0;336self->state = PhantomShinobi_State_FinishedAttack;337}338else {339self->state = PhantomShinobi_State_AttackDelay;340}341}342343PhantomShinobi_CheckPlayerCollisions();344}345346void PhantomShinobi_State_FinishedAttack(void)347{348RSDK_THIS(PhantomShinobi);349350if (self->finRadius > 0)351self->finRadius -= (self->finRadius >> 4);352353if (++self->timer == 60) {354PhantomShinobi_ResetStates();355self->active = ACTIVE_NEVER;356}357}358359bool32 PhantomShinobi_SfxCheck_ShinobiBlade(void)360{361foreach_active(PhantomShinobi, shinobi)362{363if (shinobi->state == PhantomShinobi_State_Moving) {364foreach_return true;365}366}367368return false;369}370371#if GAME_INCLUDE_EDITOR372void PhantomShinobi_EditorDraw(void)373{374RSDK_THIS(PhantomShinobi);375376self->finRadius = 0x1600;377378RSDK.SetSpriteAnimation(PhantomShinobi->aniFrames, 0, &self->bodyAnimator, false, 0);379RSDK.SetSpriteAnimation(PhantomShinobi->aniFrames, 0, &self->armAnimator, false, 1);380RSDK.SetSpriteAnimation(PhantomShinobi->aniFrames, 1, &self->finAnimator, false, 0);381382PhantomShinobi_Draw();383}384385void PhantomShinobi_EditorLoad(void) { PhantomShinobi->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomShinobi.bin", SCOPE_STAGE); }386#endif387388void PhantomShinobi_Serialize(void) {}389390391