Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/CheckerBall.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: CheckerBall Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectCheckerBall *CheckerBall;
11
12
void CheckerBall_Update(void)
13
{
14
RSDK_THIS(CheckerBall);
15
self->active = ACTIVE_NORMAL;
16
CheckerBall_HandlePlayerMovement();
17
self->ballAngle += self->angleVel;
18
CheckerBall_HandlePhysics();
19
RSDK.ProcessObjectMovement(self, &CheckerBall->outerBox, &CheckerBall->innerBox);
20
CheckerBall_HandleObjectCollisions();
21
CheckerBall_HandlePlayerInteractions();
22
self->roundedPos.x = self->position.x & 0xFFFF0000;
23
self->roundedPos.y = self->position.y & 0xFFFF0000;
24
}
25
26
void CheckerBall_LateUpdate(void) {}
27
28
void CheckerBall_StaticUpdate(void) {}
29
30
void CheckerBall_Draw(void)
31
{
32
RSDK_THIS(CheckerBall);
33
self->animator.frameID = (((self->ballAngle >> 14) + 8) >> 4) & 7;
34
RSDK.DrawSprite(&self->animator, NULL, false);
35
}
36
37
void CheckerBall_Create(void *data)
38
{
39
RSDK_THIS(CheckerBall);
40
self->visible = true;
41
self->drawGroup = Zone->objectDrawGroup[0];
42
self->active = ACTIVE_BOUNDS;
43
self->updateRange.x = 0x400000;
44
self->updateRange.y = 0x400000;
45
self->onGround = false;
46
self->tileCollisions = TILECOLLISION_DOWN;
47
self->collisionLayers = Zone->collisionLayers;
48
self->roundedPos.x = self->position.x;
49
self->roundedPos.y = self->position.y;
50
self->collisionPlane = 0;
51
RSDK.SetSpriteAnimation(CheckerBall->aniFrames, 0, &self->animator, true, 0);
52
}
53
54
void CheckerBall_StageLoad(void)
55
{
56
if (RSDK.CheckSceneFolder("GHZ"))
57
CheckerBall->aniFrames = RSDK.LoadSpriteAnimation("GHZ/CheckerBall.bin", SCOPE_STAGE);
58
else if (RSDK.CheckSceneFolder("Blueprint"))
59
CheckerBall->aniFrames = RSDK.LoadSpriteAnimation("Blueprint/CheckerBall.bin", SCOPE_STAGE);
60
61
CheckerBall->outerBox.left = -9;
62
CheckerBall->outerBox.top = -22;
63
CheckerBall->outerBox.right = 9;
64
CheckerBall->outerBox.bottom = 22;
65
66
CheckerBall->innerBox.left = -8;
67
CheckerBall->innerBox.top = -22;
68
CheckerBall->innerBox.right = 8;
69
CheckerBall->innerBox.bottom = 22;
70
71
CheckerBall->hitboxBall.left = -22;
72
CheckerBall->hitboxBall.top = -22;
73
CheckerBall->hitboxBall.right = 22;
74
CheckerBall->hitboxBall.bottom = 22;
75
76
DEBUGMODE_ADD_OBJ(CheckerBall);
77
78
CheckerBall->heightArray[0] = 0;
79
CheckerBall->heightArray[1] = 0;
80
CheckerBall->heightArray[2] = 0;
81
CheckerBall->heightArray[3] = 0;
82
CheckerBall->heightArray[4] = 1;
83
CheckerBall->heightArray[5] = 1;
84
CheckerBall->heightArray[6] = 1;
85
CheckerBall->heightArray[7] = 1;
86
CheckerBall->heightArray[8] = 2;
87
CheckerBall->heightArray[9] = 2;
88
CheckerBall->heightArray[10] = 3;
89
CheckerBall->heightArray[11] = 3;
90
CheckerBall->heightArray[12] = 4;
91
CheckerBall->heightArray[13] = 4;
92
CheckerBall->heightArray[14] = 5;
93
CheckerBall->heightArray[15] = 6;
94
CheckerBall->heightArray[16] = 7;
95
CheckerBall->heightArray[17] = 8;
96
CheckerBall->heightArray[18] = 9;
97
CheckerBall->heightArray[19] = 10;
98
CheckerBall->heightArray[20] = 12;
99
CheckerBall->heightArray[21] = 14;
100
CheckerBall->heightArray[22] = 16;
101
CheckerBall->heightArray[23] = 20;
102
103
// an unused array, here since the ye olde days of v4
104
CheckerBall->unusedArray[0] = 253;
105
CheckerBall->unusedArray[1] = 251;
106
CheckerBall->unusedArray[2] = 248;
107
CheckerBall->unusedArray[3] = 245;
108
CheckerBall->unusedArray[4] = 243;
109
CheckerBall->unusedArray[5] = 240;
110
CheckerBall->unusedArray[6] = 237;
111
CheckerBall->unusedArray[7] = 235;
112
CheckerBall->unusedArray[8] = 232;
113
CheckerBall->unusedArray[9] = 229;
114
CheckerBall->unusedArray[10] = 226;
115
CheckerBall->unusedArray[11] = 224;
116
CheckerBall->unusedArray[12] = 221;
117
CheckerBall->unusedArray[13] = 219;
118
CheckerBall->unusedArray[14] = 216;
119
CheckerBall->unusedArray[15] = 213;
120
CheckerBall->unusedArray[16] = 210;
121
CheckerBall->unusedArray[17] = 208;
122
CheckerBall->unusedArray[18] = 205;
123
CheckerBall->unusedArray[19] = 203;
124
CheckerBall->unusedArray[20] = 200;
125
CheckerBall->unusedArray[21] = 197;
126
CheckerBall->unusedArray[22] = 195;
127
CheckerBall->unusedArray[23] = 192;
128
}
129
130
void CheckerBall_DebugSpawn(void)
131
{
132
RSDK_THIS(DebugMode);
133
134
CREATE_ENTITY(CheckerBall, NULL, self->position.x, self->position.y);
135
}
136
137
void CheckerBall_DebugDraw(void)
138
{
139
RSDK.SetSpriteAnimation(CheckerBall->aniFrames, 0, &DebugMode->animator, true, 0);
140
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
141
}
142
143
void CheckerBall_HandlePhysics(void)
144
{
145
RSDK_THIS(CheckerBall);
146
if (self->onGround) {
147
int32 spd = RSDK.Sin256(self->angle) << 13 >> 8;
148
self->groundVel += spd;
149
self->angleVel = self->groundVel;
150
if (!spd && !self->playerControlled) {
151
if (self->groundVel <= 0) {
152
self->groundVel += 0x400;
153
if (self->groundVel > 0)
154
self->groundVel = 0;
155
}
156
else {
157
self->groundVel -= 0x400;
158
if (self->groundVel < 0)
159
self->groundVel = 0;
160
}
161
}
162
self->velocity.x = self->groundVel * RSDK.Cos256(self->angle) >> 8;
163
self->velocity.y = self->groundVel * RSDK.Sin256(self->angle) >> 8;
164
}
165
else {
166
self->velocity.y += 0x3800;
167
self->groundVel = self->velocity.x;
168
}
169
self->playerControlled = false;
170
}
171
172
void CheckerBall_HandlePlayerMovement(void)
173
{
174
RSDK_THIS(CheckerBall);
175
176
Hitbox hitbox;
177
hitbox.top = -22;
178
hitbox.bottom = 22;
179
180
int32 playerID = 0;
181
self->activePlayers = 0;
182
foreach_active(Player, player)
183
{
184
Hitbox *playerHitbox = Player_GetHitbox(player);
185
int32 acc = player->acceleration >> 1;
186
if (player->onGround) {
187
if (player->position.x <= self->position.x) {
188
hitbox.left = -23;
189
hitbox.right = 0;
190
if (Player_CheckCollisionTouch(player, self, &hitbox)) {
191
if (!player->right) {
192
if (self->velocity.x > 0 && player->groundVel > self->groundVel) {
193
player->velocity.x -= 0x10000;
194
player->groundVel -= 0x10000;
195
}
196
}
197
else {
198
self->activePlayers |= 1 << playerID;
199
if (self->groundVel < player->topSpeed)
200
self->groundVel += acc;
201
self->playerControlled = true;
202
player->position.x = self->roundedPos.x + ((playerHitbox->left - 22) << 16);
203
player->groundVel = 0;
204
}
205
}
206
}
207
else {
208
hitbox.left = 0;
209
hitbox.right = 23;
210
if (Player_CheckCollisionTouch(player, self, &hitbox)) {
211
if (!player->left) {
212
if (self->velocity.x < 0 && player->groundVel < self->groundVel) {
213
player->velocity.x += 0x10000;
214
player->groundVel += 0x10000;
215
}
216
}
217
else {
218
self->activePlayers |= 1 << playerID;
219
if (self->groundVel > -player->topSpeed)
220
self->groundVel -= acc;
221
self->playerControlled = true;
222
player->position.x = self->roundedPos.x + ((playerHitbox->right + 22) << 16);
223
player->groundVel = 0;
224
}
225
}
226
}
227
}
228
++playerID;
229
}
230
}
231
232
void CheckerBall_HandlePlayerInteractions(void)
233
{
234
RSDK_THIS(CheckerBall);
235
int32 x = ((self->position.x - self->collisionOffset.x) & 0xFFFF0000) - self->roundedPos.x;
236
int32 y = ((self->position.y - self->collisionOffset.y) & 0xFFFF0000) - self->roundedPos.y;
237
int32 startX = self->position.x;
238
int32 startY = self->position.y;
239
self->position.x = self->roundedPos.x;
240
self->position.y = self->roundedPos.y;
241
242
int32 playerID = 0;
243
foreach_active(Player, player)
244
{
245
Hitbox *playerHitbox = Player_GetHitbox(player);
246
if ((1 << playerID) & self->activePlayers) {
247
if (player->position.x >= self->position.x)
248
player->position.x = (22 - playerHitbox->left) << 16;
249
else
250
player->position.x = (-22 - playerHitbox->right) << 16;
251
player->position.x += startX;
252
}
253
else {
254
int32 side = Player_CheckCollisionBox(player, self, &CheckerBall->hitboxBall);
255
if (side == C_BOTTOM && self->velocity.y >= 0 && player->onGround) {
256
player->deathType = PLAYER_DEATH_DIE_USESFX;
257
}
258
else if (side == C_TOP) {
259
player->position.x += x + (x >> 1) + self->collisionOffset.x;
260
player->position.y += y + self->collisionOffset.y;
261
262
if (player->velocity.x) {
263
if (player->velocity.x <= 0)
264
self->groundVel += player->acceleration >> 2;
265
else
266
self->groundVel -= player->acceleration >> 2;
267
self->playerControlled = true;
268
}
269
self->position.x = startX;
270
self->position.y = startY;
271
self->position.x = self->roundedPos.x;
272
self->position.y = self->roundedPos.y;
273
if (!Player_CheckCollisionBox(player, self, &CheckerBall->hitboxBall)) {
274
player->groundVel += x + (x >> 1);
275
player->velocity.x = player->groundVel;
276
player->onGround = false;
277
player->controlLock = 15;
278
}
279
}
280
}
281
++playerID;
282
}
283
self->position.x = startX;
284
self->position.y = startY;
285
self->collisionOffset.x = 0;
286
self->collisionOffset.y = 0;
287
}
288
289
void CheckerBall_BadnikBreak(void *b, Hitbox *hitbox)
290
{
291
RSDK_THIS(CheckerBall);
292
Entity *badnik = (Entity *)b;
293
294
if (RSDK.CheckObjectCollisionTouchBox(badnik, hitbox, self, &CheckerBall->hitboxBall)) {
295
BadnikHelpers_BadnikBreakUnseeded(badnik, false, true);
296
297
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
298
EntityScoreBonus *bonus = CREATE_ENTITY(ScoreBonus, NULL, badnik->position.x, badnik->position.y);
299
bonus->drawGroup = Zone->objectDrawGroup[1];
300
bonus->animator.frameID = player1->scoreBonus;
301
switch (player1->scoreBonus) {
302
case 0: Player_GiveScore(player1, 100); break;
303
case 1: Player_GiveScore(player1, 200); break;
304
case 2: Player_GiveScore(player1, 500); break;
305
case 3:
306
case 4:
307
case 5:
308
case 6:
309
case 7:
310
case 8:
311
case 9:
312
case 10:
313
case 11:
314
case 12:
315
case 13:
316
case 14: Player_GiveScore(player1, 1000); break;
317
case 15: Player_GiveScore(player1, 10000); break;
318
default: break;
319
}
320
321
if (player1->scoreBonus < 15)
322
player1->scoreBonus++;
323
324
destroyEntity(badnik);
325
}
326
}
327
328
void CheckerBall_HandleObjectCollisions(void)
329
{
330
RSDK_THIS(CheckerBall);
331
EntityPlayer *player1 = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
332
333
foreach_active(PlaneSwitch, planeSwitch)
334
{
335
PlaneSwitch_CheckCollisions(planeSwitch, self, planeSwitch->flags, planeSwitch->size, true, Zone->playerDrawGroup[0],
336
Zone->playerDrawGroup[1]);
337
}
338
339
foreach_active(CheckerBall, checkerBall)
340
{
341
if (checkerBall != self && self->collisionPlane == checkerBall->collisionPlane) {
342
int32 pos = MIN(abs(self->position.x - checkerBall->position.x) >> 17, 23);
343
344
Hitbox hitboxBall;
345
hitboxBall.top = CheckerBall->heightArray[pos] - 22 + (CheckerBall->heightArray[pos] >> 1);
346
hitboxBall.bottom = -hitboxBall.top;
347
hitboxBall.left = -22;
348
hitboxBall.right = 22;
349
350
switch (RSDK.CheckObjectCollisionBox(checkerBall, &hitboxBall, self, &hitboxBall, true)) {
351
case C_TOP:
352
if (self->position.x >= checkerBall->position.x) {
353
self->groundVel += 0xC00;
354
self->velocity.x += 0xC00;
355
checkerBall->groundVel -= 0xC00;
356
checkerBall->velocity.x -= 0xC00;
357
checkerBall->angleVel -= 0xC00;
358
}
359
else {
360
self->groundVel -= 0xC00;
361
self->velocity.x -= 0xC00;
362
checkerBall->groundVel += 0xC00;
363
checkerBall->velocity.x += 0xC00;
364
checkerBall->angleVel += 0xC00;
365
}
366
break;
367
368
case C_LEFT:
369
case C_RIGHT:
370
if (self->groundVel <= 0) {
371
if (self->groundVel < 0 && self->position.x > checkerBall->position.x) {
372
self->velocity.x = checkerBall->velocity.x;
373
self->groundVel = checkerBall->groundVel;
374
}
375
}
376
else if (self->position.x < checkerBall->position.x) {
377
self->velocity.x = checkerBall->velocity.x;
378
self->groundVel = checkerBall->groundVel;
379
checkerBall->groundVel = self->groundVel;
380
checkerBall->velocity.x = self->velocity.x;
381
}
382
else if (self->groundVel < 0 && self->position.x > checkerBall->position.x) {
383
self->velocity.x = checkerBall->velocity.x;
384
self->groundVel = checkerBall->groundVel;
385
}
386
break;
387
388
case C_BOTTOM:
389
if (self->velocity.y <= 0) {
390
if (self->velocity.y < 0 && self->position.y > checkerBall->position.y) {
391
self->velocity.y = checkerBall->velocity.y;
392
checkerBall->velocity.y = self->velocity.y;
393
394
if (self->onGround) {
395
self->velocity.x = checkerBall->velocity.x;
396
self->groundVel = checkerBall->groundVel;
397
}
398
399
if (checkerBall->onGround) {
400
checkerBall->groundVel = self->groundVel;
401
checkerBall->velocity.x = self->velocity.x;
402
}
403
}
404
}
405
406
if (self->position.y < checkerBall->position.y) {
407
self->velocity.y = checkerBall->velocity.y;
408
checkerBall->velocity.y = self->velocity.y;
409
410
if (self->onGround) {
411
self->velocity.x = checkerBall->velocity.x;
412
self->groundVel = checkerBall->groundVel;
413
}
414
415
if (checkerBall->onGround) {
416
checkerBall->groundVel = self->groundVel;
417
checkerBall->velocity.x = self->velocity.x;
418
}
419
}
420
else {
421
if (self->velocity.y < 0 && self->position.y > checkerBall->position.y) {
422
self->velocity.y = checkerBall->velocity.y;
423
checkerBall->velocity.y = self->velocity.y;
424
425
if (self->onGround) {
426
self->velocity.x = checkerBall->velocity.x;
427
self->groundVel = checkerBall->groundVel;
428
}
429
430
if (checkerBall->onGround) {
431
checkerBall->groundVel = self->groundVel;
432
checkerBall->velocity.x = self->velocity.x;
433
}
434
}
435
}
436
break;
437
438
default: break;
439
}
440
441
if (RSDK.CheckObjectCollisionTouchBox(checkerBall, &hitboxBall, self, &hitboxBall)) {
442
if (self->position.x >= checkerBall->position.x)
443
self->position.x += 0x10000;
444
else
445
self->position.x -= 0x10000;
446
447
if (self->position.y >= checkerBall->position.y)
448
self->position.y += 0x10000;
449
else
450
self->position.y -= 0x10000;
451
}
452
}
453
}
454
455
foreach_active(Platform, platform)
456
{
457
if (platform->state != Platform_State_Falling2 && platform->state != Platform_State_Hold) {
458
platform->position.x = platform->drawPos.x - platform->collisionOffset.x;
459
platform->position.y = platform->drawPos.y - platform->collisionOffset.y;
460
461
int32 side = C_NONE;
462
if (platform->collision)
463
side = RSDK.CheckObjectCollisionBox(platform, &platform->hitbox, self, &CheckerBall->hitboxBall, true);
464
else
465
side = RSDK.CheckObjectCollisionPlatform(platform, &platform->hitbox, self, &CheckerBall->hitboxBall, true);
466
467
if (side == C_TOP) {
468
if (platform->state == Platform_State_Fall && !platform->timer)
469
platform->timer = 30;
470
platform->stood = true;
471
self->position.x += platform->collisionOffset.x;
472
self->position.y += platform->collisionOffset.y;
473
self->position.y &= 0xFFFF0000;
474
self->onGround = true;
475
self->collisionOffset.x = platform->collisionOffset.x;
476
self->collisionOffset.y = platform->collisionOffset.y;
477
}
478
platform->position.x = platform->centerPos.x;
479
platform->position.y = platform->centerPos.y;
480
}
481
}
482
483
foreach_active(Bridge, bridge) { Bridge_HandleCollisions(self, bridge, &CheckerBall->hitboxBall, true, false); }
484
485
foreach_active(Batbrain, batBrain) { CheckerBall_BadnikBreak(batBrain, &Batbrain->hitboxBadnik); }
486
487
foreach_active(BuzzBomber, buzzBomber)
488
{
489
if (buzzBomber->state == BuzzBomber_State_ProjectileCharge || buzzBomber->state == BuzzBomber_State_ProjectileShot) {
490
if (RSDK.CheckObjectCollisionTouchBox(buzzBomber, &BuzzBomber->hitboxProjectile, self, &CheckerBall->hitboxBall)) {
491
int32 angle = RSDK.ATan2(self->position.x - buzzBomber->position.x, self->position.y - buzzBomber->position.y);
492
buzzBomber->velocity.x = -0x800 * RSDK.Cos256(angle);
493
buzzBomber->velocity.y = -0x800 * RSDK.Sin256(angle);
494
}
495
}
496
else {
497
CheckerBall_BadnikBreak(buzzBomber, &BuzzBomber->hitboxBadnik);
498
}
499
}
500
501
foreach_active(Chopper, chopper) { CheckerBall_BadnikBreak(chopper, &Chopper->hitboxJump); }
502
503
foreach_active(Crabmeat, crabmeat)
504
{
505
if (crabmeat->state == Crabmeat_State_Projectile) {
506
if (RSDK.CheckObjectCollisionTouchBox(crabmeat, &Crabmeat->hitboxProjectile, self, &CheckerBall->hitboxBall)) {
507
int32 angle = RSDK.ATan2(self->position.x - crabmeat->position.x, self->position.y - crabmeat->position.y);
508
crabmeat->velocity.x = -0x800 * RSDK.Cos256(angle);
509
crabmeat->velocity.y = -0x800 * RSDK.Sin256(angle);
510
}
511
}
512
else {
513
CheckerBall_BadnikBreak(crabmeat, &Crabmeat->hitboxBadnik);
514
}
515
}
516
517
foreach_active(Motobug, motobug)
518
{
519
if (motobug->state != Motobug_State_Smoke)
520
CheckerBall_BadnikBreak(motobug, &Motobug->hitboxBadnik);
521
}
522
523
foreach_active(Newtron, newtron)
524
{
525
if (newtron->state == Newtron_State_Projectile) {
526
if (RSDK.CheckObjectCollisionTouchBox(newtron, &Newtron->hitboxProjectile, self, &CheckerBall->hitboxBall)) {
527
int32 angle = RSDK.ATan2(self->position.x - newtron->position.x, self->position.y - newtron->position.y);
528
newtron->velocity.x = -0x800 * RSDK.Cos256(angle);
529
newtron->velocity.y = -0x800 * RSDK.Sin256(angle);
530
}
531
}
532
else {
533
if (newtron->type == NEWTRON_FLY)
534
CheckerBall_BadnikBreak(newtron, &Newtron->hitboxFly);
535
else
536
CheckerBall_BadnikBreak(newtron, &Newtron->hitboxShoot);
537
}
538
}
539
540
foreach_active(Splats, splats) { CheckerBall_BadnikBreak(splats, &Splats->hitboxBadnikGHZ); }
541
542
foreach_active(ItemBox, itemBox)
543
{
544
if ((itemBox->state == ItemBox_State_Idle || itemBox->state == ItemBox_State_Falling)
545
&& RSDK.CheckObjectCollisionTouchBox(itemBox, &ItemBox->hitboxItemBox, self, &CheckerBall->hitboxBall)) {
546
547
// This code is basically "ItemBox_Break"
548
// "ItemBox_Break" was updated for plus stuff (mighty, swap monitors, etc)
549
// But this is cant be in comp or effect mighty's velocity this was left unchanged
550
551
RSDK.CreateEntity(TYPE_BLANK, NULL, itemBox->position.x, itemBox->position.y);
552
itemBox->storedEntity = (Entity *)player1;
553
itemBox->alpha = 0x100;
554
itemBox->contentsSpeed = -0x38000;
555
itemBox->active = ACTIVE_ALWAYS;
556
itemBox->velocity.y = -0x20000;
557
itemBox->state = ItemBox_State_Break;
558
RSDK.SetSpriteAnimation(ItemBox->aniFrames, 1, &itemBox->boxAnimator, true, 0);
559
itemBox->boxAnimator.frameID = ItemBox->brokenFrame++;
560
ItemBox->brokenFrame %= 3;
561
RSDK.SetSpriteAnimation(-1, 0, &itemBox->overlayAnimator, true, 0);
562
RSDK.SetSpriteAnimation(-1, 0, &itemBox->debrisAnimator, true, 0);
563
CREATE_ENTITY(Explosion, INT_TO_VOID(EXPLOSION_ITEMBOX), itemBox->position.x, itemBox->position.y - 0x100000);
564
565
for (int32 i = 0; i < 6; ++i) {
566
EntityDebris *debris = CREATE_ENTITY(Debris, NULL, itemBox->position.x + RSDK.Rand(-0x80000, 0x80000),
567
itemBox->position.y + RSDK.Rand(-0x80000, 0x80000));
568
debris->state = Debris_State_Fall;
569
debris->gravityStrength = 0x4000;
570
debris->velocity.x = RSDK.Rand(0, 0x20000);
571
if (debris->position.x < itemBox->position.x)
572
debris->velocity.x = -debris->velocity.x;
573
debris->velocity.y = RSDK.Rand(-0x40000, -0x10000);
574
debris->drawFX = FX_FLIP;
575
debris->direction = i & 3;
576
debris->drawGroup = Zone->objectDrawGroup[1];
577
RSDK.SetSpriteAnimation(ItemBox->aniFrames, 6, &debris->animator, true, RSDK.Rand(0, 4));
578
}
579
580
RSDK.PlaySfx(ItemBox->sfxDestroy, false, 0xFF);
581
itemBox->active = ACTIVE_NORMAL;
582
if (itemBox->type == ITEMBOX_RANDOM) {
583
if (itemBox->type == ITEMBOX_1UP_SONIC) {
584
switch (player1->characterID) {
585
case ID_SONIC: itemBox->type = ITEMBOX_1UP_SONIC; break;
586
case ID_TAILS: itemBox->type = ITEMBOX_1UP_TAILS; break;
587
case ID_KNUCKLES: itemBox->type = ITEMBOX_1UP_KNUX; break;
588
#if MANIA_USE_PLUS
589
case ID_MIGHTY: itemBox->type = ITEMBOX_1UP_MIGHTY; break;
590
case ID_RAY: itemBox->type = ITEMBOX_1UP_RAY; break;
591
#endif
592
default: break;
593
}
594
}
595
itemBox->contentsAnimator.frameID = itemBox->type;
596
}
597
}
598
}
599
600
foreach_active(BreakableWall, breakableWall)
601
{
602
if (breakableWall->state == BreakableWall_State_Wall
603
&& RSDK.CheckObjectCollisionTouchBox(breakableWall, &breakableWall->hitbox, self, &CheckerBall->hitboxBall)) {
604
int32 *offsets = BreakableWall->breakOffsets;
605
606
int32 *velocities = NULL;
607
if (self->position.x >= breakableWall->position.x)
608
velocities = BreakableWall->breakVelocitiesR;
609
else
610
velocities = BreakableWall->breakVelocitiesL;
611
612
for (int32 y = 0; y < 4; ++y) {
613
for (int32 x = 0; x < 2; ++x) {
614
int32 tx = breakableWall->position.x + offsets[0];
615
int32 ty = breakableWall->position.y + offsets[1];
616
EntityBreakableWall *tile = CREATE_ENTITY(BreakableWall, INT_TO_VOID(BREAKWALL_TILE_FIXED), tx, ty);
617
tile->tileInfo = RSDK.GetTile(Zone->fgLayer[1], tx >> 20, ty >> 20);
618
tile->velocity.x = velocities[0];
619
tile->velocity.y = velocities[1];
620
RSDK.SetTile(Zone->fgLayer[1], tx >> 20, ty >> 20, -1);
621
offsets += 2;
622
velocities += 2;
623
}
624
}
625
626
RSDK.PlaySfx(BreakableWall->sfxBreak, false, 0xFF);
627
destroyEntity(breakableWall);
628
}
629
}
630
631
foreach_active(CollapsingPlatform, collapsingPlatform)
632
{
633
if (RSDK.CheckObjectCollisionTouchBox(collapsingPlatform, &collapsingPlatform->hitboxTrigger, self, &CheckerBall->hitboxBall)
634
&& self->onGround)
635
collapsingPlatform->stoodPos.x = self->position.x;
636
}
637
638
foreach_active(Spikes, spikes)
639
{
640
if (RSDK.CheckObjectCollisionBox(spikes, &spikes->hitbox, self, &CheckerBall->hitboxBall, true)) {
641
self->onGround = true;
642
self->position.x += spikes->collisionOffset.x;
643
self->position.y += spikes->collisionOffset.y;
644
}
645
}
646
647
foreach_active(Spring, spring)
648
{
649
int32 side = RSDK.CheckObjectCollisionBox(spring, &spring->hitbox, self, &CheckerBall->hitboxBall, true);
650
if (side) {
651
bool32 bounced = false;
652
653
if (spring->state == Spring_State_Vertical) {
654
if ((spring->direction && side == C_BOTTOM) || (!spring->direction && side == C_TOP))
655
bounced = true;
656
}
657
else {
658
if (spring->state == Spring_State_Diagonal) {
659
if (self->onGround || self->velocity.y >= 0 || abs(self->velocity.x) > -self->velocity.y)
660
bounced = true;
661
}
662
else if (spring->state == Spring_State_Horizontal && (!spring->onGround || self->onGround)) {
663
if ((!spring->direction && side == C_RIGHT) || (spring->direction && side == C_LEFT))
664
bounced = true;
665
}
666
}
667
668
if (bounced) {
669
if (spring->state != Spring_State_Vertical) {
670
self->groundVel = spring->velocity.x;
671
self->velocity.x = spring->velocity.x;
672
}
673
674
if (spring->state != Spring_State_Horizontal) {
675
self->onGround = false;
676
self->velocity.y = spring->velocity.y;
677
}
678
679
RSDK.SetSpriteAnimation(Spring->aniFrames, spring->type, &spring->animator, true, 0);
680
RSDK.PlaySfx(Spring->sfxSpring, false, 0xFF);
681
}
682
}
683
}
684
}
685
686
#if GAME_INCLUDE_EDITOR
687
void CheckerBall_EditorDraw(void) { CheckerBall_Draw(); }
688
689
void CheckerBall_EditorLoad(void)
690
{
691
if (RSDK.CheckSceneFolder("GHZ"))
692
CheckerBall->aniFrames = RSDK.LoadSpriteAnimation("GHZ/CheckerBall.bin", SCOPE_STAGE);
693
else if (RSDK.CheckSceneFolder("Blueprint"))
694
CheckerBall->aniFrames = RSDK.LoadSpriteAnimation("Blueprint/CheckerBall.bin", SCOPE_STAGE);
695
}
696
#endif
697
698
void CheckerBall_Serialize(void) {}
699
700