Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/MSZ/RollerMKII.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: RollerMKII Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectRollerMKII *RollerMKII;
11
12
void RollerMKII_Update(void)
13
{
14
RSDK_THIS(RollerMKII);
15
16
StateMachine_Run(self->state);
17
}
18
19
void RollerMKII_LateUpdate(void) {}
20
21
void RollerMKII_StaticUpdate(void) {}
22
23
void RollerMKII_Draw(void)
24
{
25
RSDK_THIS(RollerMKII);
26
27
RSDK.DrawSprite(&self->animator, NULL, false);
28
}
29
30
void RollerMKII_Create(void *data)
31
{
32
RSDK_THIS(RollerMKII);
33
34
self->visible = true;
35
self->drawGroup = Zone->objectDrawGroup[0];
36
self->startPos = self->position;
37
self->startDir = self->direction;
38
self->drawFX = FX_FLIP;
39
self->active = ACTIVE_BOUNDS;
40
self->updateRange.x = 0x1000000;
41
self->updateRange.y = 0x1000000;
42
self->onGround = false;
43
self->tileCollisions = TILECOLLISION_DOWN;
44
self->collisionLayers = Zone->collisionLayers;
45
self->collisionPlane = 0;
46
RSDK.SetSpriteAnimation(RollerMKII->aniFrames, 0, &self->animator, true, 5);
47
self->state = RollerMKII_State_Init;
48
}
49
50
void RollerMKII_StageLoad(void)
51
{
52
if (RSDK.CheckSceneFolder("MSZ"))
53
RollerMKII->aniFrames = RSDK.LoadSpriteAnimation("MSZ/RollerMKII.bin", SCOPE_STAGE);
54
55
RollerMKII->hitboxOuter_Rolling.left = -9;
56
RollerMKII->hitboxOuter_Rolling.top = -14;
57
RollerMKII->hitboxOuter_Rolling.right = 9;
58
RollerMKII->hitboxOuter_Rolling.bottom = 14;
59
60
RollerMKII->hitboxInner_Rolling.left = -8;
61
RollerMKII->hitboxInner_Rolling.top = -14;
62
RollerMKII->hitboxInner_Rolling.right = 8;
63
RollerMKII->hitboxInner_Rolling.bottom = 14;
64
65
RollerMKII->hitboxOuter_Idle.left = -9;
66
RollerMKII->hitboxOuter_Idle.top = -14;
67
RollerMKII->hitboxOuter_Idle.right = 9;
68
RollerMKII->hitboxOuter_Idle.bottom = 24;
69
70
RollerMKII->hitboxInner_Idle.left = -8;
71
RollerMKII->hitboxInner_Idle.top = -14;
72
RollerMKII->hitboxInner_Idle.right = 8;
73
RollerMKII->hitboxInner_Idle.bottom = 24;
74
75
// Hitbox for interacting with player
76
RollerMKII->hitboxBadnik.left = -14;
77
RollerMKII->hitboxBadnik.top = -14;
78
RollerMKII->hitboxBadnik.right = 14;
79
RollerMKII->hitboxBadnik.bottom = 14;
80
81
// Hitbox for interacting with other objects
82
// It's.... the same... as above???
83
RollerMKII->hitboxObject.left = -14;
84
RollerMKII->hitboxObject.top = -14;
85
RollerMKII->hitboxObject.right = 14;
86
RollerMKII->hitboxObject.bottom = 14;
87
88
RollerMKII->sfxBumper = RSDK.GetSfx("Stage/Bumper3.wav");
89
RollerMKII->sfxJump = RSDK.GetSfx("Stage/Jump2.wav");
90
RollerMKII->sfxDropDash = RSDK.GetSfx("Global/DropDash.wav");
91
RollerMKII->sfxRelease = RSDK.GetSfx("Global/Release.wav");
92
RollerMKII->sfxSkidding = RSDK.GetSfx("Global/Skidding.wav");
93
94
DEBUGMODE_ADD_OBJ(RollerMKII);
95
}
96
97
void RollerMKII_DebugSpawn(void)
98
{
99
RSDK_THIS(DebugMode);
100
101
EntityRollerMKII *rollerMKII = CREATE_ENTITY(RollerMKII, NULL, self->position.x, self->position.y);
102
rollerMKII->direction = self->direction;
103
rollerMKII->startDir = self->direction;
104
}
105
106
void RollerMKII_DebugDraw(void)
107
{
108
RSDK.SetSpriteAnimation(RollerMKII->aniFrames, 0, &DebugMode->animator, true, 1);
109
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
110
}
111
112
void RollerMKII_CheckOffScreen(void)
113
{
114
RSDK_THIS(RollerMKII);
115
116
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
117
self->position = self->startPos;
118
self->direction = self->startDir;
119
RollerMKII_Create(NULL);
120
}
121
}
122
123
void RollerMKII_CheckPlayerCollisions(void)
124
{
125
RSDK_THIS(RollerMKII);
126
127
foreach_active(Player, player)
128
{
129
if (Player_CheckBadnikTouch(player, self, &RollerMKII->hitboxBadnik))
130
Player_CheckBadnikBreak(player, self, true);
131
}
132
}
133
134
void RollerMKII_CheckPlayerCollisions_Rolling(void)
135
{
136
RSDK_THIS(RollerMKII);
137
138
foreach_active(Player, player)
139
{
140
if (Player_CheckBadnikTouch(player, self, &RollerMKII->hitboxBadnik)) {
141
142
int32 anim = player->animator.animationID;
143
bool32 shouldBump = false;
144
145
#if MANIA_USE_PLUS
146
if (player->state == Player_State_MightyHammerDrop) {
147
Player_CheckBadnikBreak(player, self, true);
148
}
149
else {
150
shouldBump = player->characterID == ID_MIGHTY && (anim == ANI_CROUCH || player->jumpAbilityState > 1);
151
#endif
152
if (Player_CheckAttacking(player, self) || shouldBump) {
153
RSDK.PlaySfx(RollerMKII->sfxBumper, false, 255);
154
int32 angle = RSDK.ATan2(player->position.x - self->position.x, player->position.y - self->position.y);
155
int32 velX = 0x380 * RSDK.Cos256(angle);
156
int32 velY = 0x380 * RSDK.Sin256(angle);
157
158
if (anim != ANI_FLY && anim != ANI_FLY_LIFT_TIRED) {
159
if (player->state != Player_State_TailsFlight) {
160
if (player->state != Player_State_DropDash)
161
player->state = Player_State_Air;
162
if (anim != ANI_JUMP && anim != ANI_DASH)
163
player->animator.animationID = ANI_WALK;
164
}
165
}
166
167
#if MANIA_USE_PLUS
168
if (player->characterID != ID_MIGHTY || player->jumpAbilityState <= 1) {
169
#endif
170
player->velocity.x = velX;
171
player->groundVel = velX;
172
player->applyJumpCap = false;
173
if (player->characterID == ID_KNUCKLES && player->animator.animationID == ANI_GLIDE) {
174
RSDK.SetSpriteAnimation(player->aniFrames, ANI_GLIDE_DROP, &player->animator, false, 0);
175
player->state = Player_State_KnuxGlideDrop;
176
}
177
player->velocity.y = velY;
178
player->onGround = false;
179
player->tileCollisions = TILECOLLISION_DOWN;
180
#if MANIA_USE_PLUS
181
}
182
#endif
183
RSDK.PlaySfx(RollerMKII->sfxBumper, false, 255);
184
RSDK.SetSpriteAnimation(RollerMKII->aniFrames, 2, &self->animator, true, 0);
185
self->velocity.y = -0x40000;
186
self->velocity.x = -velX;
187
self->onGround = false;
188
self->touchedGround = 0;
189
self->timer = 45;
190
self->state = RollerMKII_State_Bumped;
191
self->direction = player->position.x < self->position.x;
192
}
193
else {
194
Player_Hurt(player, self);
195
}
196
#if MANIA_USE_PLUS
197
}
198
#endif
199
}
200
}
201
}
202
203
int32 RollerMKII_HandleObjectCollisions(Entity *otherEntity, Hitbox *hitbox)
204
{
205
RSDK_THIS(RollerMKII);
206
207
int32 velX = self->velocity.x;
208
int32 side = RSDK.CheckObjectCollisionBox(otherEntity, hitbox, self, &RollerMKII->hitboxObject, true);
209
210
if ((side == C_LEFT && velX > 0) || (side == C_RIGHT && velX < 0)) {
211
if (self->state != RollerMKII_State_Bumped) {
212
RSDK.PlaySfx(RollerMKII->sfxBumper, false, 255);
213
RSDK.SetSpriteAnimation(RollerMKII->aniFrames, 0, &self->animator, true, 0);
214
self->velocity.y = -0x40000;
215
self->onGround = false;
216
self->touchedGround = 0;
217
self->timer = 30;
218
self->velocity.x = velX < 0 ? 0x20000 : -0x20000;
219
self->state = RollerMKII_State_Bumped;
220
self->direction = self->position.x < Player_GetNearestPlayer()->position.x;
221
}
222
}
223
return side;
224
}
225
226
bool32 RollerMKII_HandlePlatformCollisions(EntityPlatform *platform)
227
{
228
RSDK_THIS(RollerMKII);
229
bool32 collided = false;
230
231
if (platform->state != Platform_State_Falling2 && platform->state != Platform_State_Hold) {
232
platform->position.x = platform->drawPos.x - platform->collisionOffset.x;
233
platform->position.y = platform->drawPos.y - platform->collisionOffset.y;
234
if (platform->collision) {
235
if (platform->collision != PLATFORM_C_SOLID) {
236
if (platform->collision == PLATFORM_C_TILED
237
&& RSDK.CheckObjectCollisionTouchBox(platform, &platform->hitbox, self, &RollerMKII->hitboxObject)) {
238
if (self->collisionLayers & Zone->moveLayerMask) {
239
TileLayer *move = RSDK.GetTileLayer(Zone->moveLayer);
240
move->position.x = -(platform->drawPos.x + platform->tileOrigin.x) >> 16;
241
move->position.y = -(platform->drawPos.y + platform->tileOrigin.y) >> 16;
242
}
243
244
if (self->velocity.y >= 0x3800)
245
collided = true;
246
}
247
}
248
else {
249
Hitbox *hitbox = RSDK.GetHitbox(&platform->animator, 1);
250
collided = RollerMKII_HandleObjectCollisions((Entity *)platform, hitbox);
251
}
252
}
253
else {
254
Hitbox *hitbox = RSDK.GetHitbox(&platform->animator, 0);
255
RSDK.CheckObjectCollisionPlatform(platform, hitbox, self, &RollerMKII->hitboxObject, true);
256
}
257
258
platform->position = platform->centerPos;
259
}
260
261
return collided;
262
}
263
264
void RollerMKII_HandleCollisions(void)
265
{
266
RSDK_THIS(RollerMKII);
267
268
foreach_all(PlaneSwitch, planeSwitch)
269
{
270
PlaneSwitch_CheckCollisions(planeSwitch, self, planeSwitch->flags, planeSwitch->size, true, Zone->playerDrawGroup[0],
271
Zone->playerDrawGroup[1]);
272
}
273
274
foreach_all(Platform, platform) { RollerMKII_HandlePlatformCollisions(platform); }
275
foreach_all(Spikes, spikes) { RollerMKII_HandleObjectCollisions((Entity *)spikes, &spikes->hitbox); }
276
foreach_all(BreakableWall, wall) { RollerMKII_HandleObjectCollisions((Entity *)wall, &wall->hitbox); }
277
278
if (!self->collisionMode && self->state != RollerMKII_State_Bumped) {
279
bool32 collided = self->direction == FLIP_X
280
? RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, self->collisionPlane, -0xA0000, 0, false)
281
: RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, self->collisionPlane, 0xA0000, 0, false);
282
if (collided) {
283
RSDK.PlaySfx(RollerMKII->sfxBumper, false, 255);
284
RSDK.SetSpriteAnimation(RollerMKII->aniFrames, 0, &self->animator, true, 0);
285
self->onGround = false;
286
self->velocity.x = self->direction == FLIP_X ? 0x20000 : -0x20000;
287
self->velocity.y = -0x40000;
288
self->touchedGround = 0;
289
self->timer = 30;
290
self->state = RollerMKII_State_Bumped;
291
self->direction = self->position.x < Player_GetNearestPlayer()->position.x;
292
}
293
}
294
}
295
296
void RollerMKII_State_Init(void)
297
{
298
RSDK_THIS(RollerMKII);
299
300
self->active = ACTIVE_NORMAL;
301
self->velocity.x = 0;
302
self->velocity.y = 0;
303
self->groundVel = 0;
304
self->touchedGround = 0;
305
306
self->state = RollerMKII_State_Idle;
307
RollerMKII_State_Idle();
308
}
309
310
void RollerMKII_State_Idle(void)
311
{
312
RSDK_THIS(RollerMKII);
313
314
RSDK.ProcessAnimation(&self->animator);
315
316
Vector2 range = { 0x200000, 0x200000 };
317
318
if (self->timer) {
319
self->timer--;
320
}
321
else if (RSDK.CheckOnScreen(self, &range)) {
322
bool32 wallCollided = false;
323
if (self->direction == FLIP_X)
324
wallCollided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, self->collisionPlane, -0x180000, 0, false);
325
else
326
wallCollided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, self->collisionPlane, 0x180000, 0, false);
327
328
if (wallCollided)
329
self->direction ^= FLIP_X;
330
331
foreach_active(Player, player)
332
{
333
if (self->direction) {
334
if (player->position.x < self->position.x) {
335
if (self->position.x - player->position.x < 0x800000) {
336
self->velocity.y = -0x40000;
337
RSDK.SetSpriteAnimation(RollerMKII->aniFrames, 1, &self->animator, true, 0);
338
339
self->playerPtr = player;
340
RSDK.PlaySfx(RollerMKII->sfxJump, false, 0xFF);
341
342
self->state = RollerMKII_State_SpinUp;
343
}
344
}
345
}
346
else {
347
if (player->position.x > self->position.x) {
348
if (player->position.x - self->position.x < 0x800000) {
349
self->velocity.y = -0x40000;
350
RSDK.SetSpriteAnimation(RollerMKII->aniFrames, 1, &self->animator, true, 0);
351
352
self->playerPtr = player;
353
RSDK.PlaySfx(RollerMKII->sfxJump, false, 0xFF);
354
355
self->state = RollerMKII_State_SpinUp;
356
}
357
}
358
}
359
}
360
}
361
362
RollerMKII_CheckPlayerCollisions();
363
RollerMKII_CheckOffScreen();
364
}
365
366
void RollerMKII_State_SpinUp(void)
367
{
368
RSDK_THIS(RollerMKII);
369
370
self->position.x += self->velocity.x;
371
self->position.y += self->velocity.y;
372
self->velocity.y += 0x3800;
373
374
RSDK.ProcessAnimation(&self->animator);
375
376
if (self->velocity.y > 0) {
377
self->timer = 15;
378
RSDK.PlaySfx(RollerMKII->sfxDropDash, false, 255);
379
self->state = RollerMKII_State_RollDelay;
380
}
381
382
if (self->animator.frameID <= 4)
383
RollerMKII_CheckPlayerCollisions();
384
else
385
RollerMKII_CheckPlayerCollisions_Rolling();
386
387
RollerMKII_CheckOffScreen();
388
}
389
390
void RollerMKII_State_RollDelay(void)
391
{
392
RSDK_THIS(RollerMKII);
393
394
RSDK.ProcessAnimation(&self->animator);
395
396
if (!--self->timer)
397
self->state = RollerMKII_State_Rolling_Air;
398
399
RollerMKII_CheckPlayerCollisions_Rolling();
400
RollerMKII_CheckOffScreen();
401
}
402
403
void RollerMKII_State_Rolling_Air(void)
404
{
405
RSDK_THIS(RollerMKII);
406
407
if (!self->touchedGround) {
408
if (self->position.x <= self->playerPtr->position.x) {
409
self->direction = FLIP_NONE;
410
411
if (self->velocity.x < 0x80000)
412
self->velocity.x += 0x3800;
413
}
414
else {
415
self->direction = FLIP_X;
416
417
if (self->velocity.x > -0x80000)
418
self->velocity.x -= 0x3800;
419
}
420
}
421
422
RSDK.ProcessObjectMovement(self, &RollerMKII->hitboxOuter_Rolling, &RollerMKII->hitboxInner_Rolling);
423
424
self->velocity.y += 0x3800;
425
426
RollerMKII_HandleCollisions();
427
428
if (self->onGround) {
429
if (abs(self->angle) & 0x60) {
430
self->state = RollerMKII_State_Rolling_Ground;
431
}
432
else {
433
if (self->velocity.x)
434
self->groundVel = self->velocity.x;
435
436
if (!self->touchedGround) {
437
self->touchedGround = true;
438
439
if (self->direction == FLIP_NONE) {
440
self->groundVel = 0x80000;
441
self->velocity.x = 0x80000;
442
}
443
else {
444
self->groundVel = -0x80000;
445
self->velocity.x = -0x80000;
446
}
447
self->velocity.y = -0x20000;
448
449
self->onGround = false;
450
RSDK.StopSfx(RollerMKII->sfxDropDash);
451
RSDK.PlaySfx(RollerMKII->sfxRelease, false, 255);
452
Hitbox *hitbox = RSDK.GetHitbox(&self->animator, 0);
453
454
EntityDust *dust = CREATE_ENTITY(Dust, self, self->position.x, self->position.y + 0xE0000);
455
RSDK.SetSpriteAnimation(Dust->aniFrames, 2, &dust->animator, true, 0);
456
dust->state = Dust_State_DustPuff;
457
dust->position.y += hitbox->bottom << 16;
458
dust->direction = self->direction;
459
dust->drawGroup = self->drawGroup;
460
dust->position.x += self->direction ? 0x90000 : -0x90000;
461
}
462
else if (self->velocity.y <= 0x10000) {
463
self->state = RollerMKII_State_Rolling_Ground;
464
}
465
else {
466
self->velocity.y = -0x20000;
467
self->onGround = false;
468
}
469
}
470
471
self->direction = self->groundVel < 0;
472
}
473
474
RSDK.ProcessAnimation(&self->animator);
475
476
RollerMKII_CheckPlayerCollisions_Rolling();
477
RollerMKII_CheckOffScreen();
478
}
479
480
void RollerMKII_State_Rolling_Ground(void)
481
{
482
RSDK_THIS(RollerMKII);
483
484
if (!self->collisionMode) {
485
if (self->position.x <= self->playerPtr->position.x) {
486
self->direction = FLIP_NONE;
487
488
if (self->groundVel < 0x80000) {
489
self->groundVel += 0x3800;
490
491
if (self->groundVel > 0) {
492
self->groundVel += 0x1400;
493
494
if (self->groundVel >= -0x40000) {
495
self->timer = 0;
496
}
497
else {
498
RSDK.PlaySfx(RollerMKII->sfxSkidding, false, 255);
499
self->timer = (self->timer + 1) & 3;
500
if (!self->timer)
501
CREATE_ENTITY(Dust, NULL, self->position.x, self->position.y + 0xE0000)->state = Dust_State_DustPuff;
502
}
503
}
504
}
505
}
506
else {
507
self->direction = FLIP_X;
508
509
if (self->groundVel > -0x80000) {
510
self->groundVel -= 0x3800;
511
512
if (self->groundVel > 0) {
513
self->groundVel += 0x1400;
514
515
if (self->groundVel <= 0x40000) {
516
self->timer = 0;
517
}
518
else {
519
RSDK.PlaySfx(RollerMKII->sfxSkidding, false, 255);
520
self->timer = (self->timer + 1) & 3;
521
if (!self->timer)
522
CREATE_ENTITY(Dust, NULL, self->position.x, self->position.y + 0xE0000)->state = Dust_State_DustPuff;
523
}
524
}
525
}
526
}
527
}
528
529
RSDK.ProcessObjectMovement(self, &RollerMKII->hitboxOuter_Rolling, &RollerMKII->hitboxInner_Rolling);
530
531
self->groundVel += (RSDK.Sin256(self->angle) << 13 >> 8);
532
if (self->collisionMode != CMODE_FLOOR) {
533
if (self->angle >= 0x40 && self->angle <= 0xC0 && self->groundVel <= 0x20000) {
534
self->onGround = false;
535
self->angle = 0;
536
self->collisionMode = 0;
537
}
538
}
539
540
RollerMKII_HandleCollisions();
541
542
if (!self->onGround && self->state != RollerMKII_State_Bumped)
543
self->state = RollerMKII_State_Rolling_Air;
544
545
RSDK.ProcessAnimation(&self->animator);
546
547
RollerMKII_CheckPlayerCollisions_Rolling();
548
RollerMKII_CheckOffScreen();
549
}
550
551
void RollerMKII_State_Bumped(void)
552
{
553
RSDK_THIS(RollerMKII);
554
555
RSDK.ProcessObjectMovement(self, &RollerMKII->hitboxOuter_Idle, &RollerMKII->hitboxInner_Idle);
556
557
self->velocity.y += 0x3800;
558
RollerMKII_HandleCollisions();
559
560
if (self->onGround) {
561
self->groundVel = 0;
562
self->velocity.x = 0;
563
self->velocity.y = 0;
564
self->state = RollerMKII_State_Idle;
565
RSDK.SetSpriteAnimation(RollerMKII->aniFrames, 0, &self->animator, true, 0);
566
}
567
568
RSDK.ProcessAnimation(&self->animator);
569
RollerMKII_CheckOffScreen();
570
}
571
572
#if GAME_INCLUDE_EDITOR
573
void RollerMKII_EditorDraw(void) { RollerMKII_Draw(); }
574
575
void RollerMKII_EditorLoad(void)
576
{
577
RollerMKII->aniFrames = RSDK.LoadSpriteAnimation("MSZ/RollerMKII.bin", SCOPE_STAGE);
578
579
RSDK_ACTIVE_VAR(RollerMKII, direction);
580
RSDK_ENUM_VAR("Right", FLIP_NONE);
581
RSDK_ENUM_VAR("Left", FLIP_X);
582
}
583
#endif
584
585
void RollerMKII_Serialize(void) { RSDK_EDITABLE_VAR(RollerMKII, VAR_UINT8, direction); }
586
587