Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/MSZ/Bumpalo.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Bumpalo Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectBumpalo *Bumpalo;
11
12
void Bumpalo_Update(void)
13
{
14
RSDK_THIS(Bumpalo);
15
16
RSDK.ProcessAnimation(&self->huffAnimator);
17
18
StateMachine_Run(self->state);
19
}
20
21
void Bumpalo_LateUpdate(void) {}
22
23
void Bumpalo_StaticUpdate(void) {}
24
25
void Bumpalo_Draw(void)
26
{
27
RSDK_THIS(Bumpalo);
28
29
RSDK.DrawSprite(&self->badnikAnimator, NULL, false);
30
RSDK.DrawSprite(&self->huffAnimator, NULL, false);
31
32
if (self->state == Bumpalo_State_Charging)
33
RSDK.DrawSprite(&self->dustAnimator, NULL, false);
34
}
35
36
void Bumpalo_Create(void *data)
37
{
38
RSDK_THIS(Bumpalo);
39
40
self->visible = true;
41
self->drawGroup = Zone->objectDrawGroup[0] + 1;
42
self->drawFX = FX_FLIP;
43
self->startPos = self->position;
44
self->startDir = self->direction;
45
self->active = ACTIVE_BOUNDS;
46
self->updateRange.x = 0x800000;
47
self->updateRange.y = 0x800000;
48
49
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 1, &self->badnikAnimator, true, 0);
50
self->state = Bumpalo_State_Init;
51
}
52
53
void Bumpalo_StageLoad(void)
54
{
55
if (RSDK.CheckSceneFolder("MSZ"))
56
Bumpalo->aniFrames = RSDK.LoadSpriteAnimation("MSZ/Bumpalo.bin", SCOPE_STAGE);
57
58
Bumpalo->hitboxBadnik.left = -20;
59
Bumpalo->hitboxBadnik.top = 0;
60
Bumpalo->hitboxBadnik.right = 20;
61
Bumpalo->hitboxBadnik.bottom = 16;
62
63
Bumpalo->hitboxBumper.left = -10;
64
Bumpalo->hitboxBumper.top = -16;
65
Bumpalo->hitboxBumper.right = 12;
66
Bumpalo->hitboxBumper.bottom = 0;
67
68
Bumpalo->hitboxRange.left = -128;
69
Bumpalo->hitboxRange.top = -64;
70
Bumpalo->hitboxRange.right = -16;
71
Bumpalo->hitboxRange.bottom = 96;
72
73
Bumpalo->hitboxCharge.left = -17;
74
Bumpalo->hitboxCharge.top = -14;
75
Bumpalo->hitboxCharge.right = 10;
76
Bumpalo->hitboxCharge.bottom = 0;
77
78
Bumpalo->hitboxUnused.left = -24;
79
Bumpalo->hitboxUnused.top = -10;
80
Bumpalo->hitboxUnused.right = -8;
81
Bumpalo->hitboxUnused.bottom = 0;
82
83
Bumpalo->sfxBumper = RSDK.GetSfx("Stage/Bumper.wav");
84
Bumpalo->sfxHuff = RSDK.GetSfx("Stage/Huff.wav");
85
Bumpalo->sfxClack = RSDK.GetSfx("Stage/Clack.wav");
86
Bumpalo->sfxImpact = RSDK.GetSfx("Stage/Impact5.wav");
87
88
DEBUGMODE_ADD_OBJ(Bumpalo);
89
}
90
91
void Bumpalo_DebugSpawn(void)
92
{
93
RSDK_THIS(DebugMode);
94
95
EntityBumpalo *bumpalo = CREATE_ENTITY(Bumpalo, NULL, self->position.x, self->position.y);
96
bumpalo->direction = self->direction;
97
bumpalo->startDir = self->direction;
98
}
99
100
void Bumpalo_DebugDraw(void)
101
{
102
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 0, &DebugMode->animator, true, 0);
103
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
104
}
105
106
void Bumpalo_CheckOffScreen(void)
107
{
108
RSDK_THIS(Bumpalo);
109
110
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
111
self->position = self->startPos;
112
self->direction = self->startDir;
113
Bumpalo_Create(NULL);
114
}
115
}
116
117
void Bumpalo_BumpPlayer(EntityPlayer *player)
118
{
119
RSDK_THIS(Bumpalo);
120
121
RSDK.PlaySfx(Bumpalo->sfxBumper, false, 0xFF);
122
123
int32 angle = RSDK.ATan2(player->position.x - self->position.x, player->position.y - self->position.y);
124
int32 velX = 0x700 * RSDK.Cos256(angle);
125
int32 velY = 0x700 * RSDK.Sin256(angle);
126
127
if (player->state == Player_State_FlyCarried)
128
RSDK_GET_ENTITY(SLOT_PLAYER2, Player)->flyCarryTimer = 30;
129
130
int32 anim = player->animator.animationID;
131
if (anim != ANI_FLY && anim != ANI_FLY_LIFT_TIRED) {
132
if (player->state != Player_State_TailsFlight) {
133
if (player->state != Player_State_DropDash)
134
player->state = Player_State_Air;
135
if (anim != ANI_JUMP && anim != ANI_JOG && anim != ANI_RUN && anim != ANI_DASH)
136
player->animator.animationID = ANI_WALK;
137
}
138
}
139
140
if (player->animator.animationID != ANI_FLY) {
141
player->velocity.x = velX;
142
player->groundVel = velX;
143
player->applyJumpCap = false;
144
}
145
146
player->velocity.y = velY;
147
player->onGround = false;
148
player->tileCollisions = TILECOLLISION_DOWN;
149
150
if (self->badnikAnimator.animationID == 3)
151
self->velocity.x >>= 1;
152
153
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 4, &self->badnikAnimator, true, 0);
154
155
if (self->state != Bumpalo_State_Falling && self->state != Bumpalo_State_Bumped)
156
self->velocity.x = 0;
157
158
self->state = Bumpalo_State_Bumped;
159
}
160
161
void Bumpalo_CheckPlayerCollisions(void)
162
{
163
RSDK_THIS(Bumpalo);
164
165
foreach_active(Player, player)
166
{
167
if (self->badnikAnimator.animationID == 3) {
168
if (abs(self->velocity.x) <= 0x10000) {
169
if (Player_CheckBadnikTouch(player, self, &Bumpalo->hitboxBadnik)) {
170
if (Player_CheckBadnikTouch(player, self, &Bumpalo->hitboxBadnik)) {
171
Player_CheckBadnikBreak(player, self, true);
172
}
173
}
174
else if (Player_CheckBadnikTouch(player, self, &Bumpalo->hitboxBumper)) {
175
#if MANIA_USE_PLUS
176
if (player->state == Player_State_MightyHammerDrop) {
177
RSDK.PlaySfx(Bumpalo->sfxBumper, false, 255);
178
Player_CheckBadnikBreak(player, self, true);
179
}
180
else
181
#endif
182
Bumpalo_BumpPlayer(player);
183
}
184
else if (Player_CheckCollisionTouch(player, self, &Bumpalo->hitboxCharge)) {
185
#if MANIA_USE_PLUS
186
if (Player_CheckMightyUnspin(player, 0x300, 2, &player->uncurlTimer)) {
187
RSDK.PlaySfx(Bumpalo->sfxImpact, false, 255);
188
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 4, &self->badnikAnimator, true, 0);
189
self->state = Bumpalo_State_Bumped;
190
self->velocity.x = self->direction == FLIP_NONE ? 0x10000 : -0x10000;
191
self->velocity.y = -0x20000;
192
}
193
else
194
#endif
195
Player_Hurt(player, self);
196
}
197
}
198
else if (Player_CheckBadnikTouch(player, self, &Bumpalo->hitboxBumper)) {
199
#if MANIA_USE_PLUS
200
if (player->state == Player_State_MightyHammerDrop) {
201
RSDK.PlaySfx(Bumpalo->sfxBumper, false, 255);
202
Player_CheckBadnikBreak(player, self, true);
203
}
204
else
205
#endif
206
Bumpalo_BumpPlayer(player);
207
}
208
else if (Player_CheckCollisionTouch(player, self, &Bumpalo->hitboxCharge)) {
209
#if MANIA_USE_PLUS
210
if (Player_CheckMightyUnspin(player, 0x400, 2, &player->uncurlTimer)) {
211
RSDK.PlaySfx(Bumpalo->sfxImpact, false, 255);
212
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 4, &self->badnikAnimator, true, 0);
213
self->state = Bumpalo_State_Bumped;
214
self->velocity.x = self->direction == FLIP_NONE ? 0x10000 : -0x10000;
215
self->velocity.y = -0x20000;
216
}
217
else
218
#endif
219
Player_Hurt(player, self);
220
}
221
else if (Player_CheckBadnikTouch(player, self, &Bumpalo->hitboxBadnik)) {
222
Player_CheckBadnikBreak(player, self, true);
223
}
224
}
225
else {
226
if (Player_CheckBadnikTouch(player, self, &Bumpalo->hitboxBadnik)) {
227
if (Player_CheckBadnikTouch(player, self, &Bumpalo->hitboxBadnik)) {
228
Player_CheckBadnikBreak(player, self, true);
229
}
230
}
231
else {
232
if (Player_CheckBadnikTouch(player, self, &Bumpalo->hitboxBumper)) {
233
#if MANIA_USE_PLUS
234
if (player->state == Player_State_MightyHammerDrop) {
235
RSDK.PlaySfx(Bumpalo->sfxBumper, false, 255);
236
Player_CheckBadnikBreak(player, self, true);
237
}
238
else
239
#endif
240
Bumpalo_BumpPlayer(player);
241
}
242
else {
243
if (Player_CheckCollisionTouch(player, self, &Bumpalo->hitboxCharge)) {
244
#if MANIA_USE_PLUS
245
if (Player_CheckMightyUnspin(player, 0x400, 2, &player->uncurlTimer)) {
246
RSDK.PlaySfx(Bumpalo->sfxImpact, false, 255);
247
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 4, &self->badnikAnimator, true, 0);
248
self->state = Bumpalo_State_Bumped;
249
self->velocity.x = self->direction == FLIP_NONE ? 0x10000 : -0x10000;
250
self->velocity.y = -0x20000;
251
}
252
else
253
#endif
254
Player_Hurt(player, self);
255
}
256
}
257
}
258
}
259
}
260
}
261
262
void Bumpalo_HandlePlatformCollisions(EntityPlatform *platform)
263
{
264
RSDK_THIS(Bumpalo);
265
266
if (platform->state != Platform_State_Falling2 && platform->state != Platform_State_Hold) {
267
platform->position.x = platform->drawPos.x - platform->collisionOffset.x;
268
platform->position.y = platform->drawPos.y - platform->collisionOffset.y;
269
270
bool32 collided = false;
271
if (platform->collision) {
272
if (platform->collision != PLATFORM_C_SOLID) {
273
if (platform->collision == PLATFORM_C_TILED
274
&& RSDK.CheckObjectCollisionTouchBox(platform, &platform->hitbox, self, &Bumpalo->hitboxBadnik)) {
275
if ((self->collisionLayers & Zone->moveLayerMask) != 0) {
276
TileLayer *move = RSDK.GetTileLayer(Zone->moveLayer);
277
move->position.x = -(platform->drawPos.x + platform->tileOrigin.x) >> 16;
278
move->position.y = -(platform->drawPos.y + platform->tileOrigin.y) >> 16;
279
}
280
281
if (self->velocity.y >= 0)
282
self->onGround |= true;
283
}
284
collided = true;
285
}
286
}
287
else {
288
Hitbox *solid = RSDK.GetHitbox(&platform->animator, 0);
289
self->onGround |= RSDK.CheckObjectCollisionPlatform(platform, solid, self, &Bumpalo->hitboxBadnik, true);
290
}
291
292
if (!collided) {
293
Hitbox *platformHitbox = RSDK.GetHitbox(&platform->animator, 1);
294
int32 velX = self->velocity.x;
295
296
switch (RSDK.CheckObjectCollisionBox(platform, platformHitbox, self, &Bumpalo->hitboxBadnik, true)) {
297
default:
298
case C_NONE:
299
case C_BOTTOM: break;
300
301
case C_TOP:
302
if (self->velocity.y > 0)
303
self->onGround |= true;
304
break;
305
306
case C_LEFT:
307
if (velX > 0)
308
self->wallCollided |= true;
309
break;
310
311
case C_RIGHT:
312
if (velX < 0)
313
self->wallCollided |= true;
314
break;
315
}
316
}
317
318
platform->position.x = platform->centerPos.x;
319
platform->position.y = platform->centerPos.y;
320
}
321
}
322
323
void Bumpalo_HandleObjectCollisions(void)
324
{
325
RSDK_THIS(Bumpalo);
326
327
foreach_all(Platform, platform) { Bumpalo_HandlePlatformCollisions(platform); }
328
329
foreach_all(Spikes, spikes)
330
{
331
int32 velX = self->velocity.x;
332
333
switch (RSDK.CheckObjectCollisionBox(platform, &platform->hitbox, self, &Bumpalo->hitboxBadnik, true)) {
334
default:
335
case C_NONE:
336
case C_BOTTOM: break;
337
338
case C_TOP:
339
if (self->velocity.y > 0)
340
self->onGround |= true;
341
break;
342
343
case C_LEFT:
344
if (velX > 0)
345
self->wallCollided |= true;
346
break;
347
348
case C_RIGHT:
349
if (velX < 0)
350
self->wallCollided |= true;
351
break;
352
}
353
}
354
355
foreach_all(BreakableWall, wall)
356
{
357
int32 velX = self->velocity.x;
358
359
switch (RSDK.CheckObjectCollisionBox(wall, &wall->hitbox, self, &Bumpalo->hitboxBadnik, true)) {
360
default:
361
case C_NONE:
362
case C_BOTTOM: break;
363
364
case C_TOP:
365
if (self->velocity.y > 0)
366
self->onGround |= true;
367
break;
368
369
case C_LEFT:
370
if (velX > 0)
371
self->wallCollided |= true;
372
break;
373
374
case C_RIGHT:
375
if (velX < 0)
376
self->wallCollided |= true;
377
break;
378
}
379
}
380
381
if (self->direction)
382
self->wallCollided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x140000, 0, true);
383
else
384
self->wallCollided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x140000, 0, true);
385
}
386
387
void Bumpalo_State_Init(void)
388
{
389
RSDK_THIS(Bumpalo);
390
391
self->active = ACTIVE_NORMAL;
392
self->velocity.x = self->direction == FLIP_NONE ? -0x10000 : 0x10000;
393
394
self->state = Bumpalo_State_Moving;
395
Bumpalo_State_Moving();
396
}
397
398
void Bumpalo_State_Moving(void)
399
{
400
RSDK_THIS(Bumpalo);
401
402
self->position.x += self->velocity.x;
403
self->onGround = false;
404
self->wallCollided = false;
405
Bumpalo_HandleObjectCollisions();
406
407
self->onGround |= RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xF0000, 8);
408
if (!self->onGround) {
409
if (self->ignoreCliffs) {
410
self->state = Bumpalo_State_Falling;
411
}
412
else {
413
if (self->badnikAnimator.animationID == 3)
414
self->velocity.x >>= 1;
415
416
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 0, &self->badnikAnimator, true, 0);
417
self->timer = 0;
418
self->onGround = self->direction ? RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, -0x40000, 0xF0000, 8)
419
: RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0x40000, 0xF0000, 8);
420
if (!self->onGround) {
421
self->state = Bumpalo_State_Falling;
422
}
423
else {
424
self->position.x -= self->velocity.x;
425
self->state = Bumpalo_State_Idle;
426
}
427
}
428
}
429
else if (self->badnikAnimator.animationID == 3) {
430
if (self->wallCollided) {
431
RSDK.PlaySfx(Bumpalo->sfxImpact, false, 0xFF);
432
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 4, &self->badnikAnimator, true, 0);
433
434
self->state = Bumpalo_State_Bumped;
435
self->velocity.x = self->direction == FLIP_NONE ? 0x10000 : -0x10000;
436
self->velocity.y = -0x20000;
437
}
438
}
439
else if (self->wallCollided) {
440
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 0, &self->badnikAnimator, true, 0);
441
self->timer = 0;
442
self->state = Bumpalo_State_Idle;
443
}
444
else {
445
foreach_active(Player, player)
446
{
447
if (Player_CheckCollisionTouch(player, self, &Bumpalo->hitboxRange)) {
448
self->timer = 92;
449
RSDK.PlaySfx(Bumpalo->sfxClack, false, 0xFF);
450
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 2, &self->badnikAnimator, true, 0);
451
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 6, &self->huffAnimator, true, 0);
452
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 7, &self->dustAnimator, true, 0);
453
self->state = Bumpalo_State_Charging;
454
}
455
}
456
}
457
458
RSDK.ProcessAnimation(&self->badnikAnimator);
459
460
Bumpalo_CheckPlayerCollisions();
461
Bumpalo_CheckOffScreen();
462
}
463
464
void Bumpalo_State_Idle(void)
465
{
466
RSDK_THIS(Bumpalo);
467
468
RSDK.ProcessAnimation(&self->badnikAnimator);
469
470
if (++self->timer == 48) {
471
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 5, &self->badnikAnimator, true, 0);
472
self->state = Bumpalo_State_Turning;
473
}
474
475
Bumpalo_CheckPlayerCollisions();
476
Bumpalo_CheckOffScreen();
477
}
478
479
void Bumpalo_State_Charging(void)
480
{
481
RSDK_THIS(Bumpalo);
482
483
RSDK.ProcessAnimation(&self->badnikAnimator);
484
RSDK.ProcessAnimation(&self->dustAnimator);
485
486
if (--self->timer == 83) {
487
RSDK.PlaySfx(Bumpalo->sfxHuff, false, 0xFF);
488
}
489
else if (self->timer <= 0) {
490
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 3, &self->badnikAnimator, true, 0);
491
self->state = Bumpalo_State_Moving;
492
self->velocity.x *= 2;
493
}
494
495
Bumpalo_CheckPlayerCollisions();
496
Bumpalo_CheckOffScreen();
497
}
498
499
void Bumpalo_State_Turning(void)
500
{
501
RSDK_THIS(Bumpalo);
502
503
RSDK.ProcessAnimation(&self->badnikAnimator);
504
505
if (self->badnikAnimator.frameID == self->badnikAnimator.frameCount - 1) {
506
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 1, &self->badnikAnimator, true, 0);
507
508
self->state = Bumpalo_State_Moving;
509
self->direction ^= FLIP_X;
510
self->velocity.x = self->direction == FLIP_NONE ? -0x10000 : 0x10000;
511
Bumpalo_State_Moving();
512
}
513
else {
514
Bumpalo_CheckPlayerCollisions();
515
Bumpalo_CheckOffScreen();
516
}
517
}
518
519
void Bumpalo_State_Bumped(void)
520
{
521
RSDK_THIS(Bumpalo);
522
523
RSDK.ProcessAnimation(&self->badnikAnimator);
524
525
self->position.x += self->velocity.x;
526
self->position.y += self->velocity.y;
527
self->velocity.y += 0x3800;
528
529
self->onGround = false;
530
self->wallCollided = false;
531
Bumpalo_HandleObjectCollisions();
532
self->onGround |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xF0000, true);
533
534
if (self->velocity.y >= 0 && self->onGround) {
535
self->velocity.x = 0;
536
self->velocity.y = 0;
537
}
538
539
if (self->badnikAnimator.frameID == self->badnikAnimator.frameCount - 1) {
540
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 1, &self->badnikAnimator, true, 0);
541
if (self->onGround) {
542
self->velocity.x = self->direction == FLIP_NONE ? -0x10000 : 0x10000;
543
544
if (RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xF0000, 8)) {
545
self->state = Bumpalo_State_Moving;
546
Bumpalo_State_Moving();
547
}
548
else {
549
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 5, &self->badnikAnimator, true, 0);
550
self->state = Bumpalo_State_Turning;
551
Bumpalo_State_Turning();
552
}
553
}
554
else {
555
self->state = Bumpalo_State_Falling;
556
Bumpalo_State_Falling();
557
}
558
}
559
else {
560
Bumpalo_CheckPlayerCollisions();
561
Bumpalo_CheckOffScreen();
562
}
563
}
564
565
void Bumpalo_State_Falling(void)
566
{
567
RSDK_THIS(Bumpalo);
568
569
RSDK.ProcessAnimation(&self->badnikAnimator);
570
571
self->position.x += self->velocity.x;
572
self->position.y += self->velocity.y;
573
self->velocity.y += 0x3800;
574
575
self->onGround = false;
576
self->wallCollided = false;
577
Bumpalo_HandleObjectCollisions();
578
579
self->onGround |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xF0000, true);
580
if (self->onGround) {
581
self->velocity.y = 0;
582
RSDK.PlaySfx(Player->sfxLand, false, 255);
583
RSDK.SetSpriteAnimation(Bumpalo->aniFrames, 4, &self->badnikAnimator, true, 0);
584
self->state = Bumpalo_State_Bumped;
585
}
586
else {
587
Bumpalo_CheckPlayerCollisions();
588
Bumpalo_CheckOffScreen();
589
}
590
}
591
592
#if GAME_INCLUDE_EDITOR
593
void Bumpalo_EditorDraw(void)
594
{
595
RSDK_THIS(Bumpalo);
596
597
RSDK.DrawSprite(&self->badnikAnimator, NULL, false);
598
}
599
600
void Bumpalo_EditorLoad(void)
601
{
602
Bumpalo->aniFrames = RSDK.LoadSpriteAnimation("MSZ/Bumpalo.bin", SCOPE_STAGE);
603
604
RSDK_ACTIVE_VAR(Bumpalo, direction);
605
RSDK_ENUM_VAR("Left", FLIP_NONE);
606
RSDK_ENUM_VAR("Right", FLIP_X);
607
}
608
#endif
609
610
void Bumpalo_Serialize(void)
611
{
612
RSDK_EDITABLE_VAR(Bumpalo, VAR_UINT8, direction);
613
RSDK_EDITABLE_VAR(Bumpalo, VAR_BOOL, ignoreCliffs);
614
}
615
616