Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/CPZ/TransportTube.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: TransportTube Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectTransportTube *TransportTube;
11
12
void TransportTube_Update(void)
13
{
14
RSDK_THIS(TransportTube);
15
16
StateMachine_Run(self->state);
17
}
18
19
void TransportTube_LateUpdate(void) {}
20
21
void TransportTube_StaticUpdate(void) {}
22
23
void TransportTube_Draw(void) {}
24
25
void TransportTube_Create(void *data)
26
{
27
RSDK_THIS(TransportTube);
28
29
self->drawFX = FX_FLIP;
30
if (!SceneInfo->inEditor) {
31
self->active = ACTIVE_BOUNDS;
32
self->updateRange.x = TO_FIXED(192);
33
self->updateRange.y = TO_FIXED(192);
34
TransportTube_SetupDirections(self);
35
36
switch (self->type) {
37
case TRANSPORTTUBE_CHANGEDIR: self->state = TransportTube_State_ChangeDir; break;
38
case TRANSPORTTUBE_ENTRY: self->state = TransportTube_State_Entry; break;
39
40
case TRANSPORTTUBE_TOTARGET_NEXT:
41
case TRANSPORTTUBE_TOTARGET_PREV: self->state = TransportTube_State_ToTargetEntity; break;
42
43
case TRANSPORTTUBE_TOTARGET_NODE: self->state = TransportTube_State_TargetSeqNode; break;
44
case TRANSPORTTUBE_JUNCTION: self->state = TransportTube_State_ChooseDir; break;
45
case TRANSPORTTUBE_EXIT: self->state = TransportTube_State_Exit; break;
46
default: break;
47
}
48
}
49
}
50
51
void TransportTube_StageLoad(void) { TransportTube->sfxTravel = RSDK.GetSfx("Tube/Travel.wav"); }
52
53
void TransportTube_SetupDirections(EntityTransportTube *entity)
54
{
55
int32 velocityX[] = { 0, 0, -16, 16, 12, -12, 12, -12 };
56
int32 velocityY[] = { -16, 16, 0, 0, -12, -12, 12, 12 };
57
58
entity->directionCount = 0;
59
for (int32 i = 0; i < 8; ++i) {
60
if (entity->dirMask & (1 << i)) {
61
entity->dirVelocity[entity->directionCount].x = velocityX[i];
62
entity->dirVelocity[entity->directionCount].y = velocityY[i];
63
++entity->directionCount;
64
}
65
}
66
}
67
68
void TransportTube_HandleVelocityChange(int32 velX, int32 velY)
69
{
70
RSDK_THIS(TransportTube);
71
72
int32 id = 0;
73
int32 velStore = 0xFFFF;
74
for (int32 v = 0; v < self->directionCount; ++v) {
75
int32 x = abs(velX - self->dirVelocity[v].x);
76
int32 y = abs(velY - self->dirVelocity[v].y);
77
78
if (x + y < velStore) {
79
id = v;
80
velStore = x + y;
81
}
82
}
83
84
int32 pos = 0;
85
for (int32 v = 0; v < self->directionCount; ++v) {
86
if (v != id)
87
self->directionIDs[pos++] = v;
88
}
89
90
int32 dir = self->directionIDs[RSDK.Rand(0, self->directionCount - 1)];
91
self->velocity.x = TO_FIXED(self->dirVelocity[dir].x);
92
self->velocity.y = TO_FIXED(self->dirVelocity[dir].y);
93
}
94
95
void TransportTube_State_ChangeDir(void)
96
{
97
RSDK_THIS(TransportTube);
98
99
for (int32 i = 0; i < Player->playerCount; ++i) {
100
EntityPlayer *player = RSDK_GET_ENTITY(i, Player);
101
int32 rx = FROM_FIXED(player->position.x - self->position.x);
102
int32 ry = FROM_FIXED(player->position.y - self->position.y);
103
104
if (self->playerTimers[i]) {
105
if (rx * rx + ry * ry >= 0xC0)
106
self->playerTimers[i]--;
107
}
108
else if (player->state == Player_State_TransportTube && !TransportTube->nextSlot[i] && rx * rx + ry * ry < 0xC0) {
109
TransportTube_HandleVelocityChange(rx - FROM_FIXED(player->velocity.x), ry - FROM_FIXED(player->velocity.y));
110
player->position.x = self->position.x;
111
player->position.y = self->position.y;
112
player->velocity = self->velocity;
113
self->playerTimers[i] = 2;
114
}
115
}
116
}
117
118
void TransportTube_State_Entry(void)
119
{
120
RSDK_THIS(TransportTube);
121
122
for (int32 i = 0; i < Player->playerCount; ++i) {
123
EntityPlayer *player = RSDK_GET_ENTITY(i, Player);
124
125
if (Player_CheckValidState(player)) {
126
int32 rx = FROM_FIXED(player->position.x - self->position.x);
127
int32 ry = FROM_FIXED(player->position.y - self->position.y);
128
if (self->playerTimers[i]) {
129
if (rx * rx + ry * ry >= 0xC0)
130
self->playerTimers[i]--;
131
}
132
else if (rx * rx + ry * ry < 0xC0) {
133
player->position.x = self->position.x;
134
player->position.y = self->position.y;
135
if (player->state == Player_State_TransportTube) {
136
player->drawGroup = Zone->playerDrawGroup[0];
137
player->tileCollisions = TILECOLLISION_DOWN;
138
player->interaction = true;
139
player->state = Player_State_Air;
140
if (player->velocity.x)
141
player->direction = player->velocity.x <= 0;
142
self->playerTimers[i] = 2;
143
}
144
else {
145
TransportTube_HandleVelocityChange(rx - FROM_FIXED(player->velocity.x), ry - FROM_FIXED(player->velocity.y));
146
player->velocity = self->velocity;
147
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
148
player->drawGroup = 1;
149
player->onGround = false;
150
player->tileCollisions = TILECOLLISION_NONE;
151
player->interaction = false;
152
player->state = Player_State_TransportTube;
153
player->nextAirState = StateMachine_None;
154
player->nextGroundState = StateMachine_None;
155
TransportTube->nextSlot[i] = 0;
156
RSDK.PlaySfx(TransportTube->sfxTravel, false, 255);
157
self->playerTimers[i] = 2;
158
}
159
}
160
}
161
}
162
}
163
164
void TransportTube_State_ToTargetEntity(void)
165
{
166
RSDK_THIS(TransportTube);
167
168
for (int32 i = 0; i < Player->playerCount; ++i) {
169
EntityPlayer *player = RSDK_GET_ENTITY(i, Player);
170
int32 rx = FROM_FIXED(player->position.x - self->position.x);
171
int32 ry = FROM_FIXED(player->position.y - self->position.y);
172
173
if (self->playerTimers[i]) {
174
if (rx * rx + ry * ry >= 0xC0)
175
--self->playerTimers[i];
176
}
177
else if (player->state == Player_State_TransportTube && rx * rx + ry * ry < 0xC0) {
178
if (self->players[i]) {
179
TransportTube->nextSlot[i] = 0;
180
self->players[i] = NULL;
181
self->playerTimers[i] = 2;
182
}
183
else {
184
if (self->type == TRANSPORTTUBE_TOTARGET_NEXT)
185
TransportTube->nextSlot[i] = 1;
186
else
187
TransportTube->nextSlot[i] = -1;
188
189
EntityTransportTube *node = RSDK_GET_ENTITY(SceneInfo->entitySlot + TransportTube->nextSlot[i], TransportTube);
190
int32 angle = RSDK.ATan2(FROM_FIXED(node->position.x - player->position.x), FROM_FIXED(node->position.y - player->position.y));
191
player->velocity.x = 0xC00 * RSDK.Cos256(angle);
192
player->velocity.y = 0xC00 * RSDK.Sin256(angle);
193
node->players[i] = player;
194
self->playerTimers[i] = 2;
195
}
196
}
197
}
198
}
199
200
void TransportTube_State_TargetSeqNode(void)
201
{
202
RSDK_THIS(TransportTube);
203
204
for (int32 i = 0; i < Player->playerCount; ++i) {
205
EntityPlayer *player = self->players[i];
206
if (player) {
207
if (player->state == Player_State_TransportTube) {
208
int32 rx = FROM_FIXED(player->position.x - self->position.x);
209
int32 ry = FROM_FIXED(player->position.y - self->position.y);
210
if (rx * rx + ry * ry < 0xC0) {
211
player->position.x = self->position.x;
212
player->position.y = self->position.y;
213
214
EntityTransportTube *node = RSDK_GET_ENTITY(SceneInfo->entitySlot + TransportTube->nextSlot[i], TransportTube);
215
int32 angle = RSDK.ATan2(FROM_FIXED(node->position.x - player->position.x), FROM_FIXED(node->position.y - player->position.y));
216
player->velocity.x = 0xC00 * RSDK.Cos256(angle);
217
player->velocity.y = 0xC00 * RSDK.Sin256(angle);
218
self->players[i] = NULL;
219
node->players[i] = player;
220
}
221
}
222
else {
223
self->players[i] = NULL;
224
}
225
}
226
}
227
}
228
229
void TransportTube_State_ChooseDir(void)
230
{
231
RSDK_THIS(TransportTube);
232
233
for (int32 i = 0; i < Player->playerCount; ++i) {
234
EntityPlayer *player = RSDK_GET_ENTITY(i, Player);
235
int32 rx = FROM_FIXED(player->position.x - self->position.x);
236
int32 ry = FROM_FIXED(player->position.y - self->position.y);
237
238
if (self->playerTimers[i]) {
239
if (rx * rx + ry * ry >= 0xC0)
240
--self->playerTimers[i];
241
}
242
else if (player->state == Player_State_TransportTube && rx * rx + ry * ry < 0xC0) {
243
player->position.x = self->position.x;
244
player->position.y = self->position.y;
245
player->velocity.x = 0;
246
player->velocity.y = 0;
247
248
uint8 moveMask = self->dirMask & ((player->up << 0) | (player->down << 1) | (player->left << 2) | (player->right << 3));
249
if (moveMask & 1)
250
player->velocity.y = -0x100000;
251
else if (moveMask & 2)
252
player->velocity.y = 0x100000;
253
else if (moveMask & 4)
254
player->velocity.x = -0x100000;
255
else if (moveMask & 8)
256
player->velocity.x = 0x100000;
257
258
if (player->velocity.x || player->velocity.y) {
259
self->playerTimers[i] = 2;
260
RSDK.PlaySfx(TransportTube->sfxTravel, false, 255);
261
}
262
}
263
}
264
}
265
266
void TransportTube_State_Exit(void)
267
{
268
RSDK_THIS(TransportTube);
269
270
for (int32 i = 0; i < Player->playerCount; ++i) {
271
EntityPlayer *player = RSDK_GET_ENTITY(i, Player);
272
273
if (Player_CheckValidState(player)) {
274
int32 rx = FROM_FIXED(player->position.x - self->position.x);
275
int32 ry = FROM_FIXED(player->position.y - self->position.y);
276
277
if (self->playerTimers[i]) {
278
if (rx * rx + ry * ry >= 0xC0)
279
self->playerTimers[i]--;
280
}
281
else if (rx * rx + ry * ry < 0xC0) {
282
player->position.x = self->position.x;
283
player->position.y = self->position.y;
284
player->drawGroup = Zone->playerDrawGroup[0];
285
player->tileCollisions = TILECOLLISION_DOWN;
286
player->interaction = true;
287
player->state = Player_State_Air;
288
self->playerTimers[i] = 2;
289
}
290
}
291
}
292
}
293
294
#if GAME_INCLUDE_EDITOR
295
void TransportTube_EditorDraw(void)
296
{
297
RSDK_THIS(TransportTube);
298
self->updateRange.x = 0xC00000;
299
self->updateRange.y = 0xC00000;
300
301
RSDK.SetSpriteAnimation(TransportTube->aniFrames, 0, &self->animator, true, 0);
302
RSDK.DrawSprite(&self->animator, NULL, false);
303
304
RSDK_DRAWING_OVERLAY(true);
305
306
TransportTube_SetupDirections(self);
307
for (int32 v = 0; v < self->directionCount; ++v) {
308
DrawHelpers_DrawArrow(self->position.x, self->position.y, self->position.x + (self->dirVelocity[v].x << 18),
309
self->position.y + (self->dirVelocity[v].y << 18), 0xFF0000, INK_NONE, 0xFF);
310
}
311
312
RSDK_DRAWING_OVERLAY(false);
313
314
RSDK.SetSpriteAnimation(TransportTube->aniFrames, self->type == TRANSPORTTUBE_JUNCTION ? 1 : 2, &self->animator, true, 0);
315
RSDK.DrawSprite(&self->animator, NULL, false);
316
}
317
318
void TransportTube_EditorLoad(void)
319
{
320
TransportTube->aniFrames = RSDK.LoadSpriteAnimation("CPZ/TransportTube.bin", SCOPE_STAGE);
321
322
RSDK_ACTIVE_VAR(TransportTube, type);
323
RSDK_ENUM_VAR("Change Direction", TRANSPORTTUBE_CHANGEDIR);
324
RSDK_ENUM_VAR("Entrance", TRANSPORTTUBE_ENTRY);
325
RSDK_ENUM_VAR("Start Sequence (Next Slot)", TRANSPORTTUBE_TOTARGET_NEXT);
326
RSDK_ENUM_VAR("Start Sequence (Prev Slot)", TRANSPORTTUBE_TOTARGET_PREV);
327
RSDK_ENUM_VAR("Sequence Node", TRANSPORTTUBE_TOTARGET_NODE);
328
RSDK_ENUM_VAR("Junction", TRANSPORTTUBE_JUNCTION);
329
RSDK_ENUM_VAR("Exit", TRANSPORTTUBE_EXIT);
330
}
331
#endif
332
333
void TransportTube_Serialize(void)
334
{
335
RSDK_EDITABLE_VAR(TransportTube, VAR_UINT8, type);
336
RSDK_EDITABLE_VAR(TransportTube, VAR_UINT8, dirMask);
337
}
338
339