Path: blob/master/SonicMania/Objects/ERZ/ERZGunner.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: ERZGunner Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectERZGunner *ERZGunner;1011void ERZGunner_Update(void)12{13RSDK_THIS(ERZGunner);1415StateMachine_Run(self->state);16}1718void ERZGunner_LateUpdate(void) {}1920void ERZGunner_StaticUpdate(void) {}2122void ERZGunner_Draw(void)23{24RSDK_THIS(ERZGunner);2526if (self->stateDraw) {27StateMachine_Run(self->stateDraw);28}29else {30RSDK.DrawSprite(&self->mainAnimator, NULL, false);31}32}3334void ERZGunner_Create(void *data)35{36RSDK_THIS(ERZGunner);3738if (!SceneInfo->inEditor) {39self->visible = true;40self->drawGroup = 1;41self->active = ACTIVE_NORMAL;42self->updateRange.x = 0x800000;43self->updateRange.y = 0x800000;4445self->type = VOID_TO_INT(data);46switch (self->type) {47case ERZGUNNER_BOSS:48self->drawFX = FX_FLIP;49RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 0, &self->mainAnimator, true, 0);50RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 1, &self->fxAnimator, true, 0);5152self->originPos = self->position;53self->screenPos = ScreenInfo->position;5455self->stateDraw = ERZGunner_Draw_Gunner;56self->state = ERZGunner_State_Idle;57break;5859case ERZGUNNER_LAUNCHROCKET:60RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 10, &self->mainAnimator, true, 0);61RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 11, &self->fxAnimator, true, 0);6263self->stateDraw = ERZGunner_Draw_RocketLaunch;64self->state = ERZGunner_State_LaunchedRocket;65break;6667case ERZGUNNER_NAPALM_EXPLOSION:68self->originPos = self->position;6970self->state = ERZGunner_State_NapalmExplosion;71break;7273case ERZGUNNER_MORTAR_EXPLOSION:74self->originPos = self->position;7576self->state = ERZGunner_State_MortarExplosion;77break;7879default: break;80}81}82}8384void ERZGunner_StageLoad(void)85{86ERZGunner->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomGunner.bin", SCOPE_STAGE);8788ERZGunner->hitboxNapalm.left = -8;89ERZGunner->hitboxNapalm.top = -4;90ERZGunner->hitboxNapalm.right = 4;91ERZGunner->hitboxNapalm.bottom = 26;9293ERZGunner->hitboxMortar.left = -16;94ERZGunner->hitboxMortar.top = -32;95ERZGunner->hitboxMortar.right = 16;96ERZGunner->hitboxMortar.bottom = -16;9798ERZGunner->hitboxDud.left = -8;99ERZGunner->hitboxDud.top = -8;100ERZGunner->hitboxDud.right = 8;101ERZGunner->hitboxDud.bottom = 8;102}103104void ERZGunner_HandleDudExhaust(void)105{106RSDK_THIS(ERZGunner);107if (!(Zone->timer & 7)) {108int32 x = self->position.x + (RSDK.Sin512(self->rotation) << 11);109int32 y = self->position.y - (RSDK.Cos512(self->rotation) << 11);110EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, x, y);111112RSDK.SetSpriteAnimation(Explosion->aniFrames, 3, &debris->animator, true, 0);113debris->velocity.x = RSDK.Sin512(self->rotation) << 8;114debris->velocity.y = RSDK.Sin512(self->rotation) << 4;115debris->drawGroup = Zone->objectDrawGroup[0];116debris->timer = 41;117}118}119120void ERZGunner_HandleMalfunctionDudExhaust(void)121{122RSDK_THIS(ERZGunner);123124if (Zone->timer & 3) {125if ((Zone->timer & 3) == 2) {126int32 x = self->position.x + (RSDK.Sin512(self->rotation) * 0x600);127int32 y = self->position.y - (RSDK.Cos512(self->rotation) * 0x600);128EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, x, y);129130RSDK.SetSpriteAnimation(Explosion->aniFrames, 2, &debris->animator, true, 0);131debris->drawGroup = Zone->objectDrawGroup[1];132debris->drawFX = FX_SCALE;133debris->timer = 52;134debris->scale.x = (self->scale.x * RSDK.Rand(128, 384)) >> 9;135debris->scale.y = debris->scale.x;136}137}138else {139int32 x = self->position.x + (RSDK.Sin512(self->rotation) << 11);140int32 y = self->position.y - (RSDK.Cos512(self->rotation) << 11);141EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, x, y);142143RSDK.SetSpriteAnimation(Explosion->aniFrames, 3, &debris->animator, true, 0);144debris->velocity.x = RSDK.Sin512(self->rotation) << 8;145debris->velocity.y = RSDK.Sin512(self->rotation) << 4;146debris->drawGroup = Zone->objectDrawGroup[0];147debris->drawFX = FX_SCALE;148debris->timer = 41;149debris->scale.y = self->scale.x;150}151}152153void ERZGunner_SpawnDust(void)154{155RSDK_THIS(ERZGunner);156157for (int32 i = 0; i < 4; ++i) {158int32 x = self->position.x + RSDK.Rand(-0x100000, 0x100000);159int32 y = self->position.y + RSDK.Rand(-0x280000, -0x180000);160EntityDust *dust = CREATE_ENTITY(Dust, NULL, x, y);161162dust->state = Dust_State_DustPuff;163dust->drawGroup = Zone->objectDrawGroup[1];164}165}166167void ERZGunner_HandleRotations(int32 angle)168{169RSDK_THIS(ERZGunner);170171int32 ang = angle - self->rotation;172173if (abs(angle - self->rotation) >= abs(angle - self->rotation - 0x200)) {174if (abs(angle - self->rotation - 0x200) < abs(angle - self->rotation + 0x200))175self->rotation += (ang - 0x200) >> 4;176else177self->rotation += (ang + 0x200) >> 4;178}179else {180if (abs(angle - self->rotation) < abs(angle - self->rotation + 0x200))181self->rotation += ang >> 4;182else183self->rotation += (ang + 0x200) >> 4;184}185186self->rotation &= 0x1FF;187}188189void ERZGunner_CheckPlayerMissileCollisions(void)190{191RSDK_THIS(ERZGunner);192193foreach_active(Player, player)194{195if (self->parachuteAnimator.frameID > 0 && player->velocity.y >= 0 && Player_CheckBadnikTouch(player, self, &ERZGunner->hitboxMortar)196&& player->animator.animationID != ANI_HURT) {197RSDK.SetSpriteAnimation(-1, 0, &self->parachuteAnimator, true, 0);198player->velocity.y = -0x60000;199200ERZGunner_SpawnDust();201self->state = ERZGunner_State_Napalm;202}203else {204if (Player_CheckBadnikTouch(player, self, &ERZGunner->hitboxNapalm)) {205int32 anim = player->animator.animationID;206if (anim == ANI_JUMP || anim == ANI_SPINDASH || anim == ANI_DROPDASH) {207EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), self->position.x, self->position.y);208explosion->interaction = false;209explosion->drawGroup = Zone->objectDrawGroup[1];210211if (self->parachuteAnimator.animationID == 12 && self->parachuteAnimator.frameID > 0)212ERZGunner_SpawnDust();213214RSDK.PlaySfx(ERZKing->sfxExplosion2, false, 255);215216destroyEntity(self);217foreach_break;218}219}220}221}222}223224void ERZGunner_CheckPlayerExplosionCollisions(void)225{226foreach_active(Player, player)227{228foreach_active(Explosion, explosion)229{230if (explosion->animator.frameID <= 6) {231if (Player_CheckCollisionTouch(player, explosion, &ERZGunner->hitboxDud)) {232Player_ElementHurt(player, explosion, SHIELD_FIRE);233}234}235}236}237}238239void ERZGunner_Hit(EntityERZGunner *entity)240{241RSDK.PlaySfx(ERZKing->sfxHit, false, 255);242entity->invincibilityTimer = 48;243}244245void ERZGunner_Draw_Gunner(void)246{247RSDK_THIS(ERZGunner);248249if (self->invincibilityTimer & 1) {250RSDK.CopyPalette(2, 128, 0, 128, 128);251252RSDK.DrawSprite(&self->mainAnimator, NULL, false);253254self->direction = FLIP_X;255RSDK.DrawSprite(&self->fxAnimator, NULL, false);256257self->direction = FLIP_NONE;258RSDK.DrawSprite(&self->fxAnimator, NULL, false);259260RSDK.CopyPalette(1, 128, 0, 128, 128);261}262else {263RSDK.DrawSprite(&self->mainAnimator, NULL, false);264265self->direction = FLIP_X;266RSDK.DrawSprite(&self->fxAnimator, NULL, false);267268self->direction = FLIP_NONE;269RSDK.DrawSprite(&self->fxAnimator, NULL, false);270}271}272273void ERZGunner_Draw_RocketLaunch(void)274{275RSDK_THIS(ERZGunner);276277EntityERZGunner *parent = self->parent;278279RSDK.SetClipBounds(0, 0, 0, ScreenInfo->size.x, ((self->originPos.y + parent->position.y) >> 16) - ScreenInfo->position.y);280281Vector2 drawPos;282drawPos.x = parent->position.x + self->originPos.x;283drawPos.y = self->position.y;284RSDK.DrawSprite(&self->mainAnimator, &drawPos, false);285286RSDK.SetClipBounds(0, 0, 0, ScreenInfo->size.x, ScreenInfo->size.y);287288drawPos.y = self->originPos.y + parent->position.y;289RSDK.DrawSprite(&self->fxAnimator, &drawPos, false);290}291292void ERZGunner_Draw_Rocket(void)293{294RSDK_THIS(ERZGunner);295296RSDK.DrawSprite(&self->mainAnimator, NULL, false);297RSDK.DrawSprite(&self->tailAnimator, NULL, false);298RSDK.DrawSprite(&self->parachuteAnimator, NULL, false);299}300301void ERZGunner_State_Idle(void)302{303RSDK_THIS(ERZGunner);304305if (self->invincibilityTimer > 0)306self->invincibilityTimer--;307308self->position.x += (ScreenInfo->position.x - self->screenPos.x) << 15;309self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 3, 11);310311self->screenPos = ScreenInfo->position;312313RSDK.ProcessAnimation(&self->fxAnimator);314315self->fireAnimTimer = 8;316if (++self->timer < 120 || RSDK.GetEntityCount(ERZGunner->classID, true) >= 2) {317ERZGunner_CheckPlayerExplosionCollisions();318}319else {320if (++self->rocketLaunchCount == 2) {321foreach_all(ERZKing, king) { king->active = ACTIVE_NORMAL; }322destroyEntity(self);323}324else {325ERZGunner->launchedRocketID = 0;326self->timer = 0;327RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 2, &self->mainAnimator, true, 0);328329self->state = ERZGunner_State_LaunchRockets;330ERZGunner_CheckPlayerExplosionCollisions();331}332}333}334335void ERZGunner_State_LaunchRockets(void)336{337RSDK_THIS(ERZGunner);338339if (self->invincibilityTimer > 0)340self->invincibilityTimer--;341342self->position.x += (ScreenInfo->position.x - self->screenPos.x) << 15;343self->position.y = BadnikHelpers_Oscillate(self->originPos.y, 3, 11);344345self->screenPos = ScreenInfo->position;346347RSDK.ProcessAnimation(&self->mainAnimator);348RSDK.ProcessAnimation(&self->fxAnimator);349350if (++self->timer == 8) {351EntityERZGunner *rocket = CREATE_ENTITY(ERZGunner, INT_TO_VOID(ERZGUNNER_LAUNCHROCKET), self->position.x, self->position.y);352rocket->parent = self;353rocket->originPos.x = ERZGunner->rocketOffsets[self->rocketOffsetID] << 16;354rocket->originPos.y = ERZGunner->rocketOffsets[self->rocketOffsetID + 1] << 16;355rocket->position.x += rocket->originPos.x;356rocket->position.y += rocket->originPos.y + 0x100000;357358self->rocketOffsetID = (self->rocketOffsetID - 14) & 0x1F;359}360361if (self->mainAnimator.frameID == self->mainAnimator.frameCount - 1) {362self->timer = 0;363364if (--self->fireAnimTimer > 0) {365if (!(self->fireAnimTimer & 1))366RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 2, &self->mainAnimator, true, 0);367else368RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 3, &self->mainAnimator, true, 0);369}370else {371RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 0, &self->mainAnimator, true, 0);372self->state = ERZGunner_State_Idle;373}374}375376ERZGunner_CheckPlayerExplosionCollisions();377}378379void ERZGunner_State_LaunchedRocket(void)380{381RSDK_THIS(ERZGunner);382383RSDK.ProcessAnimation(&self->mainAnimator);384RSDK.ProcessAnimation(&self->fxAnimator);385386self->position.y -= 0x80000;387388if (++self->timer == 60) {389EntityERZGunner *parent = self->parent;390391self->timer = 0;392393if ((ERZGunner->launchedRocketID & 3) == 3)394self->type = ERZGUNNER_DUD;395else396self->type = (ERZGunner->launchedRocketID & 1) + ERZGUNNER_MORTAR;397398++ERZGunner->launchedRocketID;399400self->drawGroup = Zone->objectDrawGroup[0];401self->position.y = (ScreenInfo->position.y - 64) << 16;402403bool32 canFire = false;404while (!canFire) {405canFire = true;406self->position.x = parent->position.x + RSDK.Rand(-0x1000000, 0x1000000);407408foreach_active(ERZGunner, gunner)409{410if (gunner != self && gunner->type >= ERZGUNNER_MORTAR) {411int32 dist = abs(gunner->position.x - self->position.x);412if (dist < 0x180000 && gunner->position.y - self->position.y < 0x800000)413canFire = false;414}415}416}417418if (self->type == ERZGUNNER_MORTAR) {419RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 4, &self->mainAnimator, true, 0);420RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 5, &self->tailAnimator, true, 0);421RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 12, &self->parachuteAnimator, true, 0);422423self->state = ERZGunner_State_Mortar;424self->timer = RSDK.Rand(0, 2) << 8;425self->stateDraw = ERZGunner_Draw_Rocket;426}427else if (self->type == ERZGUNNER_NAPALM) {428RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 6, &self->mainAnimator, true, 0);429RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 7, &self->tailAnimator, true, 0);430431self->state = ERZGunner_State_Napalm;432self->stateDraw = ERZGunner_Draw_Rocket;433}434else if (self->type == ERZGUNNER_DUD) {435RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 8, &self->mainAnimator, true, 0);436RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 9, &self->tailAnimator, true, 0);437438self->position.x = parent->position.x;439self->drawFX = FX_ROTATE;440self->state = ERZGunner_State_Dud_Active;441self->velocity.x = (Zone->timer & 1) ? -0x40000 : 0x40000;442self->stateDraw = ERZGunner_Draw_Rocket;443}444}445}446447void ERZGunner_State_Mortar(void)448{449RSDK_THIS(ERZGunner);450451RSDK.ProcessAnimation(&self->parachuteAnimator);452RSDK.ProcessAnimation(&self->tailAnimator);453454if (self->parachuteAnimator.frameID) {455self->drawFX = FX_ROTATE;456if (self->velocity.y > 0xC000)457self->velocity.y -= 0x3800;458459self->rotation = RSDK.Sin512(self->timer) >> 6;460self->timer = (self->timer + 4) & 0x1FF;461}462else {463if (self->velocity.y < 0x40000)464self->velocity.y += 0x3800;465}466467self->position.y += self->velocity.y;468469ERZGunner_CheckPlayerMissileCollisions();470471if (self->classID) {472if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, true)) {473if (self->type == ERZGUNNER_NAPALM) {474EntityERZGunner *napalm = CREATE_ENTITY(ERZGunner, INT_TO_VOID(ERZGUNNER_NAPALM_EXPLOSION), self->position.x, self->position.y);475napalm->velocity.x = self->velocity.y > 0x20000 ? 0x80000 : 0x40000;476477destroyEntity(self);478}479else {480CREATE_ENTITY(ERZGunner, INT_TO_VOID(ERZGUNNER_MORTAR_EXPLOSION), self->position.x, self->position.y);481482destroyEntity(self);483}484}485}486}487488void ERZGunner_State_Napalm(void)489{490RSDK_THIS(ERZGunner);491492RSDK.ProcessAnimation(&self->tailAnimator);493494if (self->velocity.y < 0x40000)495self->velocity.y += 0x1800;496497self->position.y += self->velocity.y;498499ERZGunner_CheckPlayerMissileCollisions();500501if (self->classID) {502if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, true)) {503if (self->type == ERZGUNNER_NAPALM) {504EntityERZGunner *napalm = CREATE_ENTITY(ERZGunner, INT_TO_VOID(ERZGUNNER_NAPALM_EXPLOSION), self->position.x, self->position.y);505napalm->velocity.x = self->velocity.y > 0x20000 ? 0x80000 : 0x40000;506507destroyEntity(self);508}509else {510CREATE_ENTITY(ERZGunner, INT_TO_VOID(ERZGUNNER_MORTAR_EXPLOSION), self->position.x, self->position.y);511512destroyEntity(self);513}514}515}516}517518void ERZGunner_State_Dud_Active(void)519{520RSDK_THIS(ERZGunner);521522RSDK.ProcessAnimation(&self->tailAnimator);523524EntityERZGunner *parent = self->parent;525526++self->timer;527528self->velocity.x = RSDK.Cos256(self->timer) << 11;529if (self->position.y < parent->position.y - 0x800000) {530if (self->velocity.y < 0x20000)531self->velocity.y += 0x2000;532}533if (self->position.y > parent->position.y - 0x200000) {534if (self->velocity.y > -0x20000)535self->velocity.y -= 0x2000;536}537538self->position.x += self->velocity.x;539self->position.y += self->velocity.y;540541ERZGunner_HandleDudExhaust();542543int32 angle = RSDK.ATan2(self->velocity.y, -self->velocity.x);544ERZGunner_HandleRotations(2 * angle);545546if (self->timer == 320) {547EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ITEMBOX), self->position.x, self->position.y);548explosion->interaction = false;549explosion->drawGroup = Zone->objectDrawGroup[1];550destroyEntity(self);551}552else {553foreach_active(Player, player)554{555if (Player_CheckBadnikTouch(player, self, &ERZGunner->hitboxDud)) {556self->angle = self->rotation << 8;557self->timer = 0;558self->drawFX = FX_SCALE | FX_ROTATE;559self->groundVel = 0x4000;560self->scale.x = 0x200;561self->scale.y = 0x200;562self->state = ERZGunner_State_Dud_HitByPlayer;563RSDK.PlaySfx(ERZKing->sfxHit, false, 255);564}565}566}567}568569void ERZGunner_State_Dud_HitByPlayer(void)570{571RSDK_THIS(ERZGunner);572573RSDK.ProcessAnimation(&self->tailAnimator);574575self->angle += self->groundVel;576self->rotation = self->angle >> 8;577self->groundVel -= (self->groundVel >> 3);578579ERZGunner_HandleDudExhaust();580581if (self->groundVel < 128)582self->state = ERZGunner_State_Dud_Malfunction;583}584585void ERZGunner_State_Dud_Malfunction(void)586{587RSDK_THIS(ERZGunner);588589RSDK.ProcessAnimation(&self->tailAnimator);590591EntityERZGunner *parent = self->parent;592593int32 angle = RSDK.ATan2((parent->position.y - self->position.y) >> 16, -((parent->position.x - self->position.x) >> 16));594ERZGunner_HandleRotations(2 * angle);595596self->rotation &= 0x1FF;597self->position.x -= RSDK.Sin512(self->rotation) << 9;598self->position.y += RSDK.Cos512(self->rotation) << 9;599self->scale.x -= 6;600self->scale.y = self->scale.x;601602ERZGunner_HandleMalfunctionDudExhaust();603604if (self->scale.x < 0x80) {605ERZGunner_Hit(parent);606self->position.x = parent->position.x;607self->position.y = parent->position.y;608self->visible = false;609self->state = ERZGunner_State_Dud_Explode;610}611}612613void ERZGunner_State_Dud_Explode(void)614{615RSDK_THIS(ERZGunner);616617if (!(Zone->timer % 3) && !(Zone->timer & 4)) {618int32 x = self->position.x + RSDK.Rand(-0x100000, 0x100000);619int32 y = self->position.y + RSDK.Rand(-0x100000, 0x100000);620EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID((RSDK.Rand(0, 256) > 192) + EXPLOSION_BOSS), x, y);621622explosion->interaction = false;623explosion->drawGroup = 1;624explosion->scale = self->scale;625}626627if (++self->timer == 16)628destroyEntity(self);629}630631void ERZGunner_State_NapalmExplosion(void)632{633RSDK_THIS(ERZGunner);634635if (!(Zone->timer & 3)) {636CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSS), self->originPos.x - self->napalmExplosionPos, self->position.y);637CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_BOSS), self->originPos.x + self->napalmExplosionPos, self->position.y);638}639640self->napalmExplosionPos += self->velocity.x;641642if (++self->timer == 16)643destroyEntity(self);644}645646void ERZGunner_State_MortarExplosion(void)647{648RSDK_THIS(ERZGunner);649650if (!(Zone->timer & 3))651CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ITEMBOX), self->position.x, self->position.y);652653self->position.y -= 0x40000;654655if (++self->timer == 16)656destroyEntity(self);657}658659#if GAME_INCLUDE_EDITOR660void ERZGunner_EditorDraw(void)661{662RSDK_THIS(ERZGunner);663664self->drawFX = FX_FLIP;665RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 0, &self->mainAnimator, false, 0);666RSDK.SetSpriteAnimation(ERZGunner->aniFrames, 1, &self->fxAnimator, false, 0);667668self->originPos = self->position;669self->screenPos = ScreenInfo->position;670671ERZGunner_Draw_Gunner();672}673674void ERZGunner_EditorLoad(void) { ERZGunner->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomGunner.bin", SCOPE_STAGE); }675#endif676677void ERZGunner_Serialize(void) {}678679680