Path: blob/master/SonicMania/Objects/PGZ/Acetone.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: Acetone Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectAcetone *Acetone;1011// This object goes completely unused in regular gameplay12// afterall, so does the entire PGZ1 ink gimmick13// and even then, this is basically just a tweaked copy of FrostThrower anyways1415void Acetone_Update(void)16{17RSDK_THIS(Acetone);18StateMachine_Run(self->state);19}2021void Acetone_LateUpdate(void) {}2223void Acetone_StaticUpdate(void) {}2425void Acetone_Draw(void)26{27RSDK_THIS(Acetone);2829RSDK.DrawSprite(&self->dispenseAnimator, NULL, false);3031if (self->isActive)32Acetone_DrawGustFX();33}3435void Acetone_Create(void *data)36{37RSDK_THIS(Acetone);3839self->active = ACTIVE_BOUNDS;40self->visible = true;41self->drawFX = FX_FLIP;42self->drawGroup = Zone->playerDrawGroup[0] + 1;43self->updateRange.x = 0x100000;44self->updateRange.y = 0x100000;4546self->hitbox.left = -14;47self->hitbox.right = 15;48self->maxGustCount[0] = 2;49self->maxGustCount[1] = 2;50self->maxGustCount[2] = 3;51self->maxGustCount[3] = 3;5253Acetone_HandleGustCount();54Acetone_HandleGustPos();5556RSDK.SetSpriteAnimation(Acetone->aniFrames, 0, &self->dispenseAnimator, true, 0);57RSDK.SetSpriteAnimation(Acetone->aniFrames, 1, &self->gustAnimator, true, 0);5859self->state = Acetone_State_AwaitInterval;60}6162void Acetone_StageLoad(void)63{64if (RSDK.CheckSceneFolder("PSZ1"))65Acetone->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Acetone.bin", SCOPE_STAGE);6667Acetone->sfxFrostThrower = RSDK.GetSfx("PSZ/FrostThrower.wav");68Acetone->sfxFreeze = RSDK.GetSfx("PSZ/Freeze.wav");69}7071void Acetone_DrawGustFX(void)72{73RSDK_THIS(Acetone);7475int32 pos = 0;76for (int32 i = 0; i < 4; ++i) {77int32 count = MIN(self->gustCount[i], 3);7879RSDK.SetSpriteAnimation(Acetone->aniFrames, 1, &self->gustAnimator, true, i);80for (int32 p = 0; p < count; ++p) {81Vector2 drawPos;82drawPos.x = self->position.x + self->gustPos[pos + p].x;83drawPos.y = self->position.y + self->gustPos[pos + p].y;84RSDK.DrawSprite(&self->gustAnimator, &drawPos, false);85}8687pos += 3;88}89}9091void Acetone_CheckPlayerCollisions(void)92{93RSDK_THIS(Acetone);9495foreach_active(Player, player)96{97if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {98switch (player->characterID) {99// This actually wont work on sonic specifically, it uses the "old" sonic palette100// This palette starts at index 2, instead of index 64 like usual101// To fix this up to work as "intended", simply replace the "PLAYER_PALETTE_INDEX_SONIC_OLD"s with "PLAYER_PALETTE_INDEX_SONIC"102case ID_SONIC: RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_SONIC_OLD, 0, PLAYER_PALETTE_INDEX_SONIC_OLD, 6); break;103104case ID_TAILS: RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_TAILS, 0, PLAYER_PALETTE_INDEX_TAILS, PLAYER_PRIMARY_COLOR_COUNT); break;105106case ID_KNUCKLES:107RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_KNUX, 0, PLAYER_PALETTE_INDEX_KNUX, PLAYER_PRIMARY_COLOR_COUNT);108break;109110// This is an unused object that was scrapped before plus was created, so there's no mighty/ray code111// I've created a mock-up of what mighty/ray code could've looked like, had it been implemented:112// case ID_MIGHTY: RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_MIGHTY, 0, PLAYER_PALETTE_INDEX_MIGHTY, PLAYER_PRIMARY_COLOR_COUNT); break;113// case ID_RAY: RSDK.CopyPalette(6, PLAYER_PALETTE_INDEX_RAY, 0, PLAYER_PALETTE_INDEX_RAY, PLAYER_PRIMARY_COLOR_COUNT); break;114}115116Ink->playerColors[RSDK.GetEntitySlot(player)] = 0;117}118}119}120121void Acetone_HandleGustCount(void)122{123RSDK_THIS(Acetone);124125for (int32 i = 0; i < 4; ++i) {126self->gustCount[i] = self->maxGustCount[i];127128if (self->maxGustCount[i] > 1) {129if (RSDK.Rand(0, 10) <= 6)130self->gustCount[i] = RSDK.Rand(1, self->maxGustCount[i]);131}132}133}134135void Acetone_HandleGustPos(void)136{137RSDK_THIS(Acetone);138int32 pos = 0;139140int32 yMin[] = { 2, 20, 45, 55 };141int32 yMax[] = { 22, 45, 62, 78 };142int32 xMin[] = { -3, -5, -7, -9 };143int32 xMax[] = { 3, 5, 7, 9 };144145for (int32 i = 0; i < 4; ++i) {146for (int32 p = 0; p < self->gustCount[i]; ++p) {147self->gustPos[pos + p].x = RSDK.Rand(xMin[i], xMax[i]) << 16;148self->gustPos[pos + p].y = RSDK.Rand(yMin[i], yMax[i]) << 16;149}150151pos += 3;152}153}154155void Acetone_State_AwaitInterval(void)156{157RSDK_THIS(Acetone);158159if (!((Zone->timer + self->intervalOffset) % self->interval)) {160self->active = ACTIVE_NORMAL;161self->timer = 0;162self->isActive = true;163self->state = Acetone_State_Dispensing;164RSDK.PlaySfx(Acetone->sfxFrostThrower, false, 0xFF);165}166}167168void Acetone_State_Dispensing(void)169{170RSDK_THIS(Acetone);171172self->hitbox.top = 0;173if (self->timer >= 20)174self->hitbox.bottom = 80;175else176self->hitbox.bottom = 4 * self->timer;177178Acetone_CheckPlayerCollisions();179180if (self->timer > 3)181self->maxGustCount[0] = 2;182else183self->maxGustCount[0] = 1;184185if (self->timer > 8)186self->maxGustCount[1] = 2;187else if (self->timer > 5)188self->maxGustCount[1] = 1;189else190self->maxGustCount[1] = 0;191192if (self->timer > 16)193self->maxGustCount[2] = 3;194else if (self->timer > 14)195self->maxGustCount[2] = 2;196else if (self->timer > 12)197self->maxGustCount[2] = 1;198else199self->maxGustCount[2] = 0;200201if (self->timer > 19)202self->maxGustCount[3] = 3;203else if (self->timer > 17)204self->maxGustCount[3] = 2;205else if (self->timer > 15)206self->maxGustCount[3] = 1;207else208self->maxGustCount[3] = 0;209210Acetone_HandleGustCount();211Acetone_HandleGustPos();212213if (++self->timer >= self->duration) {214self->state = Acetone_State_StopDispensing;215self->timer = 0;216}217}218219void Acetone_State_StopDispensing(void)220{221RSDK_THIS(Acetone);222223self->hitbox.top = 4 * self->timer;224self->hitbox.bottom = 80;225226Acetone_CheckPlayerCollisions();227228if (self->timer > 8)229self->maxGustCount[0] = 0;230else if (self->timer > 5)231self->maxGustCount[0] = 1;232else233self->maxGustCount[0] = 2;234235if (self->timer > 8)236self->maxGustCount[1] = 0;237else if (self->timer > 5)238self->maxGustCount[1] = 1;239else240self->maxGustCount[1] = 2;241242if (self->timer > 19)243self->maxGustCount[2] = 0;244else if (self->timer > 17)245self->maxGustCount[2] = 1;246else if (self->timer > 15)247self->maxGustCount[2] = 2;248else249self->maxGustCount[2] = 3;250251if (self->timer > 16)252self->maxGustCount[3] = 0;253else if (self->timer > 14)254self->maxGustCount[3] = 1;255else if (self->timer > 12)256self->maxGustCount[3] = 2;257else258self->maxGustCount[3] = 3;259260Acetone_HandleGustCount();261Acetone_HandleGustPos();262263if (self->timer++ >= 20) {264self->active = ACTIVE_BOUNDS;265self->isActive = false;266self->state = Acetone_State_AwaitInterval;267self->timer = 0;268}269}270271#if GAME_INCLUDE_EDITOR272void Acetone_EditorDraw(void)273{274RSDK_THIS(Acetone);275276RSDK.SetSpriteAnimation(Acetone->aniFrames, 0, &self->dispenseAnimator, true, 0);277RSDK.SetSpriteAnimation(Acetone->aniFrames, 1, &self->gustAnimator, true, 0);278279Acetone_Draw();280}281282void Acetone_EditorLoad(void) { Acetone->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Acetone.bin", SCOPE_STAGE); }283#endif284285void Acetone_Serialize(void)286{287RSDK_EDITABLE_VAR(Acetone, VAR_UINT16, interval);288RSDK_EDITABLE_VAR(Acetone, VAR_UINT16, intervalOffset);289RSDK_EDITABLE_VAR(Acetone, VAR_UINT16, duration);290}291292293