Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/SPZ/CableWarp.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: CableWarp Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectCableWarp *CableWarp;
11
12
void CableWarp_Update(void)
13
{
14
RSDK_THIS(CableWarp);
15
16
StateMachine_Run(self->state);
17
}
18
19
void CableWarp_LateUpdate(void) {}
20
21
void CableWarp_StaticUpdate(void) {}
22
23
void CableWarp_Draw(void)
24
{
25
RSDK_THIS(CableWarp);
26
27
RSDK.DrawSprite(&self->animator, NULL, false);
28
}
29
30
void CableWarp_Create(void *data)
31
{
32
RSDK_THIS(CableWarp);
33
34
if (!SceneInfo->inEditor) {
35
if (data)
36
self->type = VOID_TO_INT(data);
37
38
self->active = ACTIVE_BOUNDS;
39
self->updateRange.x = 0x400000;
40
self->updateRange.y = 0x400000;
41
self->drawGroup = Zone->objectDrawGroup[1];
42
self->alpha = 0x100;
43
44
switch (self->type) {
45
case CABLEWARP_ENTRY:
46
self->visible = true;
47
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &self->animator, true, 0);
48
self->state = CableWarp_State_CablePlug;
49
break;
50
51
case CABLEWARP_EXIT:
52
self->visible = true;
53
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &self->animator, true, 2);
54
self->state = CableWarp_State_CheckPlayerEntry;
55
break;
56
57
case CABLEWARP_NODE: self->visible = false; break;
58
59
case CABLEWARP_TRANSPORT:
60
self->visible = false;
61
self->active = ACTIVE_NORMAL;
62
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 1, &self->animator, true, 0);
63
self->state = CableWarp_StateTransport_BeginEnter;
64
break;
65
66
default: break;
67
}
68
}
69
}
70
71
void CableWarp_StageLoad(void)
72
{
73
CableWarp->aniFrames = RSDK.LoadSpriteAnimation("SPZ2/CableWarp.bin", SCOPE_STAGE);
74
75
CableWarp->sfxCharge = RSDK.GetSfx("Stage/ElecCharge.wav");
76
CableWarp->sfxPulse = RSDK.GetSfx("Stage/ElecPulse.wav");
77
CableWarp->sfxLedgeBreak = RSDK.GetSfx("Stage/LedgeBreak.wav");
78
79
CableWarp->hitboxPlug.left = -16;
80
CableWarp->hitboxPlug.top = -16;
81
CableWarp->hitboxPlug.right = 16;
82
CableWarp->hitboxPlug.bottom = 32;
83
84
CableWarp->hitboxTransport.left = -16;
85
CableWarp->hitboxTransport.top = 0;
86
CableWarp->hitboxTransport.right = 16;
87
CableWarp->hitboxTransport.bottom = 32;
88
}
89
90
void CableWarp_State_CablePlug(void)
91
{
92
RSDK_THIS(CableWarp);
93
94
foreach_active(Player, player)
95
{
96
#if MANIA_USE_PLUS
97
int32 velY = player->velocity.y;
98
#endif
99
100
if (Player_CheckCollisionBox(player, self, &CableWarp->hitboxPlug) == C_TOP) {
101
#if MANIA_USE_PLUS
102
if (player->animator.animationID == ANI_JUMP || player->state == Player_State_DropDash
103
|| player->state == Player_State_MightyHammerDrop) {
104
if (player->state == Player_State_DropDash) {
105
player->velocity.y = -0x10000;
106
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
107
player->state = Player_State_Air;
108
}
109
else if (player->state == Player_State_MightyHammerDrop) {
110
player->velocity.y = velY;
111
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
112
player->state = Player_State_Air;
113
}
114
else {
115
player->velocity.y = -0x10000;
116
}
117
#else
118
if (player->animator.animationID == ANI_JUMP) {
119
player->velocity.y = -0x10000;
120
#endif
121
player->onGround = false;
122
123
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Fall, self->position.x - 0x80000, self->position.y - 0x80000);
124
debris->velocity.x = -0x20000;
125
debris->velocity.y = -0x20000;
126
debris->gravityStrength = 0x3800;
127
debris->drawGroup = Zone->playerDrawGroup[1];
128
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &debris->animator, true, 3);
129
130
debris = CREATE_ENTITY(Debris, Debris_State_Fall, self->position.x + 0x80000, self->position.y - 0x80000);
131
debris->velocity.x = 0x20000;
132
debris->velocity.y = -0x20000;
133
debris->gravityStrength = 0x3800;
134
debris->drawGroup = Zone->playerDrawGroup[1];
135
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &debris->animator, true, 4);
136
RSDK.PlaySfx(CableWarp->sfxLedgeBreak, false, 0xFF);
137
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &self->animator, true, 1);
138
self->state = CableWarp_State_CheckPlayerEntry;
139
140
foreach_break;
141
}
142
}
143
}
144
}
145
146
void CableWarp_State_CheckPlayerEntry(void)
147
{
148
RSDK_THIS(CableWarp);
149
150
foreach_active(Player, player)
151
{
152
if (Player_CheckCollisionBox(player, self, &CableWarp->hitboxTransport) == C_TOP && !self->type) {
153
player->state = Player_State_Static;
154
player->nextAirState = StateMachine_None;
155
player->nextGroundState = StateMachine_None;
156
player->tileCollisions = TILECOLLISION_NONE;
157
player->interaction = false;
158
player->onGround = false;
159
player->velocity.x = 0;
160
player->velocity.y = 0;
161
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
162
163
EntityCableWarp *warp = CREATE_ENTITY(CableWarp, INT_TO_VOID(CABLEWARP_TRANSPORT), self->position.x, self->position.y);
164
warp->isPermanent = true;
165
warp->player = player;
166
167
warp->slotID = SceneInfo->entitySlot;
168
if (self->type) {
169
warp->nextSlot = warp->slotID - 1;
170
EntityCableWarp *nextNode = RSDK_GET_ENTITY(warp->nextSlot, CableWarp);
171
if (nextNode->classID != CableWarp->classID || nextNode->type != CABLEWARP_NODE)
172
warp->nextSlot += 2;
173
}
174
else {
175
warp->nextSlot = warp->slotID + 1;
176
EntityCableWarp *nextNode = RSDK_GET_ENTITY(warp->nextSlot, CableWarp);
177
if (nextNode->classID == CableWarp->classID) {
178
if (nextNode->type != CABLEWARP_NODE)
179
warp->nextSlot -= 2;
180
}
181
else {
182
warp->nextSlot -= 2;
183
}
184
}
185
}
186
}
187
}
188
189
void CableWarp_StateTransport_BeginEnter(void)
190
{
191
RSDK_THIS(CableWarp);
192
EntityPlayer *player = (EntityPlayer *)self->player;
193
194
if (player->state == Player_State_Static) {
195
int32 x = self->position.x;
196
int32 y = self->position.y - 0x200000;
197
198
if (player->animator.speed < 0xF0)
199
player->animator.speed += 8;
200
201
player->velocity.x += ((x - player->position.x) >> 5) - (player->velocity.x >> 4);
202
player->velocity.y += ((y - player->position.y) >> 5) - (player->velocity.y >> 4);
203
204
if (++self->timer == 30) {
205
player->position.x = x;
206
player->position.y = y;
207
player->velocity.x = 0;
208
player->velocity.y = 0;
209
self->visible = true;
210
self->state = CableWarp_StateTransport_Enter;
211
RSDK.PlaySfx(CableWarp->sfxCharge, false, 0xFF);
212
}
213
}
214
else {
215
destroyEntity(self);
216
}
217
}
218
219
void CableWarp_StateTransport_Enter(void)
220
{
221
RSDK_THIS(CableWarp);
222
223
EntityPlayer *player = self->player;
224
if (player->state == Player_State_Static) {
225
RSDK.ProcessAnimation(&self->animator);
226
227
if (self->animator.frameID == 20) {
228
player->visible = false;
229
player->velocity.y = 0x60000;
230
RSDK.PlaySfx(CableWarp->sfxPulse, false, 0xFF);
231
}
232
else if (self->animator.frameID == self->animator.frameCount - 1) {
233
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 2, &self->animator, true, 0);
234
self->inkEffect = INK_ADD;
235
EntityCableWarp *nextNode = RSDK_GET_ENTITY(self->nextSlot, CableWarp);
236
int32 angle = RSDK.ATan2((nextNode->position.x - player->position.x) >> 16, (nextNode->position.y - player->position.y) >> 16);
237
self->angle = angle;
238
self->rotation = 2 * angle;
239
player->velocity.x = RSDK.Cos256(self->angle) << 12;
240
player->velocity.y = RSDK.Sin256(self->angle) << 12;
241
self->drawFX = FX_ROTATE | FX_FLIP;
242
self->state = CableWarp_StateTransport_MoveToNextNode;
243
}
244
}
245
else {
246
destroyEntity(self);
247
}
248
}
249
250
void CableWarp_StateTransport_MoveToNextNode(void)
251
{
252
RSDK_THIS(CableWarp);
253
254
EntityPlayer *player = self->player;
255
if (player->state == Player_State_Static) {
256
RSDK.ProcessAnimation(&self->animator);
257
self->position.x = player->position.x;
258
self->position.y = player->position.y;
259
RSDK_GET_ENTITY(self->slotID, CableWarp);
260
261
EntityCableWarp *nextNode = RSDK_GET_ENTITY(self->nextSlot, CableWarp);
262
int32 rx = (nextNode->position.x - player->position.x) >> 16;
263
int32 ry = (nextNode->position.y - player->position.y) >> 16;
264
if (rx * rx + ry * ry < 0x100) {
265
player->position.x = nextNode->position.x;
266
player->position.y = nextNode->position.y;
267
268
if (self->slotID >= self->nextSlot) {
269
self->nextSlot--;
270
self->slotID--;
271
}
272
else {
273
self->nextSlot++;
274
self->slotID++;
275
}
276
277
nextNode = RSDK_GET_ENTITY(self->nextSlot, CableWarp);
278
int32 angle = RSDK.ATan2((nextNode->position.x - player->position.x) >> 16, (nextNode->position.y - player->position.y) >> 16);
279
self->angle = angle;
280
self->rotation = 2 * angle + 128;
281
player->velocity.x = RSDK.Cos256(self->angle) << 12;
282
player->velocity.y = (RSDK.Sin256(self->angle) << 12);
283
if (nextNode->type != CABLEWARP_NODE)
284
self->state = CableWarp_StateTransport_EndNode;
285
}
286
}
287
else {
288
destroyEntity(self);
289
}
290
}
291
292
void CableWarp_StateTransport_EndNode(void)
293
{
294
RSDK_THIS(CableWarp);
295
EntityPlayer *player = (EntityPlayer *)self->player;
296
297
if (player->state == Player_State_Static) {
298
RSDK.ProcessAnimation(&self->animator);
299
self->position.x = player->position.x;
300
self->position.y = player->position.y;
301
302
RSDK_GET_ENTITY(self->slotID, CableWarp);
303
EntityCableWarp *nextNode = RSDK_GET_ENTITY(self->nextSlot, CableWarp);
304
305
int32 rx = (nextNode->position.x - player->position.x) >> 16;
306
int32 ry = (nextNode->position.y - player->position.y) >> 16;
307
if (rx * rx + ry * ry < 0x100) {
308
player->position.x = nextNode->position.x;
309
player->position.y = nextNode->position.y;
310
player->velocity.x = 0;
311
player->velocity.y = -0x80000;
312
if (nextNode->state == CableWarp_State_CablePlug) {
313
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Fall, nextNode->position.x - 0x80000, nextNode->position.y - 0x80000);
314
debris->velocity.x = -0x20000;
315
debris->velocity.y = -0x20000;
316
debris->gravityStrength = 0x3800;
317
debris->drawGroup = Zone->playerDrawGroup[1];
318
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &debris->animator, true, 3);
319
320
debris = CREATE_ENTITY(Debris, Debris_State_Fall, nextNode->position.x + 0x80000, nextNode->position.y - 0x80000);
321
debris->velocity.x = 0x20000;
322
debris->velocity.y = -0x20000;
323
debris->gravityStrength = 0x3800;
324
debris->drawGroup = Zone->playerDrawGroup[1];
325
326
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &debris->animator, true, 4);
327
RSDK.PlaySfx(CableWarp->sfxLedgeBreak, false, 255);
328
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &nextNode->animator, true, 1);
329
nextNode->state = CableWarp_State_CheckPlayerEntry;
330
}
331
RSDK.SetSpriteAnimation(CableWarp->aniFrames, 3, &self->animator, true, 0);
332
self->timer = 0;
333
self->state = CableWarp_StateTransport_Exit;
334
self->inkEffect = INK_NONE;
335
RSDK.PlaySfx(CableWarp->sfxPulse, false, 255);
336
}
337
}
338
else {
339
destroyEntity(self);
340
}
341
}
342
343
void CableWarp_StateTransport_Exit(void)
344
{
345
RSDK_THIS(CableWarp);
346
EntityPlayer *player = (EntityPlayer *)self->player;
347
348
RSDK.ProcessAnimation(&self->animator);
349
++self->timer;
350
if (self->animator.frameID == self->animator.frameCount - 1) {
351
player->state = Player_State_Air;
352
player->visible = true;
353
player->tileCollisions = TILECOLLISION_DOWN;
354
player->interaction = true;
355
player->applyJumpCap = false;
356
player->velocity.y = -0xA0000;
357
player->position.y = self->position.y - 0x180000;
358
destroyEntity(self);
359
}
360
}
361
362
#if GAME_INCLUDE_EDITOR
363
void CableWarp_EditorDraw(void)
364
{
365
RSDK_THIS(CableWarp);
366
367
self->updateRange.x = 0x400000;
368
self->updateRange.y = 0x400000;
369
switch (self->type) {
370
case CABLEWARP_ENTRY: RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &self->animator, true, 0); break;
371
case CABLEWARP_EXIT: RSDK.SetSpriteAnimation(CableWarp->aniFrames, 0, &self->animator, true, 2); break;
372
case CABLEWARP_NODE: RSDK.SetSpriteAnimation(CableWarp->aniFrames, 4, &self->animator, true, 2); break;
373
default: break;
374
}
375
376
CableWarp_Draw();
377
378
if (showGizmos()) {
379
RSDK_DRAWING_OVERLAY(true);
380
381
self->inkEffect = INK_BLEND;
382
383
int32 slotID = SceneInfo->entitySlot;
384
int32 nextSlot = -1;
385
switch (self->type) {
386
case CABLEWARP_ENTRY: {
387
nextSlot = slotID + 1;
388
EntityCableWarp *nextNode = RSDK_GET_ENTITY(nextSlot, CableWarp);
389
if (nextNode && nextNode->classID == CableWarp->classID) {
390
if (nextNode->type != CABLEWARP_NODE)
391
nextSlot -= 2;
392
}
393
else {
394
nextSlot -= 2;
395
}
396
break;
397
}
398
399
case CABLEWARP_EXIT: {
400
nextSlot = slotID - 1;
401
EntityCableWarp *nextNode = RSDK_GET_ENTITY(nextSlot, CableWarp);
402
if (nextNode && (nextNode->classID != CableWarp->classID || nextNode->type != CABLEWARP_NODE))
403
nextSlot += 2;
404
break;
405
}
406
407
default: break;
408
}
409
410
if (nextSlot != -1) {
411
EntityCableWarp *lastNode = RSDK_GET_ENTITY(slotID, CableWarp);
412
while (lastNode) {
413
EntityCableWarp *nextNode = RSDK_GET_ENTITY(nextSlot, CableWarp);
414
if (!nextNode)
415
break;
416
417
DrawHelpers_DrawArrow(lastNode->position.x, lastNode->position.y, nextNode->position.x, nextNode->position.y, 0xFFFF00, INK_NONE,
418
0xFF);
419
420
if (nextNode->type != CABLEWARP_NODE)
421
break;
422
423
if (slotID >= nextSlot) {
424
nextSlot--;
425
slotID--;
426
}
427
else {
428
nextSlot++;
429
slotID++;
430
}
431
432
lastNode = nextNode;
433
}
434
}
435
436
self->inkEffect = INK_NONE;
437
438
RSDK_DRAWING_OVERLAY(false);
439
}
440
}
441
442
void CableWarp_EditorLoad(void)
443
{
444
CableWarp->aniFrames = RSDK.LoadSpriteAnimation("SPZ2/CableWarp.bin", SCOPE_STAGE);
445
446
RSDK_ACTIVE_VAR(CableWarp, type);
447
RSDK_ENUM_VAR("Entry", CABLEWARP_ENTRY);
448
RSDK_ENUM_VAR("Exit", CABLEWARP_EXIT);
449
RSDK_ENUM_VAR("Warp Node", CABLEWARP_NODE);
450
}
451
#endif
452
453
void CableWarp_Serialize(void) { RSDK_EDITABLE_VAR(CableWarp, VAR_ENUM, type); }
454
455