Path: blob/master/SonicMania/Objects/UFO/UFO_Circuit.c
338 views
// ---------------------------------------------------------------------1// RSDK Project: Sonic Mania2// Object Description: UFO_Circuit Object3// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges4// Decompiled by: Rubberduckycooly & RMGRich5// ---------------------------------------------------------------------67#include "Game.h"89ObjectUFO_Circuit *UFO_Circuit;1011void UFO_Circuit_Update(void)12{13RSDK_THIS(UFO_Circuit);1415StateMachine_Run(self->state);1617RSDK.ProcessAnimation(&self->ufoAnimator);18}1920void UFO_Circuit_LateUpdate(void)21{22RSDK_THIS(UFO_Circuit);2324int32 x = self->position.x;25int32 y = self->height;26int32 z = self->position.y;2728Matrix *m = &UFO_Camera->matWorld;2930self->zdepth = m->values[2][1] * (y >> 16) + m->values[2][2] * (z >> 16) + m->values[2][0] * (x >> 16) + m->values[2][3];3132if (self->zdepth >= 0x400) {33int32 depth = (int32)((m->values[0][3] << 8) + (m->values[0][2] * (z >> 8) & 0xFFFFFF00) + (m->values[0][0] * (x >> 8) & 0xFFFFFF00)34+ (m->values[0][1] * (y >> 8) & 0xFFFFFF00))35/ self->zdepth;3637self->visible = abs(depth) < 0x100;38}39}4041void UFO_Circuit_StaticUpdate(void) {}4243void UFO_Circuit_Draw(void)44{45RSDK_THIS(UFO_Circuit);4647if (self->zdepth >= 0x4000) {48RSDK.Prepare3DScene(UFO_Circuit->sceneIndex);4950RSDK.MatrixScaleXYZ(&self->matTransform, 0x200, 0x200, 0x200);51RSDK.MatrixTranslateXYZ(&self->matTransform, self->position.x, self->height, self->position.y, false);52RSDK.MatrixRotateY(&self->matNormal, self->angleY);5354RSDK.MatrixMultiply(&self->matWorld, &self->matNormal, &self->matTransform);55RSDK.MatrixMultiply(&self->matWorld, &self->matWorld, &UFO_Camera->matWorld);56RSDK.MatrixMultiply(&self->matNormal, &self->matNormal, &UFO_Camera->matView);5758RSDK.AddMeshFrameTo3DScene(self->ufoAnimator.animationID, UFO_Circuit->sceneIndex, &self->ufoAnimator, S3D_SOLIDCOLOR_SHADED_BLENDED_SCREEN,59&self->matWorld, &self->matNormal, 0xFFFFFF);60RSDK.AddMeshFrameTo3DScene(UFO_Circuit->emeraldModel, UFO_Circuit->sceneIndex, &self->ufoAnimator, S3D_SOLIDCOLOR_SHADED_BLENDED_SCREEN,61&self->matWorld, &self->matNormal, 0xFFFFFF);6263RSDK.Draw3DScene(UFO_Circuit->sceneIndex);64}65}6667void UFO_Circuit_Create(void *data)68{69RSDK_THIS(UFO_Circuit);7071if (!SceneInfo->inEditor) {72self->startPos.x = self->position.x;73self->startPos.y = self->position.y;74int32 id = RSDK.GetEntitySlot(self);7576EntityUFO_Circuit *next = RSDK_GET_ENTITY(id + 1, UFO_Circuit);77if (next->classID == UFO_Circuit->classID) {78self->nextNode = next;79}80else {81for (int32 e = id - 1; e > 0; --e) {82EntityUFO_Circuit *node = RSDK_GET_ENTITY(e, UFO_Circuit);83if (node->classID != UFO_Circuit->classID) {84self->nextNode = RSDK_GET_ENTITY(e + 1, UFO_Circuit);85break;86}87}88}8990EntityUFO_Circuit *prev = RSDK_GET_ENTITY(id - 1, UFO_Circuit);91if (prev->classID == UFO_Circuit->classID) {92self->prevNode = prev;93}94else {95for (int32 e = id + 1; e < TEMPENTITY_START; ++e) {96EntityUFO_Circuit *node = RSDK_GET_ENTITY(e, UFO_Circuit);97if (node->classID != UFO_Circuit->classID) {98self->prevNode = RSDK_GET_ENTITY(e - 1, UFO_Circuit);99break;100}101}102}103104if (self->startNode) {105self->active = ACTIVE_NORMAL;106self->visible = true;107self->drawGroup = 4;108self->curNode = self->reverse ? self->prevNode : self->nextNode;109self->groundVel = 0x70000;110self->topSpeed = 0x70000;111112RSDK.SetModelAnimation(UFO_Circuit->ufoModel, &self->ufoAnimator, 128, 0, true, 0);113114UFO_Circuit_HandleSpeedSetup();115self->state = UFO_Circuit_State_UFO;116}117}118}119120void UFO_Circuit_StageLoad(void)121{122UFO_Circuit->ufoModel = RSDK.LoadMesh("Special/UFOChase.bin", SCOPE_STAGE);123124switch (UFO_Setup->specialStageID) {125case 1: UFO_Circuit->emeraldModel = RSDK.LoadMesh("Special/EmeraldYellow.bin", SCOPE_STAGE); break;126case 2: UFO_Circuit->emeraldModel = RSDK.LoadMesh("Special/EmeraldBlue.bin", SCOPE_STAGE); break;127case 3: UFO_Circuit->emeraldModel = RSDK.LoadMesh("Special/EmeraldPurple.bin", SCOPE_STAGE); break;128case 4: UFO_Circuit->emeraldModel = RSDK.LoadMesh("Special/EmeraldGrey.bin", SCOPE_STAGE); break;129case 5: UFO_Circuit->emeraldModel = RSDK.LoadMesh("Special/EmeraldCyan.bin", SCOPE_STAGE); break;130case 6: UFO_Circuit->emeraldModel = RSDK.LoadMesh("Special/EmeraldRed.bin", SCOPE_STAGE); break;131default: UFO_Circuit->emeraldModel = RSDK.LoadMesh("Special/EmeraldGreen.bin", SCOPE_STAGE); break;132}133134UFO_Circuit->sceneIndex = RSDK.Create3DScene("View:Special", 4096, SCOPE_STAGE);135136UFO_Circuit->nodeCount = 0;137foreach_all(UFO_Circuit, node) { UFO_Circuit->nodeCount++; }138139UFO_Circuit->decelerationNoMach = 0;140UFO_Circuit->decelerationMach = 0;141}142143void UFO_Circuit_HandleSpeedSetup(void)144{145RSDK_THIS(UFO_Circuit);146147self->angle = RSDK.ATan2((self->position.x - self->curNode->position.x) >> 16, (self->position.y - self->curNode->position.y) >> 16);148149switch (self->curNode->throttle) {150default:151case UFO_CIRCUIT_THRTLE_INVALID:152case UFO_CIRCUIT_THRTLE_NONE:153UFO_Circuit->decelerationNoMach = 0;154UFO_Circuit->decelerationMach = 0;155break;156157case UFO_CIRCUIT_THRTLE_SLOW:158UFO_Circuit->decelerationNoMach = 0x2000;159UFO_Circuit->decelerationMach = 0x8000;160break;161162case UFO_CIRCUIT_THRTLE_MED:163UFO_Circuit->decelerationNoMach = 0x4000;164UFO_Circuit->decelerationMach = 0x10000;165break;166167case UFO_CIRCUIT_THRTLE_FAST:168UFO_Circuit->decelerationNoMach = 0x8000;169UFO_Circuit->decelerationMach = 0x20000;170break;171}172}173void UFO_Circuit_HandleNodeSpeeds(void)174{175RSDK_THIS(UFO_Circuit);176177self->angle = RSDK.ATan2((self->position.x - self->curNode->startPos.x) >> 16, (self->position.y - self->curNode->startPos.y) >> 16);178179switch (self->curNode->throttle) {180default:181case UFO_CIRCUIT_THRTLE_INVALID: break;182183case UFO_CIRCUIT_THRTLE_NONE:184UFO_Circuit->decelerationNoMach = 0;185UFO_Circuit->decelerationMach = 0;186break;187188case UFO_CIRCUIT_THRTLE_SLOW:189UFO_Circuit->decelerationNoMach = 0x2000;190UFO_Circuit->decelerationMach = 0x8000;191break;192193case UFO_CIRCUIT_THRTLE_MED:194UFO_Circuit->decelerationNoMach = 0x4000;195UFO_Circuit->decelerationMach = 0x10000;196break;197198case UFO_CIRCUIT_THRTLE_FAST:199UFO_Circuit->decelerationNoMach = 0x8000;200UFO_Circuit->decelerationMach = 0x20000;201break;202}203}204bool32 UFO_Circuit_CheckNodeChange(void)205{206RSDK_THIS(UFO_Circuit);207208foreach_active(UFO_Player, player)209{210EntityUFO_Circuit *curNode = self->curNode;211EntityUFO_Circuit *targetNode = NULL;212EntityUFO_Circuit *nextNode = curNode->nextNode;213214int32 x = (player->position.x - self->position.x) >> 16;215int32 y = (player->position.y - self->position.y) >> 16;216217if (x * x + y * y >= 0x100000 && nextNode != curNode) {218int32 targetDistance = 0x7FFFFFFF;219220while (nextNode && nextNode != curNode) {221x = (player->position.x - nextNode->position.x) >> 16;222y = (player->position.y - nextNode->position.y) >> 16;223224if (x * x + y * y < targetDistance) {225targetNode = nextNode;226targetDistance = x * x + y * y;227}228229nextNode = nextNode->nextNode;230}231232if (targetNode) {233int32 id = 0;234EntityUFO_Circuit *nodePtr = self->curNode;235236if (self->reverse) {237for (; nodePtr != targetNode; ++id) nodePtr = nodePtr->nextNode;238}239else {240for (; nodePtr != targetNode; ++id) nodePtr = nodePtr->prevNode;241}242243if (id > UFO_Circuit->nodeCount >> 1) {244self->reverse ^= 1;245self->curNode = self->reverse ? self->curNode->prevNode : self->curNode->nextNode;246247UFO_Circuit_HandleNodeSpeeds();248return true;249}250}251}252}253254return false;255}256void UFO_Circuit_State_UFO(void)257{258RSDK_THIS(UFO_Circuit);259260if (self->groundVel >= self->topSpeed) {261if (self->groundVel > self->topSpeed) {262self->groundVel -= 0x8000;263264if (self->groundVel < self->topSpeed)265self->groundVel = self->topSpeed;266}267}268else {269self->groundVel += 0x8000;270271if (self->groundVel > self->topSpeed)272self->groundVel = self->topSpeed;273}274275self->topSpeed = UFO_Player->maxSpeed - (UFO_Player->maxSpeed - 0x70000) / 3;276self->velocity.x += (((-self->groundVel >> 8) * RSDK.Cos256(self->angle)) - self->velocity.x) >> 3;277self->velocity.y += (((-self->groundVel >> 8) * RSDK.Sin256(self->angle)) - self->velocity.y) >> 3;278279self->position.x += self->velocity.x;280self->position.y += self->velocity.y;281282self->angleY = 4 * RSDK.ATan2(self->velocity.y, -self->velocity.x);283if (!UFO_Circuit_CheckNodeChange()) {284EntityUFO_Circuit *curNode = self->curNode;285int32 rx = (self->position.x - curNode->startPos.x) >> 16;286int32 ry = 0;287int32 rz = (self->position.y - curNode->startPos.y) >> 16;288289if (rx * rx + rz * rz < self->groundVel >> 5) {290self->curNode = self->reverse ? curNode->prevNode : curNode->nextNode;291292UFO_Circuit_HandleNodeSpeeds();293}294295if (!UFO_Setup->timedOut) {296foreach_active(UFO_Player, player)297{298rx = (self->position.x - player->position.x) >> 16;299ry = (self->height - player->height - 0xA0000) >> 16;300rz = (self->position.y - player->position.y) >> 16;301302int32 dist = rx * rx + ry * ry + rz * rz;303if (!UFO_Setup->machLevel && dist < 0xC000)304self->topSpeed += (abs(player->velocity.y) + abs(player->velocity.x)) >> 1;305306if (dist >= 0x6000) {307if (dist > 0xC0000) {308if (UFO_Setup->machLevel) {309if (UFO_Setup->machLevel == 1 || abs(player->velocity.y) + abs(player->velocity.x) >= self->topSpeed >> 1310|| self->groundVel <= 0xC0 * self->topSpeed >> 8)311continue;312313self->groundVel -= UFO_Circuit->decelerationMach;314}315else {316if (self->groundVel > 0xC0 * self->topSpeed >> 8)317self->groundVel -= UFO_Circuit->decelerationNoMach;318}319}320}321else {322player->timer = 0;323player->circuitPtr = self;324player->stateInput = StateMachine_None;325player->state = UFO_Player_State_UFOCaught_Charge;326self->state = UFO_Circuit_State_Caught;327328SceneInfo->timeEnabled = false;329}330}331}332}333}334void UFO_Circuit_State_Caught(void)335{336RSDK_THIS(UFO_Circuit);337338self->velocity.x -= self->velocity.x >> 4;339self->velocity.y -= self->velocity.y >> 4;340self->position.x += self->velocity.x;341self->position.y += self->velocity.y;342}343344#if GAME_INCLUDE_EDITOR345void UFO_Circuit_EditorDraw(void)346{347RSDK_THIS(UFO_Circuit);348349RSDK.SetSpriteAnimation(UFO_Circuit->aniFrames, 0, &self->ufoAnimator, true, self->startNode ? 4 : 5);350351RSDK.DrawSprite(&self->ufoAnimator, NULL, false);352353self->active = showGizmos() ? ACTIVE_NORMAL : ACTIVE_BOUNDS;354355if (self->startNode && showGizmos()) {356RSDK_DRAWING_OVERLAY(true);357358int32 id = RSDK.GetEntitySlot(self) + 1;359360EntityUFO_Circuit *lastNode = self;361EntityUFO_Circuit *nextNode = RSDK_GET_ENTITY(id++, UFO_Circuit);362while (nextNode != self) {363364if (nextNode && nextNode->classID == UFO_Circuit->classID) {365DrawHelpers_DrawArrow(lastNode->position.x, lastNode->position.y, nextNode->position.x, nextNode->position.y, 0x00FF00, INK_NONE,3660xFF);367368lastNode = nextNode;369}370371nextNode = RSDK_GET_ENTITY(id++, UFO_Circuit);372if (id >= TEMPENTITY_START)373id = RESERVE_ENTITY_COUNT;374}375376if (lastNode && lastNode->classID == UFO_Circuit->classID) {377DrawHelpers_DrawArrow(lastNode->position.x, lastNode->position.y, self->position.x, self->position.y, 0x00FF00, INK_NONE, 0xFF);378}379380RSDK_DRAWING_OVERLAY(false);381}382}383384void UFO_Circuit_EditorLoad(void)385{386UFO_Circuit->aniFrames = RSDK.LoadSpriteAnimation("Global/PlaneSwitch.bin", SCOPE_STAGE);387388RSDK_ACTIVE_VAR(UFO_Circuit, mode);389RSDK_ENUM_VAR("(Unused)", UFO_CIRCUIT_MODE_UNUSED);390391RSDK_ACTIVE_VAR(UFO_Circuit, throttle);392RSDK_ENUM_VAR("Invalid", UFO_CIRCUIT_THRTLE_INVALID);393RSDK_ENUM_VAR("None", UFO_CIRCUIT_THRTLE_NONE);394RSDK_ENUM_VAR("Slow", UFO_CIRCUIT_THRTLE_SLOW);395RSDK_ENUM_VAR("Medium", UFO_CIRCUIT_THRTLE_MED);396RSDK_ENUM_VAR("Fast", UFO_CIRCUIT_THRTLE_FAST);397}398#endif399400void UFO_Circuit_Serialize(void)401{402RSDK_EDITABLE_VAR(UFO_Circuit, VAR_UINT8, mode);403RSDK_EDITABLE_VAR(UFO_Circuit, VAR_UINT8, throttle);404RSDK_EDITABLE_VAR(UFO_Circuit, VAR_BOOL, startNode);405RSDK_EDITABLE_VAR(UFO_Circuit, VAR_BOOL, reverse);406}407408409