Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/GHZ2Outro.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: GHZ2Outro Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectGHZ2Outro *GHZ2Outro;
11
12
void GHZ2Outro_Update(void)
13
{
14
RSDK_THIS(GHZ2Outro);
15
16
if (!self->activated) {
17
CutsceneSeq_StartSequence(self, GHZ2Outro_Cutscene_HoleSceneFadeIn, GHZ2Outro_Cutscene_SpyOnEggman, GHZ2Outro_Cutscene_BreakupGroup,
18
GHZ2Outro_Cutscene_RubyHover, GHZ2Outro_Cutscene_StartRubyWarp, GHZ2Outro_Cutscene_HandleRubyWarp,
19
GHZ2Outro_Cutscene_LoadCPZ1, StateMachine_None);
20
21
#if MANIA_USE_PLUS
22
CutsceneSeq_SetSkipTypeCallback(GHZ2Outro_Cutscene_SkipCB);
23
#endif
24
25
self->active = ACTIVE_NEVER;
26
}
27
else {
28
CutsceneSeq_StartSequence(self, GHZ2Outro_Cutscene_FinishActClear, GHZ2Outro_Cutscene_JumpIntoHole, StateMachine_None);
29
30
#if MANIA_USE_PLUS
31
CutsceneSeq_SetSkipType(SKIPTYPE_RELOADSCN);
32
#endif
33
34
HUD_MoveOut();
35
self->active = ACTIVE_NEVER;
36
}
37
}
38
39
void GHZ2Outro_LateUpdate(void) {}
40
41
void GHZ2Outro_StaticUpdate(void) {}
42
43
void GHZ2Outro_Draw(void) {}
44
45
void GHZ2Outro_Create(void *data)
46
{
47
RSDK_THIS(GHZ2Outro);
48
49
if (!SceneInfo->inEditor) {
50
self->activated = data != NULL;
51
52
foreach_all(DERobot, robot) { self->DERobot = robot; }
53
foreach_all(Eggman, eggman) { self->eggman = eggman; }
54
55
self->active = ACTIVE_NORMAL;
56
self->visible = false;
57
}
58
}
59
60
void GHZ2Outro_StageLoad(void)
61
{
62
GHZ2Outro->sfxRocketJet = RSDK.GetSfx("Stage/RocketJet.wav");
63
GHZ2Outro->sfxShinobiJump = RSDK.GetSfx("PSZ/ShinobiJump.wav");
64
GHZ2Outro->sfxHeliWoosh = RSDK.GetSfx("SPZ1/HeliWooshIn.wav");
65
}
66
67
bool32 GHZ2Outro_Cutscene_FinishActClear(EntityCutsceneSeq *host)
68
{
69
RSDK_THIS(GHZ2Outro);
70
71
EntityDERobot *robot = self->DERobot;
72
robot->state = StateMachine_None;
73
robot->active = ACTIVE_NEVER;
74
75
CutsceneSeq_LockAllPlayerControl();
76
77
foreach_active(Player, player)
78
{
79
player->state = Player_State_Ground;
80
if (!player->sidekick) {
81
player->stateInput = StateMachine_None;
82
player->left = true;
83
player->right = false;
84
player->up = false;
85
player->down = false;
86
player->jumpPress = false;
87
}
88
}
89
90
Zone->deathBoundary[0] += 0x4000 << 16;
91
Zone->deathBoundary[1] += 0x4000 << 16;
92
Music_PlayTrack(TRACK_STAGE);
93
94
foreach_active(EggPrison, prison) { prison->state = EggPrison_State_FlyOffScreen; }
95
96
return true;
97
}
98
bool32 GHZ2Outro_Cutscene_JumpIntoHole(EntityCutsceneSeq *host)
99
{
100
RSDK_THIS(GHZ2Outro);
101
102
EntityDERobot *robot = self->DERobot;
103
104
foreach_active(Player, player)
105
{
106
player->jumpPress = false;
107
108
if (player->onGround) {
109
if (player->angle > 8 && player->angle < 64 && player->groundVel > -0x20000)
110
player->groundVel = -0x20000;
111
112
if (player->position.x - robot->position.x < 0x600000) {
113
player->jumpPress = true;
114
player->jumpHold = true;
115
}
116
}
117
118
if (player->position.x < robot->position.x + 0x200000)
119
player->velocity.x -= player->velocity.x >> 4;
120
121
if (player->position.x < robot->position.x - 0x200000)
122
player->position.x = robot->position.x - 0x200000;
123
}
124
125
if (player->position.y > (ScreenInfo->position.y + 0x200) << 16) {
126
foreach_active(Player, playerPtr) { playerPtr->active = ACTIVE_NEVER; }
127
RSDK.SetScene("Cutscenes", "Green Hill Zone 2");
128
129
Zone_StartFadeOut(0x10, 0x000000);
130
return true;
131
}
132
133
return false;
134
}
135
136
bool32 GHZ2Outro_Cutscene_HoleSceneFadeIn(EntityCutsceneSeq *host)
137
{
138
RSDK_THIS(GHZ2Outro);
139
140
if (host->timer >= 8) {
141
CutsceneSeq_LockAllPlayerControl();
142
143
foreach_active(Player, player)
144
{
145
player->stateInput = StateMachine_None;
146
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
147
}
148
149
foreach_all(CutsceneHBH, cutsceneHBH) { cutsceneHBH->drawGroup = Zone->objectDrawGroup[0]; }
150
151
foreach_all(DERobot, robot)
152
{
153
robot->state = StateMachine_None;
154
robot->active = ACTIVE_NORMAL;
155
robot->visible = true;
156
}
157
158
EntityDERobot *deRobot = self->DERobot;
159
deRobot->state = DERobot_State_CutsceneExplode;
160
161
CutsceneHBH_ShinobiBounceSetup();
162
CutsceneHBH_KingSetup();
163
CutsceneHBH_RiderSetup();
164
165
EntityEggman *eggman = self->eggman;
166
RSDK.SetSpriteAnimation(Eggman->aniFrames, 9, &eggman->animator, true, 0);
167
eggman->direction = FLIP_NONE;
168
eggman->state = Eggman_State_ProcessAnimation;
169
170
foreach_all(PhantomRuby, ruby)
171
{
172
self->phantomRuby = ruby;
173
ruby->state = PhantomRuby_State_MoveRotateGravity;
174
ruby->drawFX = FX_ROTATE;
175
}
176
177
FXRuby_SetupLayerDeformation();
178
return true;
179
}
180
181
return false;
182
}
183
bool32 GHZ2Outro_Cutscene_SpyOnEggman(EntityCutsceneSeq *host)
184
{
185
RSDK_THIS(GHZ2Outro);
186
187
foreach_active(Player, player)
188
{
189
if (player->sidekick) {
190
if (host->timer >= 60) {
191
if (host->timer == 60) {
192
player->state = Player_State_Ground;
193
player->right = true;
194
}
195
}
196
else {
197
player->groundVel = 0;
198
if (player->onGround && player->groundedStore) {
199
player->state = Player_State_Static;
200
if (player->characterID == ID_TAILS)
201
RSDK.SetSpriteAnimation(player->aniFrames, ANI_BALANCE_2, &player->animator, false, 0);
202
else
203
RSDK.SetSpriteAnimation(player->aniFrames, ANI_IDLE, &player->animator, false, 0);
204
}
205
}
206
}
207
else if (player->onGround && player->groundedStore) {
208
player->right = true;
209
}
210
211
if (player->position.x > self->position.x - 0x180000 * player->playerID - 0xE00000) {
212
player->right = FLIP_NONE;
213
player->direction = FLIP_NONE;
214
if (!player->skidding && player->groundVel > 0) {
215
player->skidding = 12;
216
}
217
218
player->groundVel -= player->groundVel >> 4;
219
if (player->groundVel < 0x10000)
220
player->skidding = 0;
221
}
222
}
223
224
if (host->timer == 90)
225
Music_TransitionTrack(TRACK_HBHMISCHIEF, 0.0125);
226
227
if (host->timer == 120)
228
Camera_SetupLerp(CAMERA_LERP_SIN512, 0, self->position.x, self->position.y, 4);
229
230
if (host->timer >= 208) {
231
foreach_active(Player, playerPtr)
232
{
233
playerPtr->down = true;
234
playerPtr->camera = NULL;
235
}
236
return true;
237
}
238
return false;
239
}
240
bool32 GHZ2Outro_Cutscene_BreakupGroup(EntityCutsceneSeq *host)
241
{
242
RSDK_THIS(GHZ2Outro);
243
244
EntityEggman *eggman = self->eggman;
245
246
switch (host->timer) {
247
default: break;
248
249
case 90:
250
RSDK.SetSpriteAnimation(Eggman->aniFrames, 5, &eggman->animator, true, 2);
251
eggman->timer = 30;
252
eggman->velocity.x = 0;
253
eggman->velocity.y = -0x30000;
254
eggman->nextState = Eggman_State_ProcessUntilEnd;
255
eggman->state = Eggman_State_FallUntilTimerReset;
256
eggman->animID = 3;
257
break;
258
259
case 160: {
260
foreach_active(DERobot, robot)
261
{
262
if (robot->aniID == DEROBOT_ARM && robot->frameID == 2) {
263
robot->state = DERobot_Cutscene_ActivateArm;
264
}
265
}
266
267
RSDK.PlaySfx(DERobot->sfxButton2, false, 255);
268
break;
269
}
270
271
case 240:
272
eggman->state = Eggman_State_ProcessThenSet;
273
eggman->animID = 2;
274
Music_SetMusicTrack("RubyPresence.ogg", TRACK_RUBYPRESENCE, 198457);
275
Music_TransitionTrack(TRACK_EGGMAN1, 0.025);
276
break;
277
278
case 272: {
279
EntityCutsceneHBH *mystic = CutsceneHBH_GetEntity(HBH_MYSTIC);
280
if (mystic)
281
mystic->state = CutsceneHBH_State_MysticExit;
282
283
Camera_SetupLerp(CAMERA_LERP_NORMAL, 0, self->position.x, self->position.y - 0x400000, 1);
284
RSDK.PlaySfx(GHZ2Outro->sfxRocketJet, false, 0xFF);
285
break;
286
}
287
288
case 288: {
289
EntityCutsceneHBH *rider = CutsceneHBH_GetEntity(HBH_RIDER);
290
if (rider) {
291
if (rider->direction == FLIP_X) {
292
rider->timer = 0;
293
RSDK.SetSpriteAnimation(rider->aniFrames, 2, &rider->mainAnimator, true, 0);
294
}
295
rider->state = CutsceneHBH_State_RiderExit;
296
}
297
298
RSDK.PlaySfx(GHZ2Outro->sfxHeliWoosh, false, 255);
299
break;
300
}
301
302
case 304: {
303
CutsceneHBH_ShinobiJumpSetup();
304
305
RSDK.PlaySfx(GHZ2Outro->sfxShinobiJump, false, 255);
306
break;
307
}
308
309
case 320: {
310
EntityCutsceneHBH *gunner = CutsceneHBH_GetEntity(HBH_GUNNER);
311
if (gunner) {
312
RSDK.SetSpriteAnimation(gunner->aniFrames, 4, &gunner->mainAnimator, true, 0);
313
gunner->state = CutsceneHBH_State_GunnerExit;
314
}
315
316
EntityCutsceneHBH *king = CutsceneHBH_GetEntity(HBH_KING);
317
if (king) {
318
king->direction ^= FLIP_X;
319
king->state = CutsceneHBH_State_KingExit;
320
}
321
322
RSDK.PlaySfx(GHZ2Outro->sfxRocketJet, false, 0xFF);
323
foreach_active(Player, player) { player->down = false; }
324
EntityPhantomRuby *ruby = self->phantomRuby;
325
ruby->startPos.x = ruby->position.x;
326
ruby->startPos.y = ruby->position.y;
327
ruby->state = PhantomRuby_State_Oscillate;
328
return true;
329
}
330
}
331
332
return false;
333
}
334
bool32 GHZ2Outro_Cutscene_RubyHover(EntityCutsceneSeq *host)
335
{
336
RSDK_THIS(GHZ2Outro);
337
EntityPlayer *player2 = RSDK_GET_ENTITY(SLOT_PLAYER2, Player);
338
EntityPhantomRuby *ruby = self->phantomRuby;
339
340
if (ruby) {
341
if (ruby->state == PhantomRuby_State_Oscillate) {
342
if (player2->classID == Player->classID && player2->characterID == ID_TAILS) {
343
player2->state = Player_State_Static;
344
RSDK.SetSpriteAnimation(player2->aniFrames, ANI_SKID, &player2->animator, false, 0);
345
}
346
return true;
347
}
348
}
349
350
return false;
351
}
352
bool32 GHZ2Outro_Cutscene_StartRubyWarp(EntityCutsceneSeq *host)
353
{
354
RSDK_THIS(GHZ2Outro);
355
356
EntityPhantomRuby *ruby = self->phantomRuby;
357
if (!host->timer)
358
PhantomRuby_SetupFlash(ruby);
359
360
if (ruby->flashFinished) {
361
PhantomRuby_PlaySfx(RUBYSFX_REDCUBE);
362
return true;
363
}
364
365
return false;
366
}
367
bool32 GHZ2Outro_Cutscene_HandleRubyWarp(EntityCutsceneSeq *host)
368
{
369
RSDK_THIS(GHZ2Outro);
370
371
EntityPhantomRuby *ruby = self->phantomRuby;
372
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
373
EntityPlayer *player2 = RSDK_GET_ENTITY(SLOT_PLAYER2, Player);
374
375
EntityFXRuby *fxRuby = NULL;
376
if (host->timer) {
377
fxRuby = self->fxRuby;
378
}
379
else {
380
fxRuby = CREATE_ENTITY(FXRuby, NULL, ruby->position.x, ruby->position.y);
381
fxRuby->drawGroup = Zone->playerDrawGroup[1];
382
self->fxRuby = fxRuby;
383
Camera_ShakeScreen(0, 4, 4);
384
player1->drawGroup = Zone->playerDrawGroup[1] + 1;
385
if (player2->classID == Player->classID)
386
player2->drawGroup = Zone->playerDrawGroup[1] + 1;
387
}
388
389
if (!host->values[0]) {
390
if (fxRuby->fullyExpanded) {
391
if (host->storedTimer) {
392
if (host->timer == host->storedTimer + 48) {
393
fxRuby->delay = 64;
394
fxRuby->state = FXRuby_State_IncreaseStageDeform;
395
PhantomRuby_PlaySfx(RUBYSFX_ATTACK4);
396
Camera_ShakeScreen(0, 4, 4);
397
}
398
else if (host->timer == host->storedTimer + 180) {
399
fxRuby->delay = 32;
400
fxRuby->state = FXRuby_State_IncreaseStageDeform;
401
PhantomRuby_PlaySfx(RUBYSFX_ATTACK1);
402
Camera_ShakeScreen(0, 4, 4);
403
Music_FadeOut(0.025);
404
host->storedTimer = host->timer;
405
host->values[0] = true;
406
}
407
}
408
else {
409
host->storedTimer = host->timer;
410
}
411
412
if (host->timer >= host->storedTimer + 52) {
413
int32 id = 0;
414
for (int32 angle = 0; angle < 0x80; angle += 0x10) {
415
EntityPlayer *player = RSDK_GET_ENTITY(id++, Player);
416
if (!player || player->classID == TYPE_BLANK)
417
break;
418
RSDK.SetSpriteAnimation(player->aniFrames, ANI_FAN, &player->animator, false, 0);
419
420
int32 valX = (ruby->position.x - 0x400000) - player->position.x;
421
int32 valY = (ruby->position.y - (0xA00000 + 944)) - player->position.y;
422
423
player->position.x += ((RSDK.Cos256(2 * (angle + host->timer - host->storedTimer)) << 12) + valX) >> 5;
424
player->position.y += ((RSDK.Sin256(2 * (angle + host->timer - host->storedTimer)) << 12) + valY) >> 5;
425
player->state = Player_State_Static;
426
player->tileCollisions = TILECOLLISION_NONE;
427
player->onGround = false;
428
}
429
}
430
}
431
}
432
else {
433
if (fxRuby->fadeWhite >= 0x200) {
434
if (fxRuby->fadeBlack >= 0x200) {
435
if (host->timer == host->storedTimer + 150)
436
return true;
437
}
438
else {
439
fxRuby->fadeBlack += 0x10;
440
}
441
}
442
else {
443
fxRuby->fadeWhite += 0x10;
444
}
445
}
446
447
return false;
448
}
449
450
bool32 GHZ2Outro_Cutscene_LoadCPZ1(EntityCutsceneSeq *host)
451
{
452
if (host->timer == 16) {
453
globals->enableIntro = true;
454
455
#if MANIA_USE_PLUS
456
if (globals->gameMode == MODE_ENCORE)
457
RSDK.SetScene("Encore Mode", "Chemical Plant Zone+ 1");
458
else
459
#endif
460
RSDK.SetScene("Mania Mode", "Chemical Plant Zone 1");
461
462
RSDK.LoadScene();
463
return true;
464
}
465
return false;
466
}
467
468
#if MANIA_USE_PLUS
469
void GHZ2Outro_Cutscene_SkipCB(void)
470
{
471
#if MANIA_USE_PLUS
472
if (globals->gameMode == MODE_ENCORE)
473
RSDK.SetScene("Encore Mode", "Chemical Plant Zone+ 1");
474
else
475
#endif
476
RSDK.SetScene("Mania Mode", "Chemical Plant Zone 1");
477
}
478
#endif
479
480
#if GAME_INCLUDE_EDITOR
481
void GHZ2Outro_EditorDraw(void)
482
{
483
RSDK_THIS(GHZ2Outro);
484
CutsceneRules_DrawCutsceneBounds(self, &self->size);
485
}
486
487
void GHZ2Outro_EditorLoad(void) {}
488
#endif
489
490
void GHZ2Outro_Serialize(void) { RSDK_EDITABLE_VAR(GHZ2Outro, VAR_VECTOR2, size); }
491
492