Path: blob/master/SonicMania/Objects/Global/ItemBox.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: ItemBox Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectItemBox *ItemBox;1011void ItemBox_Update(void)12{13RSDK_THIS(ItemBox);1415StateMachine_Run(self->state);1617#if MANIA_USE_PLUS18if (self->type == ITEMBOX_STOCK) {19if (self->contentsAnimator.animationID == 2 || self->contentsAnimator.animationID == 7 || self->contentsAnimator.animationID == 8) {20if (globals->characterFlags == 0x1F && globals->gameMode == MODE_ENCORE) {21RSDK.SetSpriteAnimation(ItemBox->aniFrames, 8, &self->contentsAnimator, false, 0);22}23else {24RSDK.SetSpriteAnimation(ItemBox->aniFrames, 7, &self->contentsAnimator, false, 0);25if (globals->gameMode == MODE_ENCORE) {26int32 id = 0;27while ((1 << self->contentsAnimator.frameID) & globals->characterFlags) {28if (++self->contentsAnimator.frameID > 4)29self->contentsAnimator.frameID = 0;30if (++id > 5) {31RSDK.SetSpriteAnimation(ItemBox->aniFrames, 8, &self->contentsAnimator, false, 0);32LogHelpers_PrintText("Bad Change Item State");33}34}35}36}37}38}39#endif40}4142void ItemBox_LateUpdate(void) {}4344void ItemBox_StaticUpdate(void)45{46// Handle The Contents outline scrolling47if (!(Zone->timer & 3)) {48RSDK.RotatePalette(0, 60, 63, true);49RSDK.RotatePalette(1, 60, 63, true);50}51}5253void ItemBox_Draw(void)54{55RSDK_THIS(ItemBox);5657if (!self->hidden) {58if (self->isContents) {59if (SceneInfo->currentDrawGroup == Zone->playerDrawGroup[1]) {60self->drawFX = FX_NONE;61RSDK.DrawSprite(&self->contentsAnimator, &self->contentsPos, false);62}63else {64self->drawFX = FX_FLIP;65self->inkEffect = INK_NONE;66RSDK.DrawSprite(&self->boxAnimator, NULL, false);6768RSDK.AddDrawListRef(Zone->playerDrawGroup[1], SceneInfo->entitySlot);69}70}71else {72self->inkEffect = INK_NONE;73RSDK.DrawSprite(&self->boxAnimator, NULL, false);74RSDK.DrawSprite(&self->contentsAnimator, &self->contentsPos, false);7576self->inkEffect = INK_ADD;77RSDK.DrawSprite(&self->overlayAnimator, NULL, false);7879self->inkEffect = INK_NONE;80RSDK.DrawSprite(&self->debrisAnimator, NULL, false);81}82}83}8485void ItemBox_Create(void *data)86{87RSDK_THIS(ItemBox);8889if (data)90self->type = VOID_TO_INT(data);9192if (self->state != ItemBox_State_Broken) {93RSDK.SetSpriteAnimation(ItemBox->aniFrames, 0, &self->boxAnimator, true, 0);94RSDK.SetSpriteAnimation(ItemBox->aniFrames, 2, &self->contentsAnimator, true, 0);95RSDK.SetSpriteAnimation(ItemBox->aniFrames, 3, &self->overlayAnimator, true, 0);96RSDK.SetSpriteAnimation(ItemBox->aniFrames, 4, &self->debrisAnimator, true, 0);9798EntityPlayer *player = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);99switch (self->type) {100case ITEMBOX_1UP_SONIC:101case ITEMBOX_1UP_TAILS:102case ITEMBOX_1UP_KNUX:103#if MANIA_USE_PLUS104case ITEMBOX_1UP_MIGHTY:105case ITEMBOX_1UP_RAY:106#endif107if (globals->gameMode == MODE_TIMEATTACK) {108self->type = ITEMBOX_RING;109}110#if MANIA_USE_PLUS111else if (globals->gameMode == MODE_ENCORE) {112self->type = ITEMBOX_STOCK;113}114#endif115else {116switch (player->characterID) {117case ID_SONIC: self->type = ITEMBOX_1UP_SONIC; break;118case ID_TAILS: self->type = ITEMBOX_1UP_TAILS; break;119case ID_KNUCKLES: self->type = ITEMBOX_1UP_KNUX; break;120#if MANIA_USE_PLUS121case ID_MIGHTY: self->type = ITEMBOX_1UP_MIGHTY; break;122case ID_RAY: self->type = ITEMBOX_1UP_RAY; break;123#endif124default: break;125}126}127self->contentsAnimator.frameID = self->type;128break;129130#if MANIA_USE_PLUS131case ITEMBOX_SWAP:132case ITEMBOX_RANDOM:133if (globals->gameMode == MODE_ENCORE || globals->gameMode == MODE_COMPETITION)134self->contentsAnimator.frameID = self->type;135else136destroyEntity(self);137#endif138break;139140default: self->contentsAnimator.frameID = self->type; break;141}142}143144self->drawFX = FX_FLIP;145if (!SceneInfo->inEditor) {146self->direction *= FLIP_Y;147self->active = ACTIVE_BOUNDS;148self->updateRange.x = TO_FIXED(64);149self->updateRange.y = TO_FIXED(64);150self->visible = true;151if (self->planeFilter > 0 && ((uint8)self->planeFilter - 1) & 2)152self->drawGroup = Zone->objectDrawGroup[1];153else154self->drawGroup = Zone->objectDrawGroup[0];155156self->alpha = 0xFF;157if (self->state == ItemBox_State_Broken) {158RSDK.SetSpriteAnimation(ItemBox->aniFrames, 1, &self->boxAnimator, true, self->boxAnimator.frameID);159}160else if (self->hidden) {161self->state = StateMachine_None;162}163else if (self->isFalling) {164self->active = ACTIVE_NORMAL;165self->state = ItemBox_State_Falling;166}167else if (LRZConvItem && self->lrzConvPhys) {168self->active = ACTIVE_NORMAL;169self->state = ItemBox_State_Conveyor;170}171else {172self->state = ItemBox_State_Idle;173}174}175}176177void ItemBox_StageLoad(void)178{179ItemBox->aniFrames = RSDK.LoadSpriteAnimation("Global/ItemBox.bin", SCOPE_STAGE);180181ItemBox->hitboxItemBox.left = -15;182ItemBox->hitboxItemBox.top = -16;183ItemBox->hitboxItemBox.right = 15;184ItemBox->hitboxItemBox.bottom = 16;185186ItemBox->hitboxHidden.left = -15;187ItemBox->hitboxHidden.top = -24;188ItemBox->hitboxHidden.right = 15;189ItemBox->hitboxHidden.bottom = 16;190191DEBUGMODE_ADD_OBJ(ItemBox);192193if (globals->gameMode == MODE_COMPETITION) {194if (globals->itemMode == ITEMS_RANDOM) {195foreach_all(ItemBox, entity) { entity->type = ITEMBOX_RANDOM; }196}197else if (globals->itemMode == ITEMS_TELEPORT) {198foreach_all(ItemBox, entity) { entity->type = ITEMBOX_SWAP; }199}200}201202ItemBox->sfxDestroy = RSDK.GetSfx("Global/Destroy.wav");203ItemBox->sfxTeleport = RSDK.GetSfx("Global/Teleport.wav");204ItemBox->sfxHyperRing = RSDK.GetSfx("Global/HyperRing.wav");205#if MANIA_USE_PLUS206ItemBox->sfxPowerDown = RSDK.GetSfx("Stage/PowerDown.wav");207ItemBox->sfxRecovery = RSDK.GetSfx("Global/Recovery.wav");208#endif209}210211void ItemBox_DebugDraw(void)212{213RSDK_THIS(ItemBox);214215DebugMode->itemTypeCount = ITEMBOX_COUNT;216217RSDK.SetSpriteAnimation(ItemBox->aniFrames, 0, &DebugMode->animator, true, 0);218RSDK.DrawSprite(&DebugMode->animator, NULL, false);219220RSDK.SetSpriteAnimation(ItemBox->aniFrames, 2, &DebugMode->animator, true, DebugMode->itemType);221222Vector2 drawPos;223drawPos.x = self->position.x;224drawPos.y = self->position.y - TO_FIXED(3);225RSDK.DrawSprite(&DebugMode->animator, &drawPos, false);226}227void ItemBox_DebugSpawn(void)228{229RSDK_THIS(DebugMode);230231EntityItemBox *itemBox = CREATE_ENTITY(ItemBox, NULL, self->position.x, self->position.y);232itemBox->type = DebugMode->itemType;233itemBox->contentsAnimator.frameID = DebugMode->itemType;234}235236void ItemBox_State_Broken(void)237{238RSDK_THIS(ItemBox);239240if (LRZConvItem)241LRZConvItem_HandleLRZConvPhys(self);242else243ItemBox_HandleFallingCollision();244}245void ItemBox_State_Break(void)246{247RSDK_THIS(ItemBox);248249if (LRZConvItem && self->lrzConvPhys)250LRZConvItem_HandleLRZConvPhys(self);251else252ItemBox_HandleFallingCollision();253254if (self->contentsSpeed < 0) {255self->contentsPos.y += self->contentsSpeed;256self->contentsSpeed += 0x1800;257}258259if (self->contentsSpeed >= 0) {260self->contentsSpeed = 0;261262ItemBox_GivePowerup();263264RSDK.SetSpriteAnimation(ItemBox->aniFrames, 5, &self->contentsAnimator, true, 0);265self->state = ItemBox_State_IconFinish;266}267}268269void ItemBox_State_IconFinish(void)270{271RSDK_THIS(ItemBox);272273if (LRZConvItem && self->lrzConvPhys)274LRZConvItem_HandleLRZConvPhys(self);275else276ItemBox_HandleFallingCollision();277278RSDK.ProcessAnimation(&self->contentsAnimator);279280if (self->contentsAnimator.frameID == self->contentsAnimator.frameCount - 1) {281RSDK.SetSpriteAnimation(-1, 0, &self->contentsAnimator, true, 0);282self->state = ItemBox_State_Broken;283}284}285286void ItemBox_State_Idle(void)287{288RSDK_THIS(ItemBox);289290self->contentsPos.x = self->position.x;291292if (self->direction == FLIP_NONE)293self->contentsPos.y = self->position.y - TO_FIXED(3);294else295self->contentsPos.y = self->position.y + TO_FIXED(3);296297ItemBox_HandleObjectCollisions();298ItemBox_CheckHit();299300RSDK.ProcessAnimation(&self->overlayAnimator);301302#if MANIA_USE_PLUS303if (self->type == ITEMBOX_STOCK) {304RSDK.ProcessAnimation(&self->contentsAnimator);305306if (!API.CheckDLC(DLC_PLUS) && self->contentsAnimator.frameID >= 3)307self->contentsAnimator.frameID = 0;308}309#endif310311if (self->timer) {312self->timer--;313}314else {315RSDK.ProcessAnimation(&self->debrisAnimator);316317if (!self->debrisAnimator.frameID) {318self->timer = RSDK.Rand(1, 15);319self->debrisAnimator.frameDuration = RSDK.Rand(1, 32);320}321}322}323void ItemBox_State_Falling(void)324{325RSDK_THIS(ItemBox);326327if (ItemBox_HandleFallingCollision())328self->state = ItemBox_State_Idle;329330self->contentsPos.x = self->position.x;331if (self->direction == FLIP_NONE)332self->contentsPos.y = self->position.y - TO_FIXED(3);333else334self->contentsPos.y = self->position.y + TO_FIXED(3);335336ItemBox_CheckHit();337RSDK.ProcessAnimation(&self->overlayAnimator);338339#if MANIA_USE_PLUS340if (self->type == ITEMBOX_STOCK) {341RSDK.ProcessAnimation(&self->contentsAnimator);342343if (!API.CheckDLC(DLC_PLUS) && self->contentsAnimator.frameID >= 3)344self->contentsAnimator.frameID = 0;345}346#endif347348if (self->timer) {349self->timer--;350}351else {352RSDK.ProcessAnimation(&self->debrisAnimator);353354if (!self->debrisAnimator.frameID) {355self->timer = RSDK.Rand(1, 15);356self->debrisAnimator.frameDuration = RSDK.Rand(1, 32);357}358}359}360void ItemBox_State_Conveyor(void)361{362RSDK_THIS(ItemBox);363364self->moveOffset = LRZConvItem_HandleLRZConvPhys(self);365self->contentsPos.x = self->position.x;366if (self->direction == FLIP_NONE)367self->contentsPos.y = self->position.y - TO_FIXED(3);368else369self->contentsPos.y = self->position.y + TO_FIXED(3);370371ItemBox_CheckHit();372373RSDK.ProcessAnimation(&self->overlayAnimator);374375#if MANIA_USE_PLUS376if (self->type == ITEMBOX_STOCK) {377RSDK.ProcessAnimation(&self->contentsAnimator);378379if (!API.CheckDLC(DLC_PLUS) && self->contentsAnimator.frameID >= 3)380self->contentsAnimator.frameID = 0;381}382#endif383384if (self->timer) {385self->timer--;386}387else {388RSDK.ProcessAnimation(&self->debrisAnimator);389390if (!self->debrisAnimator.frameID) {391self->timer = RSDK.Rand(1, 15);392self->debrisAnimator.frameDuration = RSDK.Rand(1, 32);393}394}395}396397void ItemBox_CheckHit(void)398{399RSDK_THIS(ItemBox);400401foreach_active(Player, player)402{403if (self->planeFilter <= 0 || player->collisionPlane == (((uint8)self->planeFilter - 1) & 1)) {404#if MANIA_USE_PLUS405if (player->characterID == ID_MIGHTY && player->jumpAbilityState > 1 && !self->parent) {406if (RSDK.CheckObjectCollisionTouchCircle(player, TO_FIXED(256), self, TO_FIXED(16))) {407if (self->position.y - TO_FIXED(128) < player->position.y && self->state != ItemBox_State_Falling) {408self->active = ACTIVE_NORMAL;409if (!self->lrzConvPhys)410self->state = ItemBox_State_Falling;411self->velocity.y = -TO_FIXED(2);412}413}414}415#endif416417int32 anim = player->animator.animationID;418bool32 attacking =419anim == ANI_JUMP && (player->velocity.y >= 0 || player->onGround || self->direction || player->state == Ice_PlayerState_Frozen);420switch (player->characterID) {421case ID_SONIC: attacking |= anim == ANI_DROPDASH; break;422case ID_KNUCKLES: attacking |= anim == ANI_GLIDE || anim == ANI_GLIDE_SLIDE; break;423#if MANIA_USE_PLUS424case ID_MIGHTY: attacking |= anim == ANI_HAMMERDROP || player->jumpAbilityState > 1; break;425#endif426}427428if (attacking && !player->sidekick) {429if (Player_CheckBadnikTouch(player, self, &ItemBox->hitboxItemBox)) {430ItemBox_Break(self, player);431foreach_break;432}433}434else {435self->position.x -= self->moveOffset.x;436self->position.y -= self->moveOffset.y;437int32 px = player->position.x;438int32 py = player->position.y;439440uint8 side = Player_CheckCollisionBox(player, self, &ItemBox->hitboxItemBox);441442player->position.x = px;443player->position.y = py;444self->position.x += self->moveOffset.x;445self->position.y += self->moveOffset.y;446447if (side == C_BOTTOM) {448self->active = ACTIVE_NORMAL;449450if (!self->lrzConvPhys)451self->state = ItemBox_State_Falling;452453self->velocity.y = -TO_FIXED(2);454455if (!player->onGround)456player->velocity.y = TO_FIXED(2);457}458else if (side == C_TOP) {459player->position.x += self->moveOffset.x;460player->position.y += self->moveOffset.y;461}462463if (Player_CheckCollisionBox(player, self, &ItemBox->hitboxItemBox) == C_BOTTOM) {464if (player->onGround) {465player->position.x = px;466player->position.y = py;467}468}469}470}471}472}473void ItemBox_GivePowerup(void)474{475RSDK_THIS(ItemBox);476477EntityPlayer *player = (EntityPlayer *)self->storedEntity;478479switch (self->type) {480case ITEMBOX_RING: Player_GiveRings(player, 10, true); break;481482case ITEMBOX_BLUESHIELD:483player->shield = SHIELD_BLUE;484Player_ApplyShield(player);485RSDK.PlaySfx(Shield->sfxBlueShield, false, 255);486break;487488case ITEMBOX_BUBBLESHIELD:489player->shield = SHIELD_BUBBLE;490Player_ApplyShield(player);491RSDK.PlaySfx(Shield->sfxBubbleShield, false, 255);492player->drownTimer = 0;493Music_JingleFadeOut(TRACK_DROWNING, false);494break;495496case ITEMBOX_FIRESHIELD:497player->shield = SHIELD_FIRE;498Player_ApplyShield(player);499RSDK.PlaySfx(Shield->sfxFireShield, false, 255);500break;501502case ITEMBOX_LIGHTNINGSHIELD:503player->shield = SHIELD_LIGHTNING;504Player_ApplyShield(player);505RSDK.PlaySfx(Shield->sfxLightningShield, false, 255);506break;507508case ITEMBOX_INVINCIBLE:509if (player->superState == SUPERSTATE_NONE) {510EntityInvincibleStars *invincibleStars = RSDK_GET_ENTITY(Player->playerCount + RSDK.GetEntitySlot(player), InvincibleStars);511RSDK.ResetEntity(invincibleStars, InvincibleStars->classID, player);512player->invincibleTimer = 1260;513Music_PlayJingle(TRACK_INVINCIBLE);514}515break;516517case ITEMBOX_SNEAKERS:518player->speedShoesTimer = 1320;519Player_UpdatePhysicsState(player);520if (player->superState == SUPERSTATE_NONE) {521Music_PlayJingle(TRACK_SNEAKERS);522EntityImageTrail *powerup = RSDK_GET_ENTITY(2 * Player->playerCount + RSDK.GetEntitySlot(player), ImageTrail);523RSDK.ResetEntity(powerup, ImageTrail->classID, player);524}525break;526527case ITEMBOX_1UP_SONIC:528case ITEMBOX_1UP_TAILS:529case ITEMBOX_1UP_KNUX:530#if MANIA_USE_PLUS531case ITEMBOX_1UP_MIGHTY:532case ITEMBOX_1UP_RAY:533#endif534Player_GiveLife(player);535break;536537case ITEMBOX_EGGMAN: Player_Hurt(player, self); break;538539case ITEMBOX_HYPERRING:540RSDK.PlaySfx(ItemBox->sfxHyperRing, false, 255);541player->hyperRing = true;542break;543544case ITEMBOX_SWAP:545#if MANIA_USE_PLUS546if (globals->gameMode == MODE_ENCORE) {547if (!globals->stock || player->animator.animationID == ANI_TRANSFORM) {548RSDK.PlaySfx(Player->sfxSwapFail, false, 255);549}550else {551int32 charID = player->characterID;552Player_ChangeCharacter(player, GET_STOCK_ID(1));553globals->stock >>= 8;554555if (GET_STOCK_ID(1)) {556charID <<= 8;557if (GET_STOCK_ID(2))558charID <<= 8;559}560globals->stock |= charID;561EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), player->position.x, player->position.y);562explosion->drawGroup = Zone->objectDrawGroup[1];563RSDK.PlaySfx(ItemBox->sfxPowerDown, false, 255);564}565}566else if (globals->gameMode != MODE_COMPETITION) {567RSDK.PlaySfx(Player->sfxSwapFail, false, 255);568}569else {570#endif571Zone_StartTeleportAction();572RSDK.PlaySfx(ItemBox->sfxTeleport, false, 255);573#if MANIA_USE_PLUS574}575#endif576break;577578#if MANIA_USE_PLUS579case ITEMBOX_RANDOM: {580uint8 playerIDs[5] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };581uint8 newPlayerIDs[5] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };582583if (player->animator.animationID == ANI_TRANSFORM) {584RSDK.PlaySfx(Player->sfxSwapFail, false, 255);585}586else {587EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);588EntityPlayer *player2 = RSDK_GET_ENTITY(SLOT_PLAYER2, Player);589590playerIDs[0] = HUD_CharacterIndexFromID(player1->characterID);591playerIDs[1] = HUD_CharacterIndexFromID(player2->characterID);592593if (playerIDs[1] == 0xFF) {594RSDK.PlaySfx(Player->sfxSwapFail, false, 255);595}596else {597for (int32 i = 1; i < 4; ++i) {598if (GET_STOCK_ID(i)) {599playerIDs[1 + i] = HUD_CharacterIndexFromID(GET_STOCK_ID(i));600}601}602603globals->stock = ID_NONE;604605int32 tempStock = 0;606int32 p = 0;607for (; p < 5;) {608bool32 inc = true;609if (playerIDs[p] == 0xFF)610break;611612newPlayerIDs[p] = RSDK.Rand(0, 5);613if ((1 << newPlayerIDs[p]) & globals->characterFlags) {614while (true) {615if (!((1 << newPlayerIDs[p]) & tempStock)) {616if (newPlayerIDs[p] != playerIDs[p]) {617tempStock |= 1 << newPlayerIDs[p];618break;619}620else if (p == 4 || playerIDs[p + 1] == 0xFF) {621int32 slot = RSDK.Rand(0, p);622int32 id = newPlayerIDs[slot];623newPlayerIDs[slot] = newPlayerIDs[p];624newPlayerIDs[p] = id;625tempStock |= 1 << newPlayerIDs[slot];626tempStock |= 1 << newPlayerIDs[p];627break;628}629else {630newPlayerIDs[p] = RSDK.Rand(0, 5);631if (!((1 << newPlayerIDs[p]) & globals->characterFlags)) {632inc = false;633break;634}635}636}637else {638newPlayerIDs[p] = RSDK.Rand(0, 5);639if (!((1 << newPlayerIDs[p]) & globals->characterFlags)) {640inc = false;641break;642}643}644}645646if (inc)647++p;648}649}650651for (int32 i = 0; i < p; ++i) {652switch (i) {653case 0: Player_ChangeCharacter(player1, 1 << newPlayerIDs[0]); break;654case 1: Player_ChangeCharacter(player2, 1 << newPlayerIDs[1]); break;655default:656globals->stock <<= 8;657globals->stock |= 1 << newPlayerIDs[i];658break;659}660}661662EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), player1->position.x, player1->position.y);663explosion->drawGroup = Zone->objectDrawGroup[1];664665explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), player2->position.x, player2->position.y);666explosion->drawGroup = Zone->objectDrawGroup[1];667668RSDK.PlaySfx(ItemBox->sfxPowerDown, false, 255);669}670}671break;672}673#endif674675case ITEMBOX_SUPER:676Player_GiveRings(player, 50, false);677Player_TryTransform(player, 0x7F);678break;679680#if MANIA_USE_PLUS681case ITEMBOX_STOCK: {682if (self->contentsAnimator.animationID == 7) {683if (globals->gameMode == MODE_ENCORE) {684if (!((1 << self->contentsAnimator.frameID) & globals->characterFlags) && globals->characterFlags != 0x1F && !GET_STOCK_ID(3)) {685globals->characterFlags |= 1 << self->contentsAnimator.frameID;686EntityPlayer *player2 = RSDK_GET_ENTITY(SLOT_PLAYER2, Player);687if (player2->classID) {688for (int32 s = 0; s < 3; ++s) {689int32 id = HUD_CharacterIndexFromID(GET_STOCK_ID(1 + s));690if (id < 0) {691globals->stock |= (1 << self->contentsAnimator.frameID) << (8 * s);692HUD->stockFlashTimers[1 + s] = 2 * 60;693break;694}695}696}697else {698player2->classID = Player->classID;699Player->respawnTimer = 0;700EntityDust *dust = CREATE_ENTITY(Dust, INT_TO_VOID(1), player2->position.x, player2->position.y);701702dust->visible = false;703dust->active = ACTIVE_NEVER;704dust->isPermanent = true;705dust->position.y = TO_FIXED(ScreenInfo->position.y - 128);706player2->playerID = 1;707EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);708if (player1->state == Player_State_Death || player1->state == Player_State_Drown) {709player2->state = Player_State_EncoreRespawn;710player2->velocity.x = 0;711player2->velocity.y = 0;712player2->position.x = -TO_FIXED(32);713player2->position.y = -TO_FIXED(32);714break;715}716else {717Player_ChangeCharacter(player2, 1 << self->contentsAnimator.frameID);718player2->velocity.x = 0;719player2->velocity.y = 0;720player2->groundVel = 0;721player2->position.x = -TO_FIXED(64);722player2->position.y = -TO_FIXED(64);723player2->angle = 0x80;724if (player2->characterID == ID_TAILS) {725player2->state = Player_State_FlyToPlayer;726}727else {728player2->state = Player_State_ReturnToPlayer;729player2->abilityValues[0] = ((ScreenInfo->position.y + ScreenInfo->size.y + 16) << 16) - player->position.y;730player2->drawFX |= FX_SCALE;731player2->scale.x = 0x400;732player2->scale.y = 0x400;733player2->velocity.y = CLAMP(player2->abilityValues[0] / -12, -0xE0000, -0x68000);734}735player2->abilityPtrs[0] = dust;736player2->abilityValues[0] = 0;737player2->nextAirState = StateMachine_None;738player2->nextGroundState = StateMachine_None;739player2->stateInput = Player_Input_P2_Delay;740player2->tileCollisions = TILECOLLISION_NONE;741player2->interaction = false;742player2->drawGroup = Zone->playerDrawGroup[1];743player2->drownTimer = 0;744player2->active = ACTIVE_NORMAL;745player2->collisionPlane = 0;746player2->collisionMode = CMODE_FLOOR;747player2->collisionLayers = Zone->collisionLayers;748player2->controllerID = CONT_P2;749player2->sidekick = true;750player2->drawFX = FX_FLIP | FX_ROTATE;751player2->visible = true;752HUD->stockFlashTimers[0] = 2 * 60;753}754}755}756757RSDK.PlaySfx(ItemBox->sfxRecovery, false, 255);758}759else {760switch (self->contentsAnimator.frameID) {761case 0: Player_ChangeCharacter(player, ID_SONIC); break;762case 1: Player_ChangeCharacter(player, ID_TAILS); break;763case 2: Player_ChangeCharacter(player, ID_KNUCKLES); break;764case 3: Player_ChangeCharacter(player, ID_MIGHTY); break;765case 4: Player_ChangeCharacter(player, ID_RAY); break;766default: break;767}768769EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ENEMY), player->position.x, player->position.y);770explosion->drawGroup = Zone->objectDrawGroup[1];771RSDK.PlaySfx(ItemBox->sfxPowerDown, false, 255);772}773}774else {775switch (self->contentsAnimator.frameID) {776case 1: self->type = ITEMBOX_BLUESHIELD; break;777case 2: self->type = ITEMBOX_BUBBLESHIELD; break;778case 3: self->type = ITEMBOX_FIRESHIELD; break;779case 4: self->type = ITEMBOX_LIGHTNINGSHIELD; break;780case 5: self->type = ITEMBOX_HYPERRING; break;781case 6: self->type = ITEMBOX_SWAP; break;782case 7: self->type = ITEMBOX_RANDOM; break;783default: self->type = ITEMBOX_RING; break;784}785786player = (EntityPlayer *)self->parent;787if ((uint32)self->type <= ITEMBOX_STOCK)788ItemBox_GivePowerup();789}790break;791}792793#endif794default: break;795}796}797void ItemBox_Break(EntityItemBox *itemBox, EntityPlayer *player)798{799if (globals->gameMode == MODE_COMPETITION) {800EntityCompetitionSession *session = CompetitionSession_GetSession();801++session->items[RSDK.GetEntitySlot(player)];802}803804RSDK.CreateEntity(TYPE_BLANK, NULL, itemBox->position.x, itemBox->position.y);805806#if MANIA_USE_PLUS807if (player->characterID == ID_MIGHTY && player->animator.animationID == ANI_HAMMERDROP)808player->velocity.y -= TO_FIXED(1);809else810#endif811player->velocity.y = -(player->velocity.y + 2 * player->gravityStrength);812813itemBox->storedEntity = (Entity *)player;814itemBox->alpha = 0x100;815itemBox->contentsSpeed = -TO_FIXED(3);816itemBox->active = ACTIVE_NORMAL;817itemBox->velocity.y = -TO_FIXED(2);818itemBox->isContents = true;819itemBox->state = ItemBox_State_Break;820RSDK.SetSpriteAnimation(ItemBox->aniFrames, 1, &itemBox->boxAnimator, true, 0);821itemBox->boxAnimator.frameID = ItemBox->brokenFrame++;822ItemBox->brokenFrame %= 3;823RSDK.SetSpriteAnimation(-1, 0, &itemBox->overlayAnimator, true, 0);824RSDK.SetSpriteAnimation(-1, 0, &itemBox->debrisAnimator, true, 0);825826EntityExplosion *explosion = CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ITEMBOX), itemBox->position.x, itemBox->position.y - TO_FIXED(16));827explosion->drawGroup = Zone->objectDrawGroup[1];828829for (int32 d = 0; d < 6; ++d) {830EntityDebris *debris = CREATE_ENTITY(Debris, NULL, itemBox->position.x + RSDK.Rand(-0x80000, 0x80000),831itemBox->position.y + RSDK.Rand(-TO_FIXED(8), TO_FIXED(8)));832debris->state = Debris_State_Fall;833debris->gravityStrength = 0x4000;834debris->velocity.x = RSDK.Rand(0, TO_FIXED(2));835if (debris->position.x < itemBox->position.x)836debris->velocity.x = -debris->velocity.x;837debris->velocity.y = RSDK.Rand(-TO_FIXED(4), -TO_FIXED(1));838debris->drawFX = FX_FLIP;839debris->direction = d & 3;840debris->drawGroup = Zone->objectDrawGroup[1];841RSDK.SetSpriteAnimation(ItemBox->aniFrames, 6, &debris->animator, true, RSDK.Rand(0, 4));842}843844RSDK.PlaySfx(ItemBox->sfxDestroy, false, 255);845846itemBox->active = ACTIVE_NORMAL;847if (itemBox->type == ITEMBOX_RANDOM) {848#if MANIA_USE_PLUS849if (globals->gameMode != MODE_ENCORE) {850#endif851while (true) {852itemBox->type = RSDK.Rand(0, 13);853switch (itemBox->type) {854case ITEMBOX_1UP_SONIC:855if (globals->gameMode == MODE_TIMEATTACK)856continue;857858switch (player->characterID) {859case ID_SONIC: itemBox->type = ITEMBOX_1UP_SONIC; break;860case ID_TAILS: itemBox->type = ITEMBOX_1UP_TAILS; break;861case ID_KNUCKLES: itemBox->type = ITEMBOX_1UP_KNUX; break;862#if MANIA_USE_PLUS863case ID_MIGHTY: itemBox->type = ITEMBOX_1UP_MIGHTY; break;864case ID_RAY: itemBox->type = ITEMBOX_1UP_RAY;865#endif866break;867default: break;868}869itemBox->contentsAnimator.frameID = itemBox->type;870break;871872case ITEMBOX_1UP_TAILS:873case ITEMBOX_1UP_KNUX:874#if MANIA_USE_PLUS875case ITEMBOX_1UP_MIGHTY:876case ITEMBOX_1UP_RAY:877#endif878continue;879880case ITEMBOX_SWAP:881if (globals->gameMode != MODE_COMPETITION)882continue;883itemBox->contentsAnimator.frameID = itemBox->type;884break;885886default: itemBox->contentsAnimator.frameID = itemBox->type; break;887}888break;889}890#if MANIA_USE_PLUS891}892#endif893}894}895bool32 ItemBox_HandleFallingCollision(void)896{897RSDK_THIS(ItemBox);898899if (self->direction)900return false;901902self->moveOffset.x = -self->position.x;903self->moveOffset.y = -self->position.y;904if (self->velocity.y)905#if MANIA_USE_PLUS906self->parent = NULL;907#else908self->groundVel = 0;909#endif910911self->position.x += self->velocity.x;912self->position.y += self->velocity.y;913self->velocity.y += 0x3800;914915ItemBox_HandleObjectCollisions();916917if (self->velocity.y >= 0) {918bool32 collided = (self->direction == FLIP_Y && self->boxAnimator.animationID == 1)919? RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, TO_FIXED(0), true)920: RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, TO_FIXED(16), true);921if (collided) {922self->velocity.y = 0;923if (self->state != ItemBox_State_IconFinish && self->state != ItemBox_State_Break)924self->active = ACTIVE_BOUNDS;925self->moveOffset.x += self->position.x;926self->moveOffset.y += self->position.y;927return true;928}929}930931self->moveOffset.x += self->position.x;932self->moveOffset.y += self->position.y;933return false;934}935bool32 ItemBox_HandlePlatformCollision(void *plat)936{937RSDK_THIS(ItemBox);938EntityPlatform *platform = (EntityPlatform *)plat;939940bool32 collided = false;941if (platform->state != Platform_State_Falling2 && platform->state != Platform_State_Hold) {942platform->position.x = platform->drawPos.x - platform->collisionOffset.x;943platform->position.y = platform->drawPos.y - platform->collisionOffset.y;944945switch (platform->collision) {946case PLATFORM_C_PLATFORM:947collided = RSDK.CheckObjectCollisionPlatform(platform, RSDK.GetHitbox(&platform->animator, 0), self, &ItemBox->hitboxItemBox, true);948break;949case PLATFORM_C_SOLID:950collided = RSDK.CheckObjectCollisionBox(platform, RSDK.GetHitbox(&platform->animator, 1), self, &ItemBox->hitboxItemBox, true);951break;952953case PLATFORM_C_TILED:954if (!RSDK.CheckObjectCollisionTouchBox(platform, &platform->hitbox, self, &ItemBox->hitboxItemBox))955break;956957if (self->collisionLayers & Zone->moveLayerMask) {958TileLayer *move = RSDK.GetTileLayer(Zone->moveLayer);959move->position.x = -(platform->drawPos.x + platform->tileOrigin.x) >> 16;960move->position.y = -(platform->drawPos.y + platform->tileOrigin.y) >> 16;961}962963if (self->state == ItemBox_State_Idle || self->velocity.y > 0x3800) {964platform->position.x = platform->centerPos.x;965platform->position.y = platform->centerPos.y;966return false;967}968969collided = true;970break;971972default:973break;974}975976if (!collided) {977platform->position.x = platform->centerPos.x;978platform->position.y = platform->centerPos.y;979return false;980}981982#if MANIA_USE_PLUS983self->parent = (Entity *)platform;984#else985self->groundVel = RSDK.GetEntitySlot(platform);986#endif987988self->scale.x = (self->position.x - platform->drawPos.x) & 0xFFFF0000;989self->scale.y = (self->position.y - platform->drawPos.y) & 0xFFFF0000;990991self->updateRange.x = platform->updateRange.x;992self->updateRange.y = platform->updateRange.y;993994if (self->state == ItemBox_State_Falling)995self->state = ItemBox_State_Idle;996997if (platform->state == Platform_State_Fall && !platform->timer)998platform->timer = 30;9991000self->velocity.y = 0;1001platform->stood = true;1002platform->position.x = platform->centerPos.x;1003platform->position.y = platform->centerPos.y;1004return collided;1005}10061007return false;1008}1009void ItemBox_HandleObjectCollisions(void)1010{1011RSDK_THIS(ItemBox);10121013bool32 platformCollided = false;10141015if (Platform) {1016#if MANIA_USE_PLUS1017if (self->parent) {1018EntityPlatform *platform = (EntityPlatform *)self->parent;1019#else1020if (self->groundVel) {1021EntityPlatform *platform = RSDK_GET_ENTITY(self->groundVel, Platform);1022#endif10231024if (platform->classID == Platform->classID) {1025platform->stood = true;1026self->position.x = self->scale.x + platform->drawPos.x;1027self->position.y = (self->scale.y + platform->drawPos.y) & 0xFFFF0000;1028self->moveOffset.x = platform->collisionOffset.x & 0xFFFF0000;1029self->moveOffset.y = platform->collisionOffset.y & 0xFFFF0000;1030self->contentsPos.x += platform->collisionOffset.x;1031self->contentsPos.y += platform->collisionOffset.y;1032self->velocity.y = 0;1033platformCollided = true;1034}1035}1036else {1037foreach_active(Platform, platform)1038{1039if (ItemBox_HandlePlatformCollision(platform))1040platformCollided = true;1041}1042}1043}10441045#if MANIA_USE_PLUS1046if (TilePlatform && self->parent) {1047EntityTilePlatform *tilePlatform = (EntityTilePlatform *)self->parent;1048if (tilePlatform->classID == TilePlatform->classID) {1049platformCollided = true;1050tilePlatform->stood = true;1051self->position.x = self->scale.x + tilePlatform->drawPos.x;1052self->position.y = (self->scale.y + tilePlatform->drawPos.y) & 0xFFFF0000;1053self->moveOffset.x = tilePlatform->collisionOffset.x & 0xFFFF0000;1054self->moveOffset.y = tilePlatform->collisionOffset.y & 0xFFFF0000;1055self->contentsPos.x += tilePlatform->collisionOffset.x;1056self->contentsPos.y += tilePlatform->collisionOffset.y;1057self->velocity.y = 0;1058}1059}1060#endif10611062if (Crate) {1063#if MANIA_USE_PLUS1064if (self->parent) {1065EntityCrate *crate = (EntityCrate *)self->parent;1066#else1067if (self->groundVel) {1068EntityCrate *crate = RSDK_GET_ENTITY(self->groundVel, Crate);1069#endif1070if (crate->classID == Crate->classID) {1071crate->stood = true;1072self->position.x = self->scale.x + crate->drawPos.x;1073self->position.y = (self->scale.y + crate->drawPos.y) & 0xFFFF0000;1074self->moveOffset.x = crate->collisionOffset.x & 0xFFFF0000;1075self->moveOffset.y = crate->collisionOffset.y & 0xFFFF0000;1076self->contentsPos.x += crate->collisionOffset.x;1077self->contentsPos.y += crate->collisionOffset.y;1078self->velocity.y = 0;1079}1080else {1081#if MANIA_USE_PLUS1082self->parent = NULL;1083#else1084self->groundVel = 0;1085#endif1086}1087}1088else {1089foreach_active(Crate, crate)1090{1091if (!crate->ignoreItemBox && ItemBox_HandlePlatformCollision(crate))1092platformCollided = true;1093}1094}1095}10961097if (!platformCollided)1098#if MANIA_USE_PLUS1099self->parent = NULL;1100#else1101self->groundVel = 0;1102#endif11031104if (Ice) {1105foreach_active(Ice, ice)1106{1107if (ice->stateDraw == Ice_Draw_IceBlock) {1108int32 storeX = ice->position.x;1109int32 storeY = ice->position.y;1110ice->position.x -= ice->playerMoveOffset.x;1111ice->position.y -= ice->playerMoveOffset.y;11121113if (RSDK.CheckObjectCollisionBox(ice, &ice->hitboxBlock, self, &ItemBox->hitboxItemBox, true) == C_TOP) {1114self->position.x += ice->playerMoveOffset.x;1115self->position.y += ice->playerMoveOffset.y;1116self->position.y &= 0xFFFF0000;11171118self->contentsPos.x += ice->playerMoveOffset.x;1119self->contentsPos.y += ice->playerMoveOffset.y;1120self->contentsPos.y &= 0xFFFF0000;11211122self->moveOffset.x = ice->playerMoveOffset.x;1123self->moveOffset.y = ice->playerMoveOffset.y;1124self->velocity.y = 0;1125}11261127ice->position.x = storeX;1128ice->position.y = storeY;1129}1130}1131}11321133foreach_active(Spikes, spikes)1134{1135int32 storeX = spikes->position.x;1136int32 storeY = spikes->position.y;11371138spikes->position.x -= spikes->collisionOffset.x;1139spikes->position.y -= spikes->collisionOffset.y;1140if (RSDK.CheckObjectCollisionBox(spikes, &spikes->hitbox, self, &ItemBox->hitboxItemBox, true) == C_TOP) {1141self->position.x += spikes->collisionOffset.x;1142self->position.y += spikes->collisionOffset.y;1143self->position.y &= 0xFFFF0000;11441145self->contentsPos.x += spikes->collisionOffset.x;1146self->contentsPos.y += spikes->collisionOffset.y;1147self->contentsPos.y &= 0xFFFF0000;11481149self->moveOffset.x = spikes->collisionOffset.x;1150self->moveOffset.y = spikes->collisionOffset.y;1151self->velocity.y = 0;1152}11531154spikes->position.x = storeX;1155spikes->position.y = storeY;1156}11571158foreach_active(ItemBox, itemBox)1159{1160if (itemBox != self) {1161if (self->state == ItemBox_State_Idle || self->state == ItemBox_State_Falling) {1162if (itemBox->state == ItemBox_State_Idle || itemBox->state == ItemBox_State_Falling) {1163int32 storeX = itemBox->position.x;1164int32 storeY = itemBox->position.y;11651166itemBox->position.x -= itemBox->moveOffset.x;1167itemBox->position.y -= itemBox->moveOffset.y;1168if (RSDK.CheckObjectCollisionBox(itemBox, &ItemBox->hitboxItemBox, self, &ItemBox->hitboxItemBox, true) == C_TOP) {1169self->position.x += itemBox->moveOffset.x;1170self->position.y += itemBox->moveOffset.y;1171self->position.y = TO_FIXED(self->position.y >> 16);11721173self->contentsPos.x += itemBox->moveOffset.x;1174self->contentsPos.y += itemBox->moveOffset.y;1175self->contentsPos.y = TO_FIXED(self->contentsPos.y >> 16);11761177self->moveOffset.x = itemBox->moveOffset.x;1178self->moveOffset.y = itemBox->moveOffset.y;1179self->velocity.y = 0;1180}11811182itemBox->position.x = storeX;1183itemBox->position.y = storeY;1184}1185}1186}1187}1188}11891190#if GAME_INCLUDE_EDITOR1191void ItemBox_EditorDraw(void)1192{1193RSDK_THIS(ItemBox);11941195int32 dir = self->direction;1196self->direction *= FLIP_Y;11971198self->contentsPos.x = self->position.x;1199if (self->direction == FLIP_NONE)1200self->contentsPos.y = self->position.y - TO_FIXED(3);1201else1202self->contentsPos.y = self->position.y + TO_FIXED(3);12031204self->inkEffect = INK_ALPHA;1205self->alpha = self->hidden ? 0x80 : 0x100;12061207RSDK.SetSpriteAnimation(ItemBox->aniFrames, 2, &self->contentsAnimator, true, self->type);1208RSDK.DrawSprite(&self->boxAnimator, NULL, false);1209RSDK.DrawSprite(&self->contentsAnimator, &self->contentsPos, false);12101211self->direction = dir;1212}12131214void ItemBox_EditorLoad(void)1215{1216ItemBox->aniFrames = RSDK.LoadSpriteAnimation("Global/ItemBox.bin", SCOPE_STAGE);12171218RSDK_ACTIVE_VAR(ItemBox, type);1219RSDK_ENUM_VAR("Super Ring", ITEMBOX_RING);1220RSDK_ENUM_VAR("Blue Shield", ITEMBOX_BLUESHIELD);1221RSDK_ENUM_VAR("Bubble Shield", ITEMBOX_BUBBLESHIELD);1222RSDK_ENUM_VAR("Fire Shield", ITEMBOX_FIRESHIELD);1223RSDK_ENUM_VAR("Lightning Shield", ITEMBOX_LIGHTNINGSHIELD);1224RSDK_ENUM_VAR("Invincibility", ITEMBOX_INVINCIBLE);1225RSDK_ENUM_VAR("Sneakers", ITEMBOX_SNEAKERS);1226RSDK_ENUM_VAR("1UP Sonic", ITEMBOX_1UP_SONIC);1227RSDK_ENUM_VAR("1UP Tails", ITEMBOX_1UP_TAILS);1228RSDK_ENUM_VAR("1UP Knux", ITEMBOX_1UP_KNUX);1229RSDK_ENUM_VAR("Eggman", ITEMBOX_EGGMAN);1230RSDK_ENUM_VAR("Hyper Ring", ITEMBOX_HYPERRING);1231RSDK_ENUM_VAR("Swap", ITEMBOX_SWAP);1232RSDK_ENUM_VAR("Random", ITEMBOX_RANDOM);1233RSDK_ENUM_VAR("Super", ITEMBOX_SUPER);1234#if MANIA_USE_PLUS1235RSDK_ENUM_VAR("1UP Mighty", ITEMBOX_1UP_MIGHTY);1236RSDK_ENUM_VAR("1UP Ray", ITEMBOX_1UP_RAY);1237RSDK_ENUM_VAR("Change", ITEMBOX_STOCK);1238#endif12391240RSDK_ACTIVE_VAR(ItemBox, planeFilter);1241RSDK_ENUM_VAR("None", PLANEFILTER_NONE);1242RSDK_ENUM_VAR("AL", PLANEFILTER_AL);1243RSDK_ENUM_VAR("BL", PLANEFILTER_BL);1244RSDK_ENUM_VAR("AH", PLANEFILTER_AH);1245RSDK_ENUM_VAR("BH", PLANEFILTER_BH);12461247RSDK_ACTIVE_VAR(ItemBox, direction);1248RSDK_ENUM_VAR("Normal", FLIP_NONE);1249RSDK_ENUM_VAR("Upside-Down", FLIP_X);1250}1251#endif12521253void ItemBox_Serialize(void)1254{1255RSDK_EDITABLE_VAR(ItemBox, VAR_ENUM, type);1256RSDK_EDITABLE_VAR(ItemBox, VAR_BOOL, isFalling);1257RSDK_EDITABLE_VAR(ItemBox, VAR_BOOL, hidden);1258RSDK_EDITABLE_VAR(ItemBox, VAR_UINT8, direction);1259RSDK_EDITABLE_VAR(ItemBox, VAR_ENUM, planeFilter);1260RSDK_EDITABLE_VAR(ItemBox, VAR_BOOL, lrzConvPhys);1261}126212631264