Path: blob/master/SonicMania/Objects/GHZ/ZipLine.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: ZipLine Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectZipLine *ZipLine;1011void ZipLine_Update(void)12{13RSDK_THIS(ZipLine);1415StateMachine_Run(self->state);1617int32 storeX = self->position.x;18int32 storeY = self->position.y;1920self->position = self->handlePos;21foreach_active(Player, player)22{23int32 playerID = RSDK.GetEntitySlot(player);24if (self->grabDelay[playerID])25self->grabDelay[playerID]--;2627if ((1 << playerID) & self->activePlayers) {28if (Player_CheckValidState(player)) {29Hitbox *playerHitbox = Player_GetHitbox(player);3031if (player->state != Player_State_Hurt) {32if (player->velocity.x) {33self->groundVel = player->groundVel;34if (self->angle >= 0x40 && self->angle <= 0xC0)35self->groundVel = -player->groundVel;3637self->groundVel = CLAMP(self->groundVel, -0xA0000, 0xA0000);3839self->velocity.x = self->groundVel * RSDK.Cos256(self->angle) >> 8;40self->velocity.y = self->groundVel * RSDK.Sin256(self->angle) >> 8;41player->velocity.x = 0;42player->velocity.y = 0;43player->groundVel = 0;44player->angle = 0;45player->rotation = 0;46}4748int32 lastX = player->position.x;49player->position.x = self->position.x;50player->position.y = self->position.y + (((ZipLine->hitboxHandle.bottom - ZipLine->hitboxHandle.top) << 15) & 0xFFFF0000)51+ ((ZipLine->hitboxHandle.top - playerHitbox->top) << 16);5253if (abs(lastX - self->position.x) <= 0x100000) {54if (!self->grabDelay[playerID] && player->jumpPress) {55player->velocity.y = -0x40000;56player->jumpAbilityState = 1;57RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);58player->animator.speed = 48;59player->state = Player_State_Air;60self->grabDelay[playerID] = 60;61self->activePlayers &= ~(1 << playerID);62player->onGround = false;63player->groundedStore = false;64player->tileCollisions = TILECOLLISION_DOWN;65}66}67else {68player->state = Player_State_Air;69self->grabDelay[playerID] = 60;70self->activePlayers &= ~(1 << playerID);71player->onGround = false;72player->groundedStore = false;73player->tileCollisions = TILECOLLISION_DOWN;74}75}76else {77self->grabDelay[playerID] = 60;78self->activePlayers &= ~(1 << playerID);79player->onGround = false;80player->groundedStore = false;81player->tileCollisions = TILECOLLISION_DOWN;82}83}84else {85self->activePlayers &= ~(1 << playerID);86if (player->state != Player_State_Death) {87player->tileCollisions = TILECOLLISION_DOWN;88}89}90}91else if (!self->grabDelay[playerID] && player->state != Player_State_Static && !player->down) {92Hitbox *playerHitbox = Player_GetHitbox(player);93Hitbox otherHitbox;94otherHitbox.top = playerHitbox->top - 4;95otherHitbox.left = playerHitbox->left;96otherHitbox.right = playerHitbox->right;97otherHitbox.bottom = otherHitbox.top + 8;9899if (RSDK.CheckObjectCollisionTouchBox(self, &ZipLine->hitboxHandle, player, &otherHitbox)) {100if (player->sidekick || self->state == ZipLine_State_Moving) {101ZipLine_GrabHandle(player, playerID, playerHitbox);102}103else if (!self->state) {104self->groundVel = player->groundVel;105if (self->angle >= 0x40 && self->angle <= 0xC0)106self->groundVel = -player->groundVel;107108self->groundVel = CLAMP(self->groundVel, -0xA0000, 0xA0000);109110self->velocity.x = self->groundVel * RSDK.Cos256(self->angle) >> 8;111self->velocity.y = self->groundVel * RSDK.Sin256(self->angle) >> 8;112113if (self->angle & 0x7F) {114if ((uint8)self->angle < 0x80) {115if (self->handlePos.x == self->startPos.x) {116if (self->velocity.y < 0) {117self->velocity.x = 0;118self->velocity.y = 0;119self->groundVel = 0;120}121self->state = ZipLine_State_Moving;122}123124if (self->handlePos.x == self->endPos.x && self->velocity.y < 0)125ZipLine_GrabHandle(player, playerID, playerHitbox);126}127else {128if (self->handlePos.x == self->endPos.x) {129if (self->velocity.y < 0) {130self->velocity.x = 0;131self->velocity.y = 0;132self->groundVel = 0;133}134135self->state = ZipLine_State_Moving;136}137138if (self->handlePos.x == self->startPos.x && self->velocity.y < 0)139ZipLine_GrabHandle(player, playerID, playerHitbox);140}141}142else if (self->groundVel) {143if ((self->groundVel < 0 && self->handlePos.x != self->startPos.x)144|| (self->groundVel > 0 && self->handlePos.x != self->endPos.x)) {145ZipLine_GrabHandle(player, playerID, playerHitbox);146}147}148}149}150}151}152self->position.x = storeX;153self->position.y = storeY;154}155156void ZipLine_LateUpdate(void) {}157158void ZipLine_StaticUpdate(void) {}159160void ZipLine_Draw(void)161{162RSDK_THIS(ZipLine);163164RSDK.DrawLine(self->startPos.x, self->startPos.y, self->endPos.x, self->endPos.y, 0x6060A0, 0x00, INK_NONE, false);165RSDK.DrawLine(self->startPos.x, self->startPos.y + 0x10000, self->endPos.x, self->endPos.y + 0x10000, 0x303070, 0x00, INK_NONE, false);166167self->animator.frameID = 0;168RSDK.DrawSprite(&self->animator, &self->handlePos, false);169self->animator.frameID = 1;170171RSDK.DrawSprite(&self->animator, &self->startPos, false);172RSDK.DrawSprite(&self->animator, &self->endPos, false);173}174175void ZipLine_Create(void *data)176{177RSDK_THIS(ZipLine);178self->active = ACTIVE_BOUNDS;179self->visible = true;180self->drawFX = FX_FLIP;181RSDK.SetSpriteAnimation(ZipLine->aniFrames, 0, &self->animator, true, 0);182self->drawGroup = Zone->playerDrawGroup[0];183184self->handlePos = self->position;185self->startPos = self->position;186self->endPos.x = self->position.x + (self->length << 8) * RSDK.Cos256(self->angle);187self->endPos.y = self->position.y + (self->length << 8) * RSDK.Sin256(self->angle);188189if (!SceneInfo->inEditor) {190self->position.x += (self->endPos.x - self->startPos.x) >> 1;191self->position.y += (self->endPos.y - self->startPos.y) >> 1;192self->updateRange.x = (abs(self->endPos.x - self->startPos.x) >> 1) + 0x400000;193self->updateRange.y = (abs(self->endPos.y - self->startPos.y) >> 1) + 0x400000;194self->joinPos = ZipLine_GetJoinPos();195}196}197198void ZipLine_StageLoad(void)199{200if (RSDK.CheckSceneFolder("GHZ"))201ZipLine->aniFrames = RSDK.LoadSpriteAnimation("GHZ/ZipLine.bin", SCOPE_STAGE);202203ZipLine->hitboxHandle.top = 0;204ZipLine->hitboxHandle.left = -8;205ZipLine->hitboxHandle.bottom = 24;206ZipLine->hitboxHandle.right = 8;207208Zone_AddVSSwapCallback(ZipLine_VSSwap_CheckBusy);209}210211void ZipLine_VSSwap_CheckBusy(void)212{213foreach_active(ZipLine, zipline)214{215#if MANIA_USE_PLUS216if ((1 << Zone->swapPlayerID) & zipline->activePlayers)217Zone->playerSwapEnabled[Zone->swapPlayerID] = false;218#else219if (zipline->activePlayers)220Zone->playerSwapEnabled = false;221#endif222}223}224225void ZipLine_GrabHandle(EntityPlayer *player, int32 playerID, Hitbox *playerHitbox)226{227RSDK_THIS(ZipLine);228229self->state = ZipLine_State_Moving;230self->activePlayers |= 1 << playerID;231player->onGround = false;232player->groundedStore = false;233player->velocity.x = 0;234player->velocity.y = 0;235player->groundVel = 0;236player->angle = 0;237player->rotation = 0;238player->position.x = self->position.x;239player->position.y = self->position.y;240player->position.y +=241((ZipLine->hitboxHandle.top - playerHitbox->top) << 16) + (((ZipLine->hitboxHandle.bottom - ZipLine->hitboxHandle.top) << 15) & 0xFFFF0000);242player->tileCollisions = TILECOLLISION_NONE;243RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG, &player->animator, true, 0);244player->state = Player_State_Static;245player->nextAirState = StateMachine_None;246player->nextGroundState = StateMachine_None;247RSDK.PlaySfx(Player->sfxGrab, false, 0xFF);248self->grabDelay[playerID] = 15;249self->active = ACTIVE_NORMAL;250}251252void ZipLine_ForceReleasePlayers(void)253{254RSDK_THIS(ZipLine);255256foreach_active(Player, player)257{258int32 playerID = RSDK.GetEntitySlot(player);259if ((1 << playerID) & self->activePlayers) {260self->grabDelay[playerID] = 60;261player->velocity.y = self->velocity.y;262player->velocity.x = self->velocity.x;263player->groundVel = player->velocity.x;264self->activePlayers &= ~(1 << playerID);265player->onGround = false;266player->groundedStore = false;267player->tileCollisions = TILECOLLISION_DOWN;268player->state = Player_State_Air;269}270}271}272273// this func actually rules, you can join any number of ZipLines together using this274Vector2 ZipLine_GetJoinPos(void)275{276RSDK_THIS(ZipLine);277278EntityZipLine *endMarker = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, ZipLine);279Vector2 result;280result.x = 0;281result.y = 0;282283if (endMarker->classID == ZipLine->classID) {284Hitbox thisHitbox, otherHitbox;285286if (self->startPos.y >= self->endPos.y) {287otherHitbox.top = (self->endPos.y - self->position.y) >> 16;288otherHitbox.bottom = (self->startPos.y - self->position.y) >> 16;289}290else {291otherHitbox.top = (self->startPos.y - self->position.y) >> 16;292otherHitbox.bottom = (self->endPos.y - self->position.y) >> 16;293}294295if (self->startPos.x >= self->endPos.x) {296otherHitbox.left = (self->endPos.x - self->position.y) >> 16;297otherHitbox.right = (self->startPos.x - self->position.y) >> 16;298}299else {300otherHitbox.left = (self->startPos.x - self->position.x) >> 16;301otherHitbox.right = (self->endPos.x - self->position.x) >> 16;302}303304if (endMarker->startPos.y >= endMarker->endPos.y) {305thisHitbox.top = (endMarker->endPos.y - endMarker->position.y) >> 16;306thisHitbox.bottom = (endMarker->startPos.y - endMarker->position.y) >> 16;307}308else {309thisHitbox.top = (endMarker->startPos.y - endMarker->position.y) >> 16;310thisHitbox.bottom = (endMarker->endPos.y - endMarker->position.y) >> 16;311}312313if (endMarker->startPos.x >= endMarker->endPos.x) {314thisHitbox.left = (endMarker->endPos.x - endMarker->position.y) >> 16;315thisHitbox.right = (endMarker->startPos.x - endMarker->position.y) >> 16;316}317else {318thisHitbox.left = (endMarker->startPos.x - endMarker->position.x) >> 16;319thisHitbox.right = (endMarker->endPos.x - endMarker->position.x) >> 16;320}321322otherHitbox.left -= 8;323otherHitbox.top -= 8;324otherHitbox.right += 8;325otherHitbox.bottom += 8;326thisHitbox.left -= 8;327thisHitbox.top -= 8;328thisHitbox.right += 8;329thisHitbox.bottom += 8;330if (RSDK.CheckObjectCollisionTouchBox(endMarker, &thisHitbox, self, &otherHitbox)) {331int32 distX1 = (self->startPos.x >> 17) - (self->endPos.x >> 17);332int32 distY1 = (self->endPos.y >> 17) - (self->startPos.y >> 17);333int32 distX2 = (endMarker->startPos.x >> 17) - (endMarker->endPos.x >> 17);334int32 distY2 = (endMarker->endPos.y >> 17) - (endMarker->startPos.y >> 17);335336int32 val1 = distX1 * (self->startPos.y >> 17) + distY1 * (self->startPos.x >> 17);337int32 val2 = distX2 * (endMarker->startPos.y >> 17) + distY2 * (endMarker->startPos.x >> 17);338float divisor = (float)(distY1 * distX2 - distX1 * distY2);339if (divisor != 0.0f) {340endMarker->handlePos.x = -0x100000;341result.x = (int32)((float)(distX2 * val1 - distX1 * val2) / divisor) << 17;342result.y = (int32)((float)(distY1 * val2 - distY2 * val1) / divisor) << 17;343}344}345}346return result;347}348349void ZipLine_State_Moving(void)350{351RSDK_THIS(ZipLine);352353self->groundVel += (RSDK.Sin256(self->angle) << 14 >> 8);354if (self->groundVel >= 0xA0000)355self->groundVel = 0xA0000;356357self->velocity.x = self->groundVel * RSDK.Cos256(self->angle) >> 8;358self->velocity.y = self->groundVel * RSDK.Sin256(self->angle) >> 8;359360if (self->joinPos.x) {361int32 storeX = self->position.x;362int32 storeY = self->position.y;363self->position.x = self->handlePos.x;364self->position.y = self->handlePos.y;365366Hitbox otherHitbox;367otherHitbox.top = ((self->joinPos.y - self->position.y - (self->velocity.y >> 1)) >> 16) + 8;368otherHitbox.bottom = (((self->velocity.y >> 1) + (self->joinPos.y - self->position.y)) >> 16) + 16;369370if (self->velocity.x >= 0) {371otherHitbox.left = (self->joinPos.x - self->position.x) >> 16;372otherHitbox.right = ((self->joinPos.x + self->velocity.x - self->position.x) >> 16) + 5;373}374else {375otherHitbox.left = (((self->joinPos.x - self->position.x) - self->velocity.x) >> 16) - 5;376otherHitbox.right = (self->joinPos.x - self->position.x) >> 16;377}378379if (RSDK.CheckObjectCollisionTouchBox(self, &ZipLine->hitboxHandle, self, &otherHitbox)) {380EntityZipLine *endMarker = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, ZipLine);381endMarker->handlePos.x = self->joinPos.x;382endMarker->handlePos.y = self->joinPos.y;383endMarker->onGround = true;384endMarker->activePlayers = self->activePlayers;385endMarker->groundVel = self->groundVel;386endMarker->state = ZipLine_State_Moving;387self->position.x = storeX;388self->position.y = storeY;389self->activePlayers = 0;390self->groundVel = 0;391self->handlePos.x = -0x100000;392self->state = StateMachine_None;393foreach_active(Player, player)394{395if ((1 << RSDK.GetEntitySlot(player)) & endMarker->activePlayers) {396Hitbox *playerHitbox = Player_GetHitbox(player);397player->velocity.x = 0;398player->velocity.y = 0;399player->groundVel = 0;400player->angle = 0;401player->rotation = 0;402player->position.x = endMarker->handlePos.x;403player->position.y = endMarker->handlePos.y + (((ZipLine->hitboxHandle.bottom - ZipLine->hitboxHandle.top) << 15) & 0xFFFF0000)404+ ((ZipLine->hitboxHandle.top - playerHitbox->top) << 16);405}406}407return;408}409self->position.x = storeX;410self->position.y = storeY;411}412413self->handlePos.x += self->velocity.x;414self->handlePos.y += self->velocity.y;415if (self->groundVel < 0) {416if (self->velocity.x < 0) {417if (self->handlePos.x < self->startPos.x)418self->handlePos.x = self->startPos.x;419420if (self->velocity.y < 0) {421if (self->handlePos.y < self->startPos.y)422self->handlePos.y = self->startPos.y;423}424if (self->velocity.y > 0) {425if (self->handlePos.y > self->startPos.y)426self->handlePos.y = self->startPos.y;427}428429if (self->handlePos.x == self->startPos.x && self->handlePos.y == self->startPos.y) {430self->groundVel = 0;431if (self->startPos.y >= self->endPos.y || !self->onGround) {432self->onGround = false;433self->active = ACTIVE_BOUNDS;434self->state = StateMachine_None;435ZipLine_ForceReleasePlayers();436}437}438}439else if (self->velocity.x > 0) {440if (self->handlePos.x > self->startPos.x)441self->handlePos.x = self->startPos.x;442443if (self->velocity.y < 0) {444if (self->handlePos.y < self->startPos.y)445self->handlePos.y = self->startPos.y;446}447if (self->velocity.y > 0) {448if (self->handlePos.y > self->startPos.y)449self->handlePos.y = self->startPos.y;450}451452if (self->handlePos.x == self->startPos.x && self->handlePos.y == self->startPos.y) {453self->groundVel = 0;454if (self->startPos.y >= self->endPos.y || !self->onGround) {455self->onGround = false;456self->active = ACTIVE_BOUNDS;457self->state = StateMachine_None;458ZipLine_ForceReleasePlayers();459}460}461}462}463else if (self->groundVel > 0) {464if (self->velocity.x > 0) {465if (self->handlePos.x > self->endPos.x) {466self->handlePos.x = self->endPos.x;467}468}469else if (self->velocity.x < 0) {470self->endPos.x = self->endPos.x;471if (self->handlePos.x < self->endPos.x) {472self->handlePos.x = self->endPos.x;473}474}475476if (self->velocity.y < 0) {477if (self->handlePos.y < self->endPos.y)478self->handlePos.y = self->endPos.y;479}480else if (self->velocity.y > 0) {481if (self->handlePos.y > self->endPos.y)482self->handlePos.y = self->endPos.y;483}484485if (self->handlePos.x == self->endPos.x && self->handlePos.y == self->endPos.y) {486self->groundVel = 0;487if (self->endPos.y >= self->startPos.y || !self->onGround) {488self->onGround = false;489self->active = ACTIVE_BOUNDS;490self->state = StateMachine_None;491ZipLine_ForceReleasePlayers();492}493}494}495}496497#if GAME_INCLUDE_EDITOR498void ZipLine_EditorDraw(void)499{500RSDK_THIS(ZipLine);501self->handlePos = self->position;502self->startPos = self->position;503self->endPos.x = self->position.x + (self->length << 8) * RSDK.Cos256(self->angle);504self->endPos.y = self->position.y + (self->length << 8) * RSDK.Sin256(self->angle);505506ZipLine_Draw();507}508509void ZipLine_EditorLoad(void) { ZipLine->aniFrames = RSDK.LoadSpriteAnimation("GHZ/ZipLine.bin", SCOPE_STAGE); }510#endif511512void ZipLine_Serialize(void)513{514RSDK_EDITABLE_VAR(ZipLine, VAR_INT32, angle);515RSDK_EDITABLE_VAR(ZipLine, VAR_ENUM, length);516}517518519