Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/ERZ/ERZMystic.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: ERZMystic Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectERZMystic *ERZMystic;
11
12
void ERZMystic_Update(void)
13
{
14
RSDK_THIS(ERZMystic);
15
16
if (self->invincibilityTimer > 0)
17
self->invincibilityTimer--;
18
19
StateMachine_Run(self->state);
20
21
RSDK.ProcessAnimation(&self->mysticAnimator);
22
}
23
24
void ERZMystic_LateUpdate(void) {}
25
26
void ERZMystic_StaticUpdate(void) {}
27
28
void ERZMystic_Draw(void)
29
{
30
RSDK_THIS(ERZMystic);
31
32
if (self->stateDraw) {
33
StateMachine_Run(self->stateDraw);
34
}
35
else {
36
RSDK.DrawSprite(&self->mysticAnimator, NULL, false);
37
}
38
}
39
40
void ERZMystic_Create(void *data)
41
{
42
RSDK_THIS(ERZMystic);
43
44
self->drawFX = FX_FLIP;
45
46
if (!SceneInfo->inEditor) {
47
self->visible = true;
48
self->drawGroup = Zone->objectDrawGroup[0];
49
self->active = ACTIVE_NORMAL;
50
self->updateRange.x = 0x800000;
51
self->updateRange.y = 0x800000;
52
53
self->unused1[0] = 0;
54
self->unused1[1] = 1;
55
self->unused1[2] = 2;
56
57
self->cupAlpha[0] = 0xC0;
58
self->cupAlpha[1] = 0x00;
59
self->cupAlpha[2] = 0xC0;
60
61
self->hitbox.left = -12;
62
self->hitbox.top = -12;
63
self->hitbox.right = 12;
64
self->hitbox.bottom = 12;
65
66
self->correctCup = 1;
67
self->state = ERZMystic_State_Init;
68
self->stateDraw = ERZMystic_Draw_CupSetup;
69
70
RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 2, &self->mysticAnimator, true, 0);
71
RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 0, &self->cupAnimator, true, 0);
72
RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 0, &self->cupSilhouetteAnimator, true, 1);
73
RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 1, &self->cupSpikeAnimator, true, 0);
74
}
75
}
76
77
void ERZMystic_StageLoad(void) { ERZMystic->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomMystic.bin", SCOPE_STAGE); }
78
79
void ERZMystic_CheckPlayerCollisions(void)
80
{
81
RSDK_THIS(ERZMystic);
82
83
int32 storeX = self->position.x;
84
int32 storeY = self->position.y;
85
86
self->position.x = self->mysticPos.x;
87
self->position.y = self->mysticPos.y;
88
89
foreach_active(Player, player)
90
{
91
if (!self->invincibilityTimer && Player_CheckBadnikTouch(player, self, &self->hitbox) && Player_CheckBossHit(player, self)) {
92
ERZMystic_Hit();
93
}
94
95
if (self->cupBlastAnimator.frameID > 8 && self->cupBlastAnimator.frameID < 26) {
96
for (int32 i = 0; i < 3; ++i) {
97
if (i != self->correctCup) {
98
self->position.x = storeX + self->cupPos[i];
99
if (abs(self->position.x - player->position.x) < 0x400000 && player->position.y > self->position.y)
100
Player_Hurt(player, self);
101
}
102
}
103
}
104
105
self->position.x = self->mysticPos.x;
106
}
107
108
self->position.x = storeX;
109
self->position.y = storeY;
110
}
111
112
void ERZMystic_Hit(void)
113
{
114
RSDK_THIS(ERZMystic);
115
116
self->invincibilityTimer = 48;
117
RSDK.PlaySfx(ERZKing->sfxHit, false, 255);
118
}
119
120
void ERZMystic_SetupNewCupSwap(void)
121
{
122
RSDK_THIS(ERZMystic);
123
124
self->swapCup1 = RSDK.Rand(0, 3);
125
126
switch (self->swapCup1) {
127
case 0: self->swapCup2 = (RSDK.Rand(0, 256) > 128) + 1; break;
128
case 1: self->swapCup2 = RSDK.Rand(0, 256) <= 128 ? 2 : 0; break;
129
case 2: self->swapCup2 = RSDK.Rand(0, 256) <= 128; break;
130
}
131
132
self->swapCup1Pos = self->cupPos[self->swapCup1];
133
self->swapCup1Alpha = self->cupAlpha[self->swapCup1];
134
135
self->swapCup2Pos = self->cupPos[self->swapCup2];
136
self->swapCup2Alpha = self->cupAlpha[self->swapCup2];
137
}
138
139
void ERZMystic_Draw_CupSetup(void)
140
{
141
RSDK_THIS(ERZMystic);
142
143
RSDK.DrawSprite(&self->mysticAnimator, &self->mysticPos, false);
144
145
for (int32 i = 0; i < 3; ++i) {
146
Vector2 drawPos;
147
drawPos.x = self->position.x + self->cupPos[i];
148
if (i == 1) {
149
drawPos.y = self->middleCupY;
150
self->drawFX = FX_ROTATE | FX_FLIP;
151
}
152
else {
153
drawPos.y = self->position.y;
154
}
155
156
self->direction = FLIP_X;
157
RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);
158
159
self->direction = FLIP_NONE;
160
RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);
161
162
self->inkEffect = INK_ALPHA;
163
self->drawFX = FX_FLIP;
164
self->alpha = self->cupAlpha[i];
165
self->direction = FLIP_X;
166
RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);
167
168
self->direction = FLIP_NONE;
169
RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);
170
171
self->inkEffect = INK_NONE;
172
}
173
}
174
175
void ERZMystic_Draw_CupSwap(void)
176
{
177
RSDK_THIS(ERZMystic);
178
179
Vector2 drawPos = self->position;
180
if (self->invincibilityTimer & 1) {
181
RSDK.CopyPalette(2, 128, 0, 128, 128);
182
183
RSDK.DrawSprite(&self->mysticAnimator, &self->mysticPos, false);
184
185
RSDK.CopyPalette(1, 128, 0, 128, 128);
186
}
187
else {
188
RSDK.DrawSprite(&self->mysticAnimator, &self->mysticPos, false);
189
}
190
191
for (int32 i = 0; i < 3; ++i) {
192
drawPos.x = self->position.x + self->cupPos[i];
193
self->direction = FLIP_X;
194
RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);
195
196
self->direction = FLIP_NONE;
197
RSDK.DrawSprite(&self->cupAnimator, &drawPos, false);
198
199
self->inkEffect = INK_ALPHA;
200
self->alpha = self->cupAlpha[i];
201
self->direction = FLIP_X;
202
RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);
203
204
self->direction = FLIP_NONE;
205
RSDK.DrawSprite(&self->cupSilhouetteAnimator, &drawPos, false);
206
207
self->inkEffect = INK_NONE;
208
if (i != self->correctCup)
209
RSDK.DrawSprite(&self->cupBlastAnimator, &drawPos, false);
210
}
211
}
212
213
void ERZMystic_State_Init(void)
214
{
215
RSDK_THIS(ERZMystic);
216
217
self->mysticPos.x = self->position.x;
218
self->velocity.y = 0x40000;
219
self->mysticVelY = -0x80000;
220
self->mysticPos.y = self->position.y;
221
self->middleCupY = self->position.y;
222
223
self->state = ERZMystic_State_SetupInitialCupPos;
224
}
225
226
void ERZMystic_State_SetupInitialCupPos(void)
227
{
228
RSDK_THIS(ERZMystic);
229
230
self->mysticVelY += 0x3800;
231
self->mysticPos.y += self->mysticVelY;
232
233
self->velocity.y -= 0x2800;
234
self->middleCupY += self->velocity.y;
235
236
if (self->middleCupY <= self->position.y) {
237
self->velocity.y = 0;
238
self->middleCupY = self->position.y;
239
}
240
241
self->cupPos[0] += (-0x800000 - self->cupPos[0]) >> 4;
242
self->cupPos[2] += ((0x800000 - self->cupPos[2]) >> 4);
243
244
if (self->rotation < 256) {
245
self->rotation += 16;
246
}
247
248
if (++self->timer == 60) {
249
self->cupPos[0] = -0x800000;
250
self->cupPos[2] = 0x800000;
251
self->timer = 0;
252
self->state = ERZMystic_State_MoveCupsDownwards;
253
}
254
}
255
256
void ERZMystic_State_MoveCupsDownwards(void)
257
{
258
RSDK_THIS(ERZMystic);
259
260
self->mysticVelY += 0x3800;
261
self->mysticPos.y += self->mysticVelY;
262
263
self->velocity.y += 0x3800;
264
self->position.y += self->velocity.y;
265
266
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x380000, true))
267
self->velocity.y = 0;
268
269
if (self->mysticPos.y >= self->position.y - 0x180000) {
270
self->mysticPos.y = 0;
271
self->mysticVelY = 0;
272
self->onGround = false;
273
self->state = ERZMystic_State_RotateMiddleCup;
274
}
275
}
276
277
void ERZMystic_State_RotateMiddleCup(void)
278
{
279
RSDK_THIS(ERZMystic);
280
281
// This does continue to move the side cups downwards too if they're not on the ground yet
282
self->velocity.y += 0x4000;
283
self->position.y += self->velocity.y;
284
285
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x380000, true)) {
286
if (!self->onGround)
287
Camera_ShakeScreen(0, 0, 4);
288
289
self->velocity.y = 0;
290
self->onGround = true;
291
}
292
293
if (self->rotation >= 512) {
294
self->rotation = 0;
295
self->state = ERZMystic_State_MoveMiddleCupToFloor;
296
}
297
else {
298
self->rotation += 16;
299
}
300
}
301
302
void ERZMystic_State_MoveMiddleCupToFloor(void)
303
{
304
RSDK_THIS(ERZMystic);
305
306
self->velocity.y += 0x4000;
307
self->middleCupY += self->velocity.y;
308
309
if (self->middleCupY >= self->position.y) {
310
Camera_ShakeScreen(0, 0, 4);
311
self->velocity.y = 0;
312
self->middleCupY = self->position.y;
313
self->stateDraw = ERZMystic_Draw_CupSwap;
314
self->state = ERZMystic_State_PrepareCupSwap;
315
}
316
}
317
318
void ERZMystic_State_PrepareCupSwap(void)
319
{
320
RSDK_THIS(ERZMystic);
321
322
++self->timer;
323
if (self->cupAlpha[0] < 0x90) {
324
self->cupAlpha[0] += 4;
325
self->cupAlpha[2] += 4;
326
}
327
328
if (self->timer == 30) {
329
self->timer = 0;
330
self->cupSwapCount = 6;
331
ERZMystic_SetupNewCupSwap();
332
self->state = ERZMystic_State_CupSwapping;
333
}
334
}
335
336
void ERZMystic_State_CupSwapping(void)
337
{
338
RSDK_THIS(ERZMystic);
339
340
if (abs(self->swapCup2Pos - self->swapCup1Pos) <= 0x800000)
341
self->timer += 16;
342
else
343
self->timer += 8;
344
345
int32 cup1 = self->swapCup1;
346
int32 cup2 = self->swapCup2;
347
348
// Use Lerp Math to move each cup to the other's initial position
349
int32 cup1Pos = self->swapCup1Pos;
350
if (self->timer > 0) {
351
if (self->timer < 256)
352
cup1Pos += ((self->swapCup2Pos - cup1Pos) >> 8) * ((RSDK.Sin512(self->timer + 0x180) >> 2) + 0x80);
353
else
354
cup1Pos = self->swapCup2Pos;
355
}
356
self->cupPos[cup1] = cup1Pos;
357
358
int32 cup2Pos = self->swapCup2Pos;
359
if (self->timer > 0) {
360
if (self->timer < 256)
361
cup2Pos += ((self->swapCup1Pos - cup2Pos) >> 8) * ((RSDK.Sin512(self->timer + 0x180) >> 2) + 0x80);
362
else
363
cup2Pos = self->swapCup1Pos;
364
}
365
self->cupPos[cup2] = cup2Pos;
366
367
self->cupAlpha[cup1] = abs(self->cupPos[cup1]) / 0xE38E;
368
self->cupAlpha[cup2] = abs(self->cupPos[cup2]) / 0xE38E;
369
370
if (self->timer == 0x100) {
371
self->timer = 0;
372
373
if (self->cupSwapCount <= 1) {
374
self->middleCupY -= 0x600000;
375
self->mysticPos.x = self->position.x + self->cupPos[self->correctCup];
376
self->mysticPos.y = self->position.y;
377
self->originPos.x = self->mysticPos.x;
378
self->originPos.y = self->mysticPos.y;
379
self->velocity.y = -0x10000;
380
self->state = ERZMystic_State_RevealMystic;
381
}
382
else {
383
self->cupSwapCount--;
384
RSDK.PlaySfx(PhantomMystic->sfxCupSwap, false, 255);
385
ERZMystic_SetupNewCupSwap();
386
}
387
}
388
}
389
390
void ERZMystic_State_RevealMystic(void)
391
{
392
RSDK_THIS(ERZMystic);
393
394
self->velocity.y -= 0x3800;
395
self->position.y += self->velocity.y;
396
397
self->cupAlpha[0] -= self->cupAlpha[0] >> 4;
398
self->cupAlpha[1] -= self->cupAlpha[1] >> 4;
399
self->cupAlpha[2] -= self->cupAlpha[2] >> 4;
400
401
if (self->position.y <= self->middleCupY) {
402
RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 3, &self->cupBlastAnimator, true, 0);
403
self->velocity.y = 0;
404
self->position.y = self->middleCupY;
405
self->state = ERZMystic_State_CupBlast;
406
}
407
408
self->mysticPos.y = BadnikHelpers_Oscillate(self->originPos.y, 4, 11);
409
410
if (self->position.y - self->middleCupY < 0x200000)
411
ERZMystic_CheckPlayerCollisions();
412
}
413
414
void ERZMystic_State_CupBlast(void)
415
{
416
RSDK_THIS(ERZMystic);
417
418
RSDK.ProcessAnimation(&self->cupBlastAnimator);
419
420
self->cupAlpha[0] -= self->cupAlpha[0] >> 4;
421
self->cupAlpha[1] -= self->cupAlpha[1] >> 4;
422
self->cupAlpha[2] -= self->cupAlpha[2] >> 4;
423
424
if (self->cupBlastAnimator.frameID == self->cupBlastAnimator.frameCount - 1) {
425
self->mysticVelY = 0;
426
self->state = ERZMystic_State_MoveCupsToMystic;
427
}
428
429
self->mysticPos.y = BadnikHelpers_Oscillate(self->originPos.y, 4, 11);
430
431
ERZMystic_CheckPlayerCollisions();
432
}
433
434
void ERZMystic_State_MoveCupsToMystic(void)
435
{
436
RSDK_THIS(ERZMystic);
437
438
self->cupPos[0] += (self->cupPos[self->correctCup] - self->cupPos[0]) >> 3;
439
self->cupPos[1] += (self->cupPos[self->correctCup] - self->cupPos[1]) >> 3;
440
self->cupPos[2] += (self->cupPos[self->correctCup] - self->cupPos[2]) >> 3;
441
442
self->mysticVelY -= 0x3000;
443
self->mysticPos.y += self->mysticVelY;
444
445
if (self->mysticPos.y < self->position.y)
446
self->mysticPos.y = self->position.y;
447
448
ERZMystic_CheckPlayerCollisions();
449
if (++self->timer == 60) {
450
foreach_all(ERZKing, king)
451
{
452
king->active = ACTIVE_NORMAL;
453
king->position.x = self->mysticPos.x;
454
}
455
destroyEntity(self);
456
}
457
}
458
459
#if GAME_INCLUDE_EDITOR
460
void ERZMystic_EditorDraw(void)
461
{
462
RSDK_THIS(ERZMystic);
463
464
self->mysticPos = self->position;
465
self->middleCupY = self->position.y;
466
467
self->cupAlpha[0] = 0x60;
468
self->cupAlpha[1] = 0;
469
self->cupAlpha[2] = 0x60;
470
471
RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 2, &self->mysticAnimator, true, 0);
472
RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 0, &self->cupAnimator, true, 0);
473
RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 0, &self->cupSilhouetteAnimator, true, 1);
474
RSDK.SetSpriteAnimation(ERZMystic->aniFrames, 1, &self->cupSpikeAnimator, true, 0);
475
476
ERZMystic_Draw_CupSetup();
477
}
478
479
void ERZMystic_EditorLoad(void) { ERZMystic->aniFrames = RSDK.LoadSpriteAnimation("Phantom/PhantomMystic.bin", SCOPE_STAGE); }
480
#endif
481
482
void ERZMystic_Serialize(void) {}
483
484