Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/Cutscene/RubyPortal.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: RubyPortal Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectRubyPortal *RubyPortal;
11
12
void RubyPortal_Update(void)
13
{
14
RSDK_THIS(RubyPortal);
15
16
RSDK.ProcessAnimation(&self->animator);
17
18
StateMachine_Run(self->state);
19
}
20
21
void RubyPortal_LateUpdate(void) {}
22
23
void RubyPortal_StaticUpdate(void) {}
24
25
void RubyPortal_Draw(void)
26
{
27
RSDK_THIS(RubyPortal);
28
29
RSDK.CopyPalette(0, 160, 1, 160, 16);
30
RSDK.CopyPalette(2, 160, 0, 160, 16);
31
32
RSDK.DrawSprite(&self->animator, NULL, false);
33
34
RSDK.CopyPalette(1, 160, 0, 160, 16);
35
}
36
37
void RubyPortal_Create(void *data)
38
{
39
RSDK_THIS(RubyPortal);
40
41
self->drawFX = FX_SCALE;
42
self->inkEffect = INK_ALPHA;
43
44
if (!SceneInfo->inEditor) {
45
self->active = ACTIVE_BOUNDS;
46
self->visible = true;
47
self->drawGroup = Zone->objectDrawGroup[0];
48
self->updateRange.x = TO_FIXED(128);
49
self->updateRange.y = TO_FIXED(128);
50
51
RSDK.SetSpriteAnimation(RubyPortal->aniFrames, 0, &self->animator, true, 0);
52
53
#if MANIA_USE_PLUS
54
if (data) {
55
self->state = (Type_StateMachine)data;
56
}
57
else if (RSDK.CheckSceneFolder("ERZ")) {
58
self->state = StateMachine_None;
59
}
60
else if (RSDK.CheckSceneFolder("TMZ2")) {
61
EntityWarpDoor *door = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor);
62
63
if (door->classID == WarpDoor->classID) {
64
self->hitbox = door->hitbox;
65
door->hitbox.left = 0;
66
door->hitbox.top = 0x7FFF;
67
door->hitbox.right = 0;
68
door->hitbox.bottom = 0x7FFF;
69
}
70
71
self->state = RubyPortal_State_AwaitOpenTMZ2;
72
73
if (StarPost->postIDs[0])
74
TMZ2Setup_DrawDynTiles_Ruby();
75
else
76
TMZ2Setup_DrawDynTiles_Eggman();
77
}
78
else {
79
self->state = RubyPortal_State_Opening;
80
}
81
#else
82
self->state = StateMachine_None;
83
84
if (!RSDK.CheckSceneFolder("ERZ")) {
85
EntityWarpDoor *door = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor);
86
87
if (door->classID == WarpDoor->classID) {
88
self->hitbox = door->hitbox;
89
door->hitbox.left = 0;
90
door->hitbox.top = 0x7FFF;
91
door->hitbox.right = 0;
92
door->hitbox.bottom = 0x7FFF;
93
}
94
95
self->state = RubyPortal_State_AwaitOpenTMZ2;
96
97
if (StarPost->postIDs[0])
98
TMZ2Setup_DrawDynTiles_Ruby();
99
else
100
TMZ2Setup_DrawDynTiles_Eggman();
101
}
102
#endif
103
}
104
}
105
106
void RubyPortal_StageLoad(void)
107
{
108
if (RSDK.CheckSceneFolder("ERZ"))
109
RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("Phantom/Portal.bin", SCOPE_STAGE);
110
#if MANIA_USE_PLUS
111
else if (RSDK.CheckSceneFolder("AIZ"))
112
RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("AIZ/Portal.bin", SCOPE_STAGE);
113
else
114
#else // preplus has an explicit check
115
else if (RSDK.CheckSceneFolder("TMZ2"))
116
#endif
117
RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/Portal.bin", SCOPE_STAGE);
118
119
RubyPortal->hitbox.left = -24;
120
RubyPortal->hitbox.top = -24;
121
RubyPortal->hitbox.right = 24;
122
RubyPortal->hitbox.bottom = 24;
123
124
#if MANIA_USE_PLUS
125
RubyPortal->openPortal = false;
126
RSDK.AddViewableVariable("Open Portal", &RubyPortal->openPortal, VIEWVAR_BOOL, false, true);
127
#endif
128
}
129
130
#if MANIA_USE_PLUS
131
void RubyPortal_HandleTileDestruction(void)
132
{
133
RSDK_THIS(RubyPortal);
134
135
if (!(Zone->timer & 1)) {
136
int32 tx = ((self->position.x - 0x180000) >> 20);
137
int32 spawnX = (tx << 20) + 0x80000;
138
139
for (int32 x = 0; x < 4; ++x) {
140
int32 ty = (self->position.y >> 20) - 8;
141
int32 spawnY = (ty << 20) + 0x80000;
142
143
for (int32 y = 4; y < 52; y += 3) {
144
uint16 tile = RSDK.GetTile(Zone->fgLayer[0], tx, ty);
145
if (tile != (uint16)-1) {
146
EntityBreakableWall *wall = CREATE_ENTITY(BreakableWall, INT_TO_VOID(BREAKWALL_TILE_FIXED), spawnX, spawnY);
147
148
wall->drawGroup = Zone->objectDrawGroup[0] + 1;
149
wall->targetLayer = Zone->fgLayer[0];
150
wall->tileInfo = tile;
151
wall->drawFX = FX_SCALE | FX_ROTATE | FX_FLIP;
152
wall->tilePos.x = tx;
153
wall->tilePos.y = ty;
154
wall->timer = y;
155
wall->scale.x = 0x200;
156
wall->scale.y = 0x200;
157
wall->velocity.x = RSDK.Rand(-0x20000, 0x20000);
158
wall->velocity.y = RSDK.Rand(-0x20000, 0x20000);
159
wall->gravityStrength = 0;
160
wall->active = ACTIVE_NORMAL;
161
162
RSDK.SetTile(Zone->fgLayer[0], tx, ty, -1);
163
}
164
165
tile = RSDK.GetTile(Zone->fgLayer[1], tx, ty);
166
if (tile != (uint16)-1) {
167
EntityBreakableWall *wall = CREATE_ENTITY(BreakableWall, INT_TO_VOID(BREAKWALL_TILE_FIXED), spawnX, spawnY);
168
169
wall->drawGroup = Zone->objectDrawGroup[1];
170
wall->targetLayer = Zone->fgLayer[1];
171
wall->tileInfo = tile;
172
wall->drawFX = FX_SCALE | FX_ROTATE | FX_FLIP;
173
wall->tilePos.x = tx;
174
wall->tilePos.y = ty;
175
wall->timer = y;
176
wall->scale.x = 0x200;
177
wall->scale.y = 0x200;
178
wall->velocity.x = RSDK.Rand(-0x20000, 0x20000);
179
wall->velocity.y = RSDK.Rand(-0x20000, 0x20000);
180
wall->gravityStrength = 0;
181
wall->active = ACTIVE_NORMAL;
182
183
RSDK.SetTile(Zone->fgLayer[1], tx, ty, -1);
184
}
185
186
spawnY += 0x100000;
187
ty++;
188
}
189
190
spawnX += 0x100000;
191
tx++;
192
}
193
}
194
}
195
#endif
196
197
void RubyPortal_State_AwaitOpenTMZ2(void)
198
{
199
RSDK_THIS(RubyPortal);
200
201
#if MANIA_USE_PLUS
202
if (TMZBarrier->clearedBarriers == (1 | 2 | 4 | 8) || RubyPortal->openPortal)
203
#else
204
if (TMZBarrier->clearedBarriers == (1 | 2 | 4 | 8))
205
#endif
206
self->state = RubyPortal_State_Opening;
207
}
208
209
void RubyPortal_State_Opening(void)
210
{
211
RSDK_THIS(RubyPortal);
212
213
if (++self->timer >= 120) {
214
self->visible = true;
215
216
#if MANIA_USE_PLUS
217
if (globals->gameMode == MODE_MANIA)
218
self->state = RubyPortal_State_Opened;
219
else if (!isMainGameMode())
220
self->state = RubyPortal_State_Open_WarpDoor;
221
else if (WarpDoor)
222
self->state = RubyPortal_State_Opened;
223
else if (self->timer >= 240)
224
self->state = RubyPortal_State_Open_Cutscene;
225
#else
226
if (!isMainGameMode())
227
self->state = RubyPortal_State_Open_WarpDoor;
228
else
229
self->state = RubyPortal_State_Opened;
230
#endif
231
}
232
}
233
234
void RubyPortal_State_Opened(void)
235
{
236
RSDK_THIS(RubyPortal);
237
238
if (self->alpha >= 0x100) {
239
if (RSDK.CheckSceneFolder("ERZ")) {
240
self->state = StateMachine_None;
241
}
242
else {
243
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
244
if (Player_CheckCollisionTouch(player1, self, &RubyPortal->hitbox)) {
245
for (int32 p = 0; p < Player->playerCount; ++p) StarPost->postIDs[p] = 0;
246
247
SaveGame_SavePlayerState();
248
249
#if !MANIA_USE_PLUS && GAME_VERSION != VER_100
250
if (player1->superState == SUPERSTATE_SUPER)
251
globals->restartPowerups |= 0x80;
252
#endif
253
254
globals->suppressAutoMusic = true;
255
globals->suppressTitlecard = true;
256
257
if (player1->invincibleTimer <= 1) {
258
if (player1->speedShoesTimer > 1)
259
player1->speedShoesTimer = 1;
260
}
261
else {
262
player1->invincibleTimer = 1;
263
}
264
265
++SceneInfo->listPos;
266
if (!RSDK.CheckValidScene())
267
RSDK.SetScene("Presentation", "Title Screen");
268
269
Zone_StartFadeOut(16, 0xF0F0F0);
270
271
#if MANIA_USE_PLUS
272
self->state = RubyPortal_State_SaveGameState;
273
#else
274
self->state = StateMachine_None;
275
#endif
276
277
int32 sfx = RSDK.Rand(0, RUBYSFX_ATTACK6);
278
int32 channel = RSDK.PlaySfx(WarpDoor->sfxRubyAttackL[sfx], false, 0x00);
279
RSDK.SetChannelAttributes(channel, 1.0, -1.0, 1.0);
280
281
channel = RSDK.PlaySfx(WarpDoor->sfxRubyAttackR[sfx], false, 0x00);
282
RSDK.SetChannelAttributes(channel, 1.0, 1.0, 1.0);
283
}
284
}
285
}
286
else {
287
self->scale.x += 8;
288
self->scale.y += 8;
289
self->alpha += 4;
290
}
291
}
292
293
#if MANIA_USE_PLUS
294
void RubyPortal_State_SaveGameState(void)
295
{
296
EntityPlayer *player = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
297
298
if (player->superState == SUPERSTATE_SUPER || player->state == Player_State_Transform)
299
globals->restartPowerups |= 0x80;
300
301
globals->restartMusicID = Music->activeTrack;
302
}
303
#endif
304
305
void RubyPortal_State_Open_WarpDoor(void)
306
{
307
RSDK_THIS(RubyPortal);
308
309
if (self->alpha >= 0x100) {
310
EntityWarpDoor *warpDoor = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, WarpDoor);
311
if (warpDoor->classID == WarpDoor->classID)
312
warpDoor->hitbox = self->hitbox;
313
314
self->state = StateMachine_None;
315
}
316
else {
317
self->scale.x += 8;
318
self->scale.y += 8;
319
320
self->alpha += 4;
321
}
322
}
323
324
void RubyPortal_State_Open_Cutscene(void)
325
{
326
RSDK_THIS(RubyPortal);
327
328
if (self->alpha >= 0x100) {
329
self->state = StateMachine_None;
330
}
331
else {
332
self->scale.x += 8;
333
self->scale.y += 8;
334
self->alpha += 4;
335
}
336
}
337
338
#if MANIA_USE_PLUS
339
void RubyPortal_State_EncoreEnd(void)
340
{
341
RSDK_THIS(RubyPortal);
342
343
if (!self->timer)
344
self->visible = true;
345
346
self->timer++;
347
if (self->alpha >= 0x100) {
348
if (self->timer == 240) {
349
self->timer = 0;
350
self->state = RubyPortal_State_EncoreRampage;
351
352
EntityFXFade *fade = CREATE_ENTITY(FXFade, INT_TO_VOID(0xF0F0F0), self->position.x, self->position.y);
353
fade->speedIn = 512;
354
fade->wait = 16;
355
fade->speedOut = 16;
356
357
PhantomRuby_PlaySfx(RUBYSFX_ATTACK1);
358
}
359
}
360
else {
361
self->scale.x += 8;
362
self->scale.y += 8;
363
self->alpha += 4;
364
}
365
}
366
367
void RubyPortal_State_EncoreRampage(void)
368
{
369
RSDK_THIS(RubyPortal);
370
371
RubyPortal_HandleTileDestruction();
372
373
self->position.x += self->velocity.x;
374
375
foreach_active(BreakableWall, wall)
376
{
377
int32 rx = (self->position.x - wall->position.x) >> 16;
378
int32 ry = (self->position.y - wall->position.y) >> 16;
379
int32 angle = RSDK.ATan2(rx, ry);
380
381
wall->velocity.x += 8 * RSDK.Cos256(angle);
382
wall->velocity.y += 8 * RSDK.Sin256(angle);
383
wall->position.x += self->velocity.x;
384
385
++wall->timer;
386
if (wall->timer == 60) {
387
wall->inkEffect = INK_ALPHA;
388
wall->alpha = 0x100;
389
}
390
else if (wall->timer > 60) {
391
wall->alpha -= 8;
392
}
393
394
if (rx * rx + ry * ry < 0x900) {
395
wall->scale.x -= 0x0C;
396
wall->scale.y -= 0x0C;
397
wall->velocity.x = (self->position.x - wall->position.x) >> 3;
398
wall->velocity.y = (self->position.y - wall->position.y) >> 3;
399
400
if (wall->scale.x <= 0)
401
destroyEntity(wall);
402
}
403
}
404
405
foreach_active(Debris, debris)
406
{
407
int32 rx = (self->position.x - debris->position.x) >> 16;
408
int32 ry = (self->position.y - debris->position.y) >> 16;
409
if (rx * rx + ry * ry < 0x900) {
410
debris->scale.x -= 0x0C;
411
debris->scale.y -= 0x0C;
412
413
debris->gravityStrength = 0;
414
debris->position.x += self->velocity.x;
415
debris->velocity.x = (self->position.x - debris->position.x) >> 3;
416
debris->velocity.y = (self->position.y - debris->position.y) >> 3;
417
418
if (debris->scale.x <= 0)
419
destroyEntity(debris);
420
}
421
}
422
423
foreach_active(PhantomRuby, ruby) { ruby->position.x += self->velocity.x; }
424
}
425
#endif
426
427
#if GAME_INCLUDE_EDITOR
428
void RubyPortal_EditorDraw(void)
429
{
430
RSDK_THIS(RubyPortal);
431
432
self->visible = true;
433
self->drawGroup = Zone->objectDrawGroup[0];
434
self->scale.x = 0x200;
435
self->scale.y = 0x200;
436
self->alpha = 0xFF;
437
RSDK.SetSpriteAnimation(RubyPortal->aniFrames, 0, &self->animator, true, 0);
438
439
RSDK.DrawSprite(&self->animator, NULL, false);
440
}
441
442
void RubyPortal_EditorLoad(void)
443
{
444
if (RSDK.CheckSceneFolder("ERZ"))
445
RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("Phantom/Portal.bin", SCOPE_STAGE);
446
#if MANIA_USE_PLUS
447
else if (RSDK.CheckSceneFolder("AIZ"))
448
RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("AIZ/Portal.bin", SCOPE_STAGE);
449
else
450
#else // preplus has an explicit check
451
else if (RSDK.CheckSceneFolder("TMZ2"))
452
#endif
453
RubyPortal->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/Portal.bin", SCOPE_STAGE);
454
}
455
#endif
456
457
void RubyPortal_Serialize(void) {}
458
459