Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/TMZ/TMZ2Outro.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: TMZ2Outro Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectTMZ2Outro *TMZ2Outro;
11
12
void TMZ2Outro_Update(void)
13
{
14
RSDK_THIS(TMZ2Outro);
15
16
TMZ2Outro_SetupCutscene();
17
self->active = ACTIVE_NEVER;
18
19
HUD_MoveOut();
20
}
21
22
void TMZ2Outro_LateUpdate(void) {}
23
24
void TMZ2Outro_StaticUpdate(void) {}
25
26
void TMZ2Outro_Draw(void) {}
27
28
void TMZ2Outro_Create(void *data)
29
{
30
RSDK_THIS(TMZ2Outro);
31
32
self->active = ACTIVE_NORMAL;
33
foreach_all(EscapeCar, car) { self->escapeCar = car; }
34
}
35
36
void TMZ2Outro_StageLoad(void)
37
{
38
TMZ2Outro->sfxAlarm = RSDK.GetSfx("TMZ3/Alarm.wav");
39
TMZ2Outro->sfxCarRev = RSDK.GetSfx("TMZ1/CarRev.wav");
40
TMZ2Outro->sfxGrab = RSDK.GetSfx("Global/Grab.wav");
41
TMZ2Outro->sfxRumble = RSDK.GetSfx("Stage/Rumble.wav");
42
TMZ2Outro->sfxDrop = RSDK.GetSfx("Stage/Drop.wav");
43
TMZ2Outro->sfxImpact = RSDK.GetSfx("Stage/Impact2.wav");
44
TMZ2Outro->sfxRubyGet = RSDK.GetSfx("TMZ3/RubyGet.wav");
45
46
TMZ2Outro->playerID = ID_NONE;
47
}
48
49
void TMZ2Outro_SetupCutscene(void)
50
{
51
RSDK_THIS(TMZ2Outro);
52
53
#if MANIA_USE_PLUS
54
if (globals->gameMode != MODE_ENCORE) {
55
#endif
56
CutsceneSeq_StartSequence(self, TMZ2Outro_Cutscene_SetupOutro, TMZ2Outro_Cutscene_WatchEggman, TMZ2Outro_Cutscene_EggmanFall,
57
TMZ2Outro_Cutscene_StartAlert, TMZ2Outro_Cutscene_TimeToEscape, TMZ2Outro_Cutscene_HurryToCar,
58
TMZ2Outro_Cutscene_StartFadeOut, TMZ2Outro_Cutscene_FadeOut, TMZ2Outro_Cutscene_FinishSequence, StateMachine_None);
59
#if MANIA_USE_PLUS
60
}
61
else {
62
if (SaveGame_AllChaosEmeralds()) {
63
CutsceneSeq_StartSequence(self, TMZ2Outro_Cutscene_SetupOutro, TMZ2Outro_Cutscene_WatchEggman, TMZ2Outro_Cutscene_EggmanFall,
64
TMZ2Outro_Cutscene_StartRubyRampage, TMZ2Outro_Cutscene_OuttaHere, TMZ2Outro_Cutscene_TeamEscape,
65
TMZ2Outro_Cutscene_FadeOut, TMZ2Outro_Cutscene_FinishSequence, StateMachine_None);
66
}
67
else {
68
self->heavyKing = CutsceneHBH_GetEntity(HBH_KINGTMZ2);
69
CutsceneSeq_StartSequence(self, TMZ2Outro_Cutscene_SetupOutro, TMZ2Outro_Cutscene_WatchEggman, TMZ2Outro_Cutscene_EggmanFall,
70
TMZ2Outro_Cutscene_StartRubyRampage, TMZ2Outro_Cutscene_Panic, TMZ2Outro_Cutscene_OuttaHere_BadEnd,
71
TMZ2Outro_Cutscene_FadeOut, TMZ2Outro_Cutscene_FinishSequence, StateMachine_None);
72
}
73
foreach_all(TMZFlames, flames) { destroyEntity(flames); }
74
}
75
#endif
76
77
#if MANIA_USE_PLUS
78
CutsceneSeq_SetSkipType(SKIPTYPE_DISABLED);
79
#endif
80
}
81
82
bool32 TMZ2Outro_Cutscene_SetupOutro(EntityCutsceneSeq *host)
83
{
84
TMZ2Outro->playerID = globals->playerID;
85
86
foreach_active(Player, player)
87
{
88
player->stateInput = StateMachine_None;
89
if (player->superState == SUPERSTATE_SUPER)
90
player->superState = SUPERSTATE_FADEOUT;
91
92
CutsceneSeq_LockAllPlayerControl();
93
}
94
95
foreach_all(BoundsMarker, marker) { destroyEntity(marker); }
96
97
for (int32 c = 0; c < 0x100; ++c) RSDK.SetPaletteEntry(7, c, RSDK.GetPaletteEntry(1, c) & 0xFF0000);
98
99
return true;
100
}
101
102
bool32 TMZ2Outro_Cutscene_WatchEggman(EntityCutsceneSeq *host)
103
{
104
bool32 finishedMoving = true;
105
106
foreach_active(Player, player)
107
{
108
if (player->sidekick && player->characterID == ID_KNUCKLES && !CHECK_CHARACTER_ID(ID_KNUCKLES, 1)) {
109
if (player->stateInput != TMZ2Outro_PlayerStateInput_Escape) {
110
Zone->playerBoundActiveR[0] = false;
111
player->stateInput = TMZ2Outro_PlayerStateInput_Escape;
112
}
113
}
114
else {
115
int32 targetPos = PhantomEgg->boundsM + (player->playerID << 21);
116
117
if (player->position.x >= targetPos + 0x300000) {
118
if (player->position.x <= targetPos + 0x700000) {
119
player->left = false;
120
player->right = false;
121
122
if (abs(player->groundVel) < 0x8000) {
123
player->groundVel = 0;
124
player->direction = FLIP_X;
125
player->up = true;
126
continue;
127
}
128
else {
129
player->groundVel -= (player->groundVel >> 5);
130
}
131
}
132
else {
133
player->left = true;
134
player->right = false;
135
}
136
}
137
else {
138
player->left = false;
139
player->right = true;
140
}
141
142
finishedMoving = false;
143
}
144
}
145
146
if (finishedMoving) {
147
foreach_active(Player, player2)
148
{
149
if (player2->sidekick && (player2->characterID != ID_KNUCKLES || CHECK_CHARACTER_ID(ID_KNUCKLES, 2)))
150
player2->stateInput = Player_Input_P2_AI;
151
}
152
}
153
154
return finishedMoving;
155
}
156
157
void TMZ2Outro_PlayerStateInput_Escape(void)
158
{
159
RSDK_THIS(Player);
160
161
self->up = false;
162
self->down = false;
163
self->left = false;
164
self->right = true;
165
self->jumpPress = false;
166
self->jumpHold = false;
167
168
if (self->position.x >= (2760 << 16)) {
169
self->visible = false;
170
self->interaction = false;
171
self->tileCollisions = TILECOLLISION_NONE;
172
self->right = false;
173
}
174
}
175
176
bool32 TMZ2Outro_Cutscene_EggmanFall(EntityCutsceneSeq *host)
177
{
178
bool32 eggmanOnGround = false;
179
180
foreach_active(Eggman, eggman)
181
{
182
if (eggman->onGround) {
183
RSDK.SetSpriteAnimation(Eggman->aniFrames, 8, &eggman->animator, true, 0);
184
foreach_active(Player, player) { player->up = false; }
185
186
eggmanOnGround = true;
187
foreach_break;
188
}
189
}
190
191
return eggmanOnGround;
192
}
193
194
bool32 TMZ2Outro_Cutscene_StartAlert(EntityCutsceneSeq *host)
195
{
196
if (host->timer == 120) {
197
RSDK.PlaySfx(TMZ2Outro->sfxAlarm, true, 255);
198
199
foreach_active(TMZAlert, alert)
200
{
201
alert->alpha = 16 * RSDK.Rand(-32, -8);
202
alert->state = TMZAlert_State_Activating;
203
}
204
205
return true;
206
}
207
208
return false;
209
}
210
bool32 TMZ2Outro_Cutscene_TimeToEscape(EntityCutsceneSeq *host)
211
{
212
RSDK.SetLimitedFade(0, 7, 1, (RSDK.Cos256(4 * host->timer) >> 1) + 128, 0, 256);
213
214
if (!(host->timer & 7))
215
Camera_ShakeScreen(0, 0, 4);
216
217
if (host->timer == 128) {
218
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
219
player1->right = true;
220
221
Zone->cameraBoundsR[0] += 832;
222
Zone->playerBoundActiveR[0] = false;
223
224
return true;
225
}
226
227
return false;
228
}
229
230
bool32 TMZ2Outro_Cutscene_HurryToCar(EntityCutsceneSeq *host)
231
{
232
RSDK_THIS(TMZ2Outro);
233
234
RSDK.SetLimitedFade(0, 7, 1, (RSDK.Cos256(4 * host->timer) >> 1) + 128, 0, 256);
235
236
if (!(host->timer & 7))
237
Camera_ShakeScreen(0, 0, 4);
238
239
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
240
EntityEscapeCar *escapeCar = self->escapeCar;
241
242
if (escapeCar->position.x - player1->position.x < 0x1800000)
243
player1->right = false;
244
245
if (escapeCar->position.x - player1->position.x < 0xC00000) {
246
player1->jumpPress = player1->onGround;
247
player1->jumpHold = true;
248
}
249
250
if (host->timer == 248)
251
RSDK.PlaySfx(TMZ2Outro->sfxGrab, false, 255);
252
253
if (host->timer == 384) {
254
Zone->cameraBoundsR[0] = 0x2000;
255
256
EntityCamera *camera = RSDK_GET_ENTITY(SLOT_CAMERA1, Camera);
257
camera->position.x = (camera->boundsR - ScreenInfo->center.x) << 16;
258
camera->boundsR = 0x2000;
259
camera->state = StateMachine_None;
260
261
self->velocity.x = 0;
262
return true;
263
}
264
265
return false;
266
}
267
bool32 TMZ2Outro_Cutscene_StartFadeOut(EntityCutsceneSeq *host)
268
{
269
RSDK_THIS(TMZ2Outro);
270
271
RSDK.SetLimitedFade(0, 7, 1, (RSDK.Cos256(4 * host->timer) >> 1) + 128, 0, 256);
272
273
if (host->timer == 15)
274
RSDK.PlaySfx(TMZ2Outro->sfxCarRev, false, 255);
275
276
if (!(host->timer & 7))
277
Camera_ShakeScreen(0, 0, 4);
278
279
EntityCamera *camera = RSDK_GET_ENTITY(SLOT_CAMERA1, Camera);
280
281
if (self->velocity.x < 0x170000)
282
self->velocity.x += 0x2000;
283
284
camera->position.x += self->velocity.x;
285
286
if (host->timer == 200) {
287
Music_FadeOut(0.0125);
288
RSDK.PlaySfx(PhantomEgg->sfxExplosion3, false, 255);
289
}
290
291
if (host->timer == 260)
292
RSDK.PlaySfx(PhantomEgg->sfxExplosion3, false, 255);
293
294
if (host->timer == 320) {
295
EntityFXFade *fxFade = CREATE_ENTITY(FXFade, INT_TO_VOID(0xF0F0F0), self->position.x, self->position.y);
296
fxFade->speedIn = 32;
297
fxFade->wait = 90;
298
fxFade->speedOut = 16;
299
fxFade->fadeOutBlack = true;
300
301
RSDK.PlaySfx(PhantomEgg->sfxExplosion3, false, 255);
302
303
return true;
304
}
305
306
return false;
307
}
308
309
#if MANIA_USE_PLUS
310
bool32 TMZ2Outro_Cutscene_StartRubyRampage(EntityCutsceneSeq *host)
311
{
312
if (host->timer == 60) {
313
foreach_active(PhantomRuby, ruby)
314
{
315
int32 pos = ScreenInfo->position.x + (SaveGame_AllChaosEmeralds() ? 64 : 96);
316
ruby->startPos.x = pos << 16;
317
ruby->startPos.y = (ScreenInfo->position.y + ScreenInfo->center.y) << 16;
318
ruby->velocity.y = 0;
319
ruby->isPermanent = true;
320
ruby->drawGroup = Zone->objectDrawGroup[1];
321
ruby->active = ACTIVE_NORMAL;
322
ruby->state = PhantomRuby_State_MoveToPos;
323
}
324
}
325
326
if (host->timer > 60) {
327
foreach_active(Player, player)
328
{
329
if (player->position.x >= (ScreenInfo->center.x - 64 + ScreenInfo->position.x) << 16) {
330
player->left = true;
331
player->right = false;
332
333
if (player->groundVel < -0x20000)
334
player->groundVel = -0x20000;
335
}
336
else {
337
player->up = true;
338
player->left = false;
339
player->right = false;
340
player->groundVel = 0;
341
}
342
}
343
}
344
345
if (host->timer == 120) {
346
foreach_active(TMZAlert, alert)
347
{
348
alert->alpha = 16 * RSDK.Rand(-32, -8);
349
alert->state = TMZAlert_State_Activating;
350
}
351
352
for (int32 i = 0; i < 7; ++i) RSDK.SetPaletteEntry(2, i - 96, TMZ2Outro->colors[i]);
353
354
if (SaveGame_AllChaosEmeralds()) {
355
CREATE_ENTITY(RubyPortal, RubyPortal_State_EncoreEnd, (ScreenInfo->position.x + 64) << 16,
356
(ScreenInfo->position.y + ScreenInfo->center.y) << 16);
357
}
358
359
return true;
360
}
361
362
return false;
363
}
364
bool32 TMZ2Outro_Cutscene_Panic(EntityCutsceneSeq *host)
365
{
366
if (host->timer == 90) {
367
foreach_active(Eggman, eggman)
368
{
369
RSDK.SetSpriteAnimation(Eggman->aniFrames, 9, &eggman->animator, true, 0);
370
eggman->direction = FLIP_NONE;
371
eggman->state = Eggman_State_WalkOffScreen;
372
eggman->velocity.x = 0x10000;
373
RSDK.ObjectTileGrip(eggman, Zone->collisionLayers, CMODE_FLOOR, eggman->collisionPlane, 0, 0x1C0000, 14);
374
}
375
}
376
377
if (host->timer < 120) {
378
foreach_active(Player, player)
379
{
380
if (player->position.x >= (ScreenInfo->center.x - 64 + ScreenInfo->position.x) << 16) {
381
player->left = true;
382
player->right = false;
383
384
if (player->groundVel < -0x20000)
385
player->groundVel = -0x20000;
386
}
387
else {
388
player->up = true;
389
player->left = false;
390
player->right = false;
391
player->groundVel = 0;
392
}
393
}
394
}
395
else if (host->timer == 256) {
396
foreach_active(Player, player)
397
{
398
player->up = false;
399
player->state = Player_State_Static;
400
RSDK.SetSpriteAnimation(player->aniFrames, ANI_BALANCE_1 + player->playerID, &player->animator, false, 0);
401
}
402
403
RSDK.PlaySfx(TMZ2Outro->sfxRumble, false, 255);
404
RSDK.SetChannelAttributes(RSDK.PlaySfx(TMZ2Outro->sfxCarRev, false, 255), 1.0, 0.75, 1.0);
405
Camera_ShakeScreen(0, 0, 4);
406
Zone->playerBoundActiveR[0] = false;
407
}
408
else {
409
if (host->timer == 290) {
410
foreach_active(Player, player)
411
{
412
player->state = Player_State_Ground;
413
player->left = false;
414
player->right = true;
415
}
416
417
return true;
418
}
419
}
420
421
return false;
422
}
423
bool32 TMZ2Outro_Cutscene_OuttaHere_BadEnd(EntityCutsceneSeq *host)
424
{
425
RSDK_THIS(TMZ2Outro);
426
427
if (host->timer == 120) {
428
Music_FadeOut(0.0125);
429
430
foreach_active(Player, player) { player->active = ACTIVE_NEVER; }
431
432
CutsceneHBH_KingTMZ2Setup();
433
434
if (self->heavyKing) {
435
self->heavyKing->visible = true;
436
self->heavyKing->collisionPlane = 1;
437
RSDK.PlaySfx(TMZ2Outro->sfxDrop, false, 255);
438
}
439
}
440
441
if (host->timer == 166)
442
RSDK.PlaySfx(TMZ2Outro->sfxImpact, false, 255);
443
444
if (host->timer == 240) {
445
if (self->heavyKing) {
446
RSDK.SetSpriteAnimation(self->heavyKing->aniFrames, 3, &self->heavyKing->mainAnimator, false, 0);
447
448
foreach_active(PhantomRuby, ruby)
449
{
450
ruby->startPos.y -= 0x100000;
451
ruby->state = PhantomRuby_State_MoveToPos;
452
}
453
}
454
}
455
456
if (host->timer == 256) {
457
foreach_active(PhantomRuby, ruby)
458
{
459
EntityFXSpinRay *spinRay = CREATE_ENTITY(FXSpinRay, NULL, ruby->position.x, ruby->position.y);
460
spinRay->parent = (Entity *)ruby;
461
spinRay->r = 240;
462
spinRay->g = 0;
463
spinRay->b = 240;
464
465
RSDK.PlaySfx(TMZ2Outro->sfxRubyGet, false, 255);
466
}
467
}
468
469
if (host->timer == 408) {
470
if (self->heavyKing) {
471
RSDK.SetSpriteAnimation(self->heavyKing->aniFrames, 4, &self->heavyKing->mainAnimator, false, 0);
472
473
foreach_active(PhantomRuby, ruby)
474
{
475
ruby->startPos.y += 0x180000;
476
ruby->state = PhantomRuby_State_MoveToPos;
477
}
478
}
479
}
480
481
if (host->timer == 420) {
482
EntityFXFade *fxFade = CREATE_ENTITY(FXFade, INT_TO_VOID(0xF0F0F0), self->position.x, self->position.y);
483
fxFade->speedIn = 32;
484
fxFade->wait = 90;
485
fxFade->speedOut = 16;
486
fxFade->fadeOutBlack = true;
487
fxFade->isPermanent = true;
488
489
PhantomRuby_PlaySfx(RUBYSFX_ATTACK1);
490
return true;
491
}
492
493
return false;
494
}
495
bool32 TMZ2Outro_Cutscene_OuttaHere(EntityCutsceneSeq *host)
496
{
497
if (host->timer >= 120) {
498
if (host->timer == 240) {
499
foreach_active(Player, player)
500
{
501
player->up = false;
502
player->onGround = false;
503
player->velocity.x = 0x20000;
504
player->velocity.y = -0x40000;
505
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HURT, &player->animator, false, 0);
506
}
507
508
Zone->cameraBoundsR[0] = 0x2000;
509
Zone->playerBoundActiveR[0] = false;
510
}
511
else if (host->timer == 290) {
512
foreach_active(Player, player)
513
{
514
player->left = false;
515
player->right = true;
516
player->groundVel = 0x40000;
517
player->topSpeed = 0x50000;
518
player->drawGroup = Zone->playerDrawGroup[1];
519
}
520
}
521
}
522
else {
523
foreach_active(Player, player)
524
{
525
if (player->position.x >= (ScreenInfo->center.x - 64 + ScreenInfo->position.x) << 16) {
526
player->left = true;
527
player->right = false;
528
529
if (player->groundVel < -0x20000)
530
player->groundVel = -0x20000;
531
}
532
else {
533
player->up = true;
534
player->left = false;
535
player->right = false;
536
player->groundVel = 0;
537
}
538
}
539
}
540
541
if (host->timer == 90) {
542
foreach_active(Eggman, eggman)
543
{
544
RSDK.SetSpriteAnimation(Eggman->aniFrames, 9, &eggman->animator, true, 0);
545
546
eggman->direction = FLIP_NONE;
547
eggman->state = Eggman_State_WalkOffScreen;
548
eggman->velocity.x = 0x10000;
549
550
RSDK.ObjectTileGrip(eggman, Zone->collisionLayers, CMODE_FLOOR, eggman->collisionPlane, 0, 0x1C0000, 14);
551
}
552
}
553
554
if (host->timer == 300) {
555
foreach_active(RubyPortal, portal)
556
{
557
portal->velocity.x = 0x20000;
558
portal->isPermanent = true;
559
portal->active = ACTIVE_NORMAL;
560
}
561
562
RSDK_GET_ENTITY(SLOT_CAMERA1, Camera)->state = StateMachine_None;
563
564
return true;
565
}
566
567
return false;
568
}
569
bool32 TMZ2Outro_Cutscene_TeamEscape(EntityCutsceneSeq *host)
570
{
571
RSDK_THIS(TMZ2Outro);
572
573
if (!(Zone->timer & 7))
574
Camera_ShakeScreen(0, 0, 4);
575
576
if (!(Zone->timer & 0x1F))
577
RSDK.PlaySfx(TMZ2Outro->sfxRumble, false, 255);
578
579
foreach_active(RubyPortal, portal)
580
{
581
if (portal->velocity.x < 0x71000)
582
portal->velocity.x += 0x2000;
583
}
584
585
EntityCamera *camera = RSDK_GET_ENTITY(SLOT_CAMERA1, Camera);
586
if (host->timer >= 400)
587
camera->position.x += 0x50000;
588
else
589
camera->position.x += 0x70000;
590
591
if (host->timer == 120)
592
RSDK.PlaySfx(TMZ2Outro->sfxCarRev, false, 255);
593
594
if (host->timer == 320) {
595
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
596
Player_ChangeCharacter(player1, ID_SONIC);
597
598
EntityPlayer *player2 = RSDK_GET_ENTITY(SLOT_PLAYER2, Player);
599
RSDK.CopyEntity(player2, player1, false);
600
player2->playerID = 1;
601
Player_ChangeCharacter(player2, ID_TAILS);
602
603
EntityPlayer *player3 = RSDK_GET_ENTITY(SLOT_PLAYER4, Player);
604
RSDK.CopyEntity(player3, player1, false);
605
player3->playerID = 3;
606
Player_ChangeCharacter(player3, ID_KNUCKLES);
607
608
EntityPlayer *player4 = RSDK_GET_ENTITY(SLOT_PLAYER5, Player);
609
RSDK.CopyEntity(player4, player1, false);
610
player4->playerID = 4;
611
Player_ChangeCharacter(player4, ID_MIGHTY);
612
613
EntityPlayer *player5 = RSDK_GET_ENTITY(SLOT_PLAYER6, Player);
614
RSDK.CopyEntity(player5, player1, false);
615
player5->playerID = 5;
616
Player_ChangeCharacter(player5, ID_RAY);
617
618
SceneInfo->timeEnabled = true;
619
620
Player_TryTransform(player1, 0xFF);
621
EntitySuperSparkle *sparkle = RSDK_GET_ENTITY(Player->playerCount, SuperSparkle);
622
RSDK.ResetEntity(sparkle, SuperSparkle->classID, player1);
623
624
Player->playerCount = 6;
625
int32 offsetX = 0;
626
for (int32 i = 0; i < Player->playerCount; ++i) {
627
if (i != 2) {
628
EntityPlayer *player = RSDK_GET_ENTITY(i, Player);
629
player->groundVel = 0x100000;
630
player->topSpeed = 0x100000;
631
player->rings = 100;
632
if (i)
633
player->sidekick = true;
634
player->position.x += offsetX;
635
offsetX -= 0x200000;
636
player->stateInput = StateMachine_None;
637
}
638
}
639
640
Zone->deathBoundary[0] = 0x8000000;
641
RSDK.PlaySfx(Player->sfxTransform2, false, 255);
642
Music_FadeOut(0.0125);
643
}
644
645
if (host->timer == 420)
646
RSDK.PlaySfx(TMZ2Outro->sfxDrop, false, 255);
647
648
if (host->timer == 512) {
649
650
EntityFXFade *fxFade = CREATE_ENTITY(FXFade, INT_TO_VOID(0xF0F0F0), self->position.x, self->position.y);
651
fxFade->speedIn = 32;
652
fxFade->wait = 90;
653
fxFade->speedOut = 16;
654
fxFade->fadeOutBlack = 1;
655
fxFade->isPermanent = true;
656
657
RSDK.SetChannelAttributes(RSDK.PlaySfx(PhantomRuby->sfxL[0], false, 0), 1.0, -1.0, 1.0);
658
RSDK.SetChannelAttributes(RSDK.PlaySfx(PhantomRuby->sfxR[0], false, 0), 1.0, 1.0, 1.0);
659
return true;
660
}
661
662
return false;
663
}
664
#endif
665
666
bool32 TMZ2Outro_Cutscene_FadeOut(EntityCutsceneSeq *host)
667
{
668
RSDK.StopSfx(TMZ2Outro->sfxAlarm);
669
670
return host->timer == 180;
671
}
672
bool32 TMZ2Outro_Cutscene_FinishSequence(EntityCutsceneSeq *host)
673
{
674
bool32 hasGoodEnding = false;
675
676
#if MANIA_USE_PLUS
677
if (!(SceneInfo->filter & FILTER_ENCORE))
678
#endif
679
hasGoodEnding = (CHECK_CHARACTER_ID(ID_SONIC, 1) || (CHECK_CHARACTER_ID(ID_KNUCKLES, 1) && CHECK_CHARACTER_ID(ID_KNUCKLES, 2)))
680
&& SaveGame_AllChaosEmeralds();
681
682
bool32 isSaveSlot = false;
683
if (!hasGoodEnding)
684
isSaveSlot = globals->saveSlotID != NO_SAVE_SLOT;
685
686
if (isSaveSlot) {
687
if (!host->timer) {
688
globals->playerID = TMZ2Outro->playerID;
689
TMZ2Outro->finishedSaving = false;
690
691
SaveGame_SaveProgress();
692
if (Zone_IsZoneLastAct())
693
GameProgress_MarkZoneCompleted(Zone_GetZoneID());
694
695
GameProgress_GiveEnding(1);
696
SaveGame_SaveFile(TMZ2Outro_SaveFileCB);
697
698
UIWaitSpinner_StartWait();
699
}
700
701
if (!TMZ2Outro->finishedSaving)
702
return false;
703
else
704
UIWaitSpinner_FinishWait();
705
}
706
707
if (hasGoodEnding) {
708
++SceneInfo->listPos;
709
RSDK.LoadScene();
710
return true;
711
}
712
else {
713
globals->playerID = TMZ2Outro->playerID;
714
#if MANIA_USE_PLUS
715
if (globals->gameMode == MODE_ENCORE) {
716
RSDK.SetScene("Presentation", "Credits");
717
}
718
else {
719
#endif
720
switch (GET_CHARACTER_ID(1)) {
721
default:
722
case ID_SONIC: RSDK.SetScene("Videos", "Bad End - Sonic"); break;
723
724
case ID_TAILS: RSDK.SetScene("Videos", "Bad End - Tails"); break;
725
726
case ID_KNUCKLES:
727
if (CHECK_CHARACTER_ID(ID_KNUCKLES, 2))
728
RSDK.SetScene("Videos", "True End?");
729
else
730
RSDK.SetScene("Videos", "Bad End - Knux");
731
break;
732
733
#if MANIA_USE_PLUS
734
case ID_MIGHTY: RSDK.SetScene("Videos", "Bad End - Mighty"); break;
735
736
case ID_RAY: RSDK.SetScene("Videos", "Bad End - Ray"); break;
737
#endif
738
}
739
#if MANIA_USE_PLUS
740
}
741
#endif
742
743
API_UnlockAchievement(&achievementList[ACH_GAME_CLEARED]);
744
RSDK.LoadScene();
745
746
return true;
747
}
748
749
return false;
750
}
751
752
#if MANIA_USE_PLUS
753
void TMZ2Outro_SaveFileCB(bool32 success) { TMZ2Outro->finishedSaving = true; }
754
#else
755
void TMZ2Outro_SaveFileCB(void) { TMZ2Outro->finishedSaving = true; }
756
#endif
757
758
#if GAME_INCLUDE_EDITOR
759
void TMZ2Outro_EditorDraw(void) {}
760
761
void TMZ2Outro_EditorLoad(void) {}
762
#endif
763
764
void TMZ2Outro_Serialize(void) {}
765
766