Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/Common/Button.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Button Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectButton *Button;
11
12
void Button_Update(void)
13
{
14
RSDK_THIS(Button);
15
16
self->down = false;
17
self->currentlyActive = false;
18
19
switch (self->type) {
20
case BUTTON_FLOOR:
21
Button_HandleFloor();
22
23
if (Button->hasEggman)
24
Button_CheckEggmanCollisions();
25
if (Button->hasPhantomRider)
26
Button_CheckPRiderCollisions();
27
break;
28
29
case BUTTON_ROOF: Button_HandleRoof(); break;
30
case BUTTON_RWALL: Button_HandleRWall(); break;
31
case BUTTON_LWALL: Button_HandleLWall(); break;
32
33
default: break;
34
}
35
36
if (!self->down)
37
self->wasActivated = false;
38
39
self->baseAnimator.frameID = self->down + 1;
40
}
41
42
void Button_LateUpdate(void) {}
43
44
void Button_StaticUpdate(void) {}
45
46
void Button_Draw(void)
47
{
48
RSDK_THIS(Button);
49
50
Vector2 drawPos;
51
52
drawPos.x = self->position.x;
53
drawPos.y = self->position.y;
54
55
if (self->type >= BUTTON_RWALL)
56
drawPos.x -= self->pressPos;
57
else
58
drawPos.y += self->pressPos;
59
60
RSDK.DrawSprite(&self->buttonAnimator, &drawPos, false);
61
RSDK.DrawSprite(&self->baseAnimator, NULL, false);
62
}
63
64
void Button_Create(void *data)
65
{
66
RSDK_THIS(Button);
67
68
self->drawFX = FX_FLIP;
69
if (!SceneInfo->inEditor) {
70
switch (self->type) {
71
case BUTTON_FLOOR:
72
self->direction = FLIP_NONE;
73
RSDK.SetSpriteAnimation(Button->aniFrames, 0, &self->buttonAnimator, true, 0);
74
RSDK.SetSpriteAnimation(Button->aniFrames, 0, &self->baseAnimator, true, 1);
75
76
self->hitboxButton.left = Button->hitboxV.left;
77
self->hitboxButton.top = Button->hitboxV.top;
78
self->hitboxButton.right = Button->hitboxV.right;
79
self->hitboxButton.bottom = Button->hitboxV.bottom;
80
break;
81
82
case BUTTON_ROOF:
83
self->direction = FLIP_Y;
84
RSDK.SetSpriteAnimation(Button->aniFrames, 0, &self->buttonAnimator, true, 0);
85
RSDK.SetSpriteAnimation(Button->aniFrames, 0, &self->baseAnimator, true, 1);
86
87
self->hitboxButton.left = Button->hitboxV.left;
88
self->hitboxButton.top = Button->hitboxV.top;
89
self->hitboxButton.right = Button->hitboxV.right;
90
self->hitboxButton.bottom = Button->hitboxV.bottom;
91
break;
92
93
case BUTTON_RWALL:
94
self->direction = FLIP_NONE;
95
RSDK.SetSpriteAnimation(Button->aniFrames, 1, &self->buttonAnimator, true, 0);
96
RSDK.SetSpriteAnimation(Button->aniFrames, 1, &self->baseAnimator, true, 1);
97
98
self->hitboxButton.left = Button->hitboxH.left;
99
self->hitboxButton.top = Button->hitboxH.top;
100
self->hitboxButton.right = Button->hitboxH.right;
101
self->hitboxButton.bottom = Button->hitboxH.bottom;
102
break;
103
104
case BUTTON_LWALL:
105
self->direction = FLIP_X;
106
RSDK.SetSpriteAnimation(Button->aniFrames, 1, &self->buttonAnimator, true, 0);
107
RSDK.SetSpriteAnimation(Button->aniFrames, 1, &self->baseAnimator, true, 1);
108
109
self->hitboxButton.left = Button->hitboxH.left;
110
self->hitboxButton.top = Button->hitboxH.top;
111
self->hitboxButton.right = Button->hitboxH.right;
112
self->hitboxButton.bottom = Button->hitboxH.bottom;
113
break;
114
115
default: break;
116
}
117
118
self->active = ACTIVE_BOUNDS;
119
self->updateRange.x = TO_FIXED(32);
120
self->updateRange.y = TO_FIXED(32);
121
self->visible = true;
122
self->drawGroup = Zone->objectDrawGroup[0];
123
}
124
}
125
126
void Button_StageLoad(void)
127
{
128
if (RSDK.CheckSceneFolder("MMZ")) {
129
Button->aniFrames = RSDK.LoadSpriteAnimation("MMZ/Button.bin", SCOPE_STAGE);
130
Button->activatePos = TO_FIXED(8);
131
Button->buttonOffset = TO_FIXED(5);
132
Button->hitboxOffset = 13;
133
Button->unused1 = 5;
134
}
135
else if (RSDK.CheckSceneFolder("FBZ")) {
136
Button->aniFrames = RSDK.LoadSpriteAnimation("FBZ/Button.bin", SCOPE_STAGE);
137
Button->activatePos = TO_FIXED(8);
138
Button->buttonOffset = TO_FIXED(5);
139
Button->hitboxOffset = 13;
140
Button->unused1 = 5;
141
}
142
else if (RSDK.CheckSceneFolder("LRZ1")) {
143
Button->aniFrames = RSDK.LoadSpriteAnimation("LRZ1/Button.bin", SCOPE_STAGE);
144
Button->activatePos = TO_FIXED(4);
145
Button->buttonOffset = TO_FIXED(3);
146
Button->hitboxOffset = 7;
147
Button->unused1 = 3;
148
}
149
else if (RSDK.CheckSceneFolder("LRZ2")) {
150
Button->aniFrames = RSDK.LoadSpriteAnimation("LRZ2/Button.bin", SCOPE_STAGE);
151
Button->activatePos = TO_FIXED(4);
152
Button->buttonOffset = TO_FIXED(3);
153
Button->hitboxOffset = 7;
154
Button->unused1 = 3;
155
}
156
else if (RSDK.CheckSceneFolder("HCZ")) {
157
Button->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Button.bin", SCOPE_STAGE);
158
Button->activatePos = TO_FIXED(3);
159
Button->buttonOffset = TO_FIXED(3);
160
Button->hitboxOffset = 9;
161
Button->unused1 = 6;
162
}
163
else if (RSDK.CheckSceneFolder("TMZ3")) {
164
Button->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/Button.bin", SCOPE_STAGE);
165
Button->activatePos = TO_FIXED(3);
166
Button->buttonOffset = TO_FIXED(3);
167
Button->hitboxOffset = 9;
168
Button->unused1 = 6;
169
}
170
else {
171
Button->activatePos = TO_FIXED(8);
172
Button->buttonOffset = TO_FIXED(5);
173
Button->hitboxOffset = 13;
174
Button->unused1 = 5;
175
}
176
177
Button->hitboxH.left = -3;
178
Button->hitboxH.top = -16;
179
Button->hitboxH.right = 8;
180
Button->hitboxH.bottom = 16;
181
182
Button->hitboxV.left = -16;
183
Button->hitboxV.top = -8;
184
Button->hitboxV.right = 16;
185
Button->hitboxV.bottom = 3;
186
187
if (RSDK.FindObject("Eggman"))
188
Button->hasEggman = true;
189
190
if (RSDK.FindObject("PhantomRider"))
191
Button->hasPhantomRider = true;
192
193
Button->sfxButton = RSDK.GetSfx("Stage/Button.wav");
194
}
195
196
void Button_CheckEggmanCollisions(void)
197
{
198
RSDK_THIS(Button);
199
200
foreach_active(Eggman, eggman)
201
{
202
self->hitboxButton.top = (Button->activatePos >> 16) - (Button->hitboxOffset & 0xFFFF);
203
if (RSDK.CheckObjectCollisionPlatform(self, &self->hitboxButton, eggman, &eggman->hitbox, true)) {
204
eggman->onGround = true;
205
self->pressPos = Button->activatePos;
206
207
if (!self->wasActivated) {
208
RSDK.PlaySfx(Button->sfxButton, false, 0xFF);
209
self->currentlyActive = true;
210
self->toggled ^= true;
211
}
212
213
self->wasActivated = true;
214
self->down = true;
215
self->activated = true;
216
}
217
}
218
}
219
220
void Button_CheckPRiderCollisions(void)
221
{
222
RSDK_THIS(Button);
223
224
foreach_active(PhantomRider, rider)
225
{
226
self->hitboxButton.top = (Button->activatePos >> 16) - (Button->hitboxOffset & 0xFFFF);
227
if (RSDK.CheckObjectCollisionPlatform(self, &self->hitboxButton, rider, &rider->hitbox, true)) {
228
self->pressPos = Button->activatePos;
229
230
if (!self->wasActivated) {
231
RSDK.PlaySfx(Button->sfxButton, false, 0xFF);
232
self->currentlyActive = true;
233
self->toggled ^= true;
234
}
235
236
self->wasActivated = true;
237
self->down = true;
238
self->activated = true;
239
}
240
}
241
}
242
243
void Button_HandleFloor(void)
244
{
245
RSDK_THIS(Button);
246
247
int32 startPressPos = self->pressPos;
248
self->pressPos = 0;
249
250
foreach_active(Player, player)
251
{
252
self->hitboxButton.top = (startPressPos >> 16) - (Button->hitboxOffset & 0xFFFF);
253
self->hitboxButton.bottom = self->hitboxButton.top + 32;
254
255
int32 playerX = player->position.x;
256
int32 playerY = player->position.y;
257
int32 xVel = player->velocity.x;
258
int32 yVel = player->velocity.y;
259
int32 vel = player->groundVel;
260
bool32 grounded = player->onGround;
261
bool32 groundedStore = player->groundedStore;
262
StateMachine(nextGState) = player->nextGroundState;
263
StateMachine(nextAState) = player->nextAirState;
264
StateMachine(state) = player->state;
265
266
if (Player_CheckCollisionBox(player, self, &self->hitboxButton) == C_TOP || self->walkOnto) {
267
player->position.x = playerX;
268
player->position.y = playerY;
269
player->velocity.x = xVel;
270
player->velocity.y = yVel;
271
player->groundVel = vel;
272
player->onGround = grounded;
273
player->groundedStore = groundedStore;
274
player->nextGroundState = nextGState;
275
player->nextAirState = nextAState;
276
player->state = state;
277
278
self->hitboxButton.top -= (startPressPos >> 16);
279
self->hitboxButton.top += (Button->activatePos >> 16);
280
int32 newPressPos = self->pressPos;
281
282
if (Player_CheckCollisionPlatform(player, self, &self->hitboxButton) == C_TOP) {
283
self->pressPos = Button->activatePos;
284
}
285
else {
286
self->position.y -= Button->activatePos;
287
if (Player_CheckCollisionTouch(player, self, &self->hitboxButton)) {
288
Hitbox *playerHitbox = Player_GetHitbox(player);
289
self->pressPos = Button->buttonOffset + (player->position.y & 0xFFFF0000) + (playerHitbox->bottom << 16) - self->position.y;
290
self->pressPos = CLAMP(self->pressPos, 0, Button->activatePos) & 0xFFFF0000;
291
}
292
293
self->position.y += Button->activatePos;
294
}
295
296
if (self->pressPos == Button->activatePos) {
297
Player_CheckCollisionBox(player, self, &self->hitboxButton);
298
player->angle = 0;
299
if (!self->wasActivated) {
300
RSDK.PlaySfx(Button->sfxButton, false, 255);
301
self->currentlyActive = true;
302
self->toggled ^= true;
303
}
304
self->wasActivated = true;
305
self->down = true;
306
self->activated = true;
307
}
308
309
if (newPressPos > self->pressPos)
310
self->pressPos = newPressPos;
311
}
312
313
if (self->pressPos)
314
startPressPos = self->pressPos;
315
}
316
}
317
void Button_HandleRoof(void)
318
{
319
RSDK_THIS(Button);
320
321
int32 startPressPos = self->pressPos;
322
self->pressPos = 0;
323
324
foreach_active(Player, player)
325
{
326
self->hitboxButton.top = -1 - (Button->hitboxOffset & 0xFFFF) - (startPressPos >> 16);
327
self->hitboxButton.bottom = self->hitboxButton.top + 32;
328
329
int32 playerX = player->position.x;
330
int32 playerY = player->position.y;
331
int32 xVel = player->velocity.x;
332
int32 yVel = player->velocity.y;
333
int32 vel = player->groundVel;
334
bool32 grounded = player->onGround;
335
bool32 groundedStore = player->groundedStore;
336
StateMachine(nextGState) = player->nextGroundState;
337
StateMachine(nextAState) = player->nextAirState;
338
StateMachine(state) = player->state;
339
340
if (Player_CheckCollisionBox(player, self, &self->hitboxButton) == C_BOTTOM || self->walkOnto) {
341
player->position.x = playerX;
342
player->position.y = playerY;
343
player->velocity.x = xVel;
344
player->velocity.y = yVel;
345
player->groundVel = vel;
346
player->onGround = grounded;
347
player->groundedStore = groundedStore;
348
player->nextGroundState = nextGState;
349
player->nextAirState = nextAState;
350
player->state = state;
351
352
self->hitboxButton.top += (startPressPos >> 16);
353
self->hitboxButton.top += (Button->activatePos >> 16);
354
int32 newPressPos = self->pressPos;
355
356
if (Player_CheckCollisionBox(player, self, &self->hitboxButton) == C_BOTTOM) {
357
self->pressPos = -Button->activatePos;
358
}
359
else {
360
self->position.y += Button->activatePos;
361
if (Player_CheckCollisionTouch(player, self, &self->hitboxButton)) {
362
Hitbox *playerHitbox = Player_GetHitbox(player);
363
self->pressPos = (player->position.y & 0xFFFF0000) + (playerHitbox->top << 16) - Button->buttonOffset - self->position.y;
364
self->pressPos = CLAMP(self->pressPos, -Button->activatePos, 0) & 0xFFFF0000;
365
}
366
367
self->position.y -= Button->activatePos;
368
}
369
370
if (self->pressPos == -Button->activatePos) {
371
if (!self->wasActivated) {
372
RSDK.PlaySfx(Button->sfxButton, false, 255);
373
self->currentlyActive = true;
374
self->toggled ^= true;
375
}
376
377
self->wasActivated = true;
378
self->down = true;
379
self->activated = true;
380
}
381
382
if (newPressPos < self->pressPos)
383
self->pressPos = newPressPos;
384
}
385
386
if (self->pressPos)
387
startPressPos = self->pressPos;
388
}
389
}
390
void Button_HandleRWall(void)
391
{
392
RSDK_THIS(Button);
393
394
int32 startPressPos = self->pressPos;
395
self->pressPos = 0;
396
397
foreach_active(Player, player)
398
{
399
self->hitboxButton.right = (Button->hitboxOffset & 0xFFFF) - (startPressPos >> 16) + 1;
400
self->hitboxButton.left = self->hitboxButton.right - 16;
401
402
int32 playerX = player->position.x;
403
int32 playerY = player->position.y;
404
int32 xVel = player->velocity.x;
405
int32 yVel = player->velocity.y;
406
int32 vel = player->groundVel;
407
bool32 grounded = player->onGround;
408
bool32 groundedStore = player->groundedStore;
409
StateMachine(nextGState) = player->nextGroundState;
410
StateMachine(nextAState) = player->nextAirState;
411
StateMachine(state) = player->state;
412
413
if (Player_CheckCollisionBox(player, self, &self->hitboxButton) == C_RIGHT || self->walkOnto) {
414
player->position.x = playerX;
415
player->position.y = playerY;
416
player->velocity.x = xVel;
417
player->velocity.y = yVel;
418
player->groundVel = vel;
419
player->onGround = grounded;
420
player->groundedStore = groundedStore;
421
player->nextGroundState = nextGState;
422
player->nextAirState = nextAState;
423
player->state = state;
424
425
self->hitboxButton.right += (startPressPos >> 16);
426
self->hitboxButton.right = self->hitboxButton.right - (Button->activatePos >> 16) - 1;
427
int32 newPressPos = self->pressPos;
428
429
if (Player_CheckCollisionBox(player, self, &self->hitboxButton) == C_RIGHT) {
430
self->pressPos = Button->activatePos;
431
}
432
else {
433
self->position.x += Button->activatePos;
434
if (Player_CheckCollisionTouch(player, self, &self->hitboxButton)) {
435
Hitbox *playerHitbox = Player_GetHitbox(player);
436
self->pressPos = Button->buttonOffset - (playerHitbox->left << 16) - (player->position.x & 0xFFFF0000) + self->position.x;
437
self->pressPos = CLAMP(self->pressPos, 0, Button->activatePos) & 0xFFFF0000;
438
}
439
self->position.x -= Button->activatePos;
440
}
441
442
if (self->pressPos == Button->activatePos) {
443
if (!self->wasActivated) {
444
RSDK.PlaySfx(Button->sfxButton, false, 255);
445
self->currentlyActive = true;
446
self->toggled ^= true;
447
}
448
449
self->wasActivated = true;
450
self->down = true;
451
self->activated = true;
452
}
453
454
if (newPressPos > self->pressPos)
455
self->pressPos = newPressPos;
456
}
457
458
if (self->pressPos)
459
startPressPos = self->pressPos;
460
}
461
}
462
void Button_HandleLWall(void)
463
{
464
RSDK_THIS(Button);
465
int32 startPressPos = self->pressPos;
466
self->pressPos = 0;
467
468
foreach_active(Player, player)
469
{
470
self->hitboxButton.right = (startPressPos >> 16) + (Button->hitboxOffset & 0xFFFF);
471
self->hitboxButton.left = self->hitboxButton.right - 16;
472
473
int32 playerX = player->position.x;
474
int32 playerY = player->position.y;
475
int32 xVel = player->velocity.x;
476
int32 yVel = player->velocity.y;
477
int32 vel = player->groundVel;
478
bool32 grounded = player->onGround;
479
bool32 groundedStore = player->groundedStore;
480
StateMachine(nextGState) = player->nextGroundState;
481
StateMachine(nextAState) = player->nextAirState;
482
StateMachine(state) = player->state;
483
484
if (Player_CheckCollisionBox(player, self, &self->hitboxButton) == C_LEFT || self->walkOnto) {
485
player->position.x = playerX;
486
player->position.y = playerY;
487
player->velocity.x = xVel;
488
player->velocity.y = yVel;
489
player->groundVel = vel;
490
player->onGround = grounded;
491
player->groundedStore = groundedStore;
492
player->nextGroundState = nextGState;
493
player->nextAirState = nextAState;
494
player->state = state;
495
496
self->hitboxButton.right -= (startPressPos >> 16);
497
self->hitboxButton.right -= (Button->activatePos >> 16);
498
int32 newPressPos = self->pressPos;
499
500
if (Player_CheckCollisionBox(player, self, &self->hitboxButton) == C_LEFT) {
501
self->pressPos = -Button->activatePos;
502
}
503
else {
504
self->position.x -= Button->activatePos;
505
if (Player_CheckCollisionTouch(player, self, &self->hitboxButton)) {
506
Hitbox *playerHitbox = Player_GetHitbox(player);
507
self->pressPos = self->position.x - (playerHitbox->right << 16) - (player->position.x & 0xFFFF0000) - Button->buttonOffset;
508
self->pressPos = CLAMP(self->pressPos, -Button->activatePos, 0) & 0xFFFF0000;
509
}
510
511
self->position.x += Button->activatePos;
512
}
513
514
if (self->pressPos == -Button->activatePos) {
515
if (!self->wasActivated) {
516
RSDK.PlaySfx(Button->sfxButton, false, 255);
517
self->currentlyActive = true;
518
self->toggled ^= true;
519
}
520
self->wasActivated = true;
521
self->down = true;
522
self->activated = true;
523
}
524
525
if (newPressPos < self->pressPos)
526
self->pressPos = newPressPos;
527
}
528
529
if (self->pressPos)
530
startPressPos = self->pressPos;
531
}
532
533
self->hitboxButton.right = (Button->hitboxOffset & 0xFFFF) + (startPressPos >> 16);
534
self->hitboxButton.left = self->hitboxButton.left - 16;
535
}
536
537
#if GAME_INCLUDE_EDITOR
538
void Button_EditorDraw(void)
539
{
540
RSDK_THIS(Button);
541
542
switch (self->type) {
543
case BUTTON_FLOOR:
544
self->direction = FLIP_NONE;
545
RSDK.SetSpriteAnimation(Button->aniFrames, 0, &self->buttonAnimator, true, 0);
546
RSDK.SetSpriteAnimation(Button->aniFrames, 0, &self->baseAnimator, true, 1);
547
break;
548
549
case BUTTON_ROOF:
550
self->direction = FLIP_Y;
551
RSDK.SetSpriteAnimation(Button->aniFrames, 0, &self->buttonAnimator, true, 0);
552
RSDK.SetSpriteAnimation(Button->aniFrames, 0, &self->baseAnimator, true, 1);
553
break;
554
555
case BUTTON_RWALL:
556
self->direction = FLIP_NONE;
557
RSDK.SetSpriteAnimation(Button->aniFrames, 1, &self->buttonAnimator, true, 0);
558
RSDK.SetSpriteAnimation(Button->aniFrames, 1, &self->baseAnimator, true, 1);
559
break;
560
561
case BUTTON_LWALL:
562
self->direction = FLIP_X;
563
RSDK.SetSpriteAnimation(Button->aniFrames, 1, &self->buttonAnimator, true, 0);
564
RSDK.SetSpriteAnimation(Button->aniFrames, 1, &self->baseAnimator, true, 1);
565
break;
566
567
default: break;
568
}
569
570
RSDK.DrawSprite(&self->buttonAnimator, NULL, false);
571
RSDK.DrawSprite(&self->baseAnimator, NULL, false);
572
}
573
574
void Button_EditorLoad(void)
575
{
576
if (RSDK.CheckSceneFolder("MMZ"))
577
Button->aniFrames = RSDK.LoadSpriteAnimation("MMZ/Button.bin", SCOPE_STAGE);
578
else if (RSDK.CheckSceneFolder("FBZ"))
579
Button->aniFrames = RSDK.LoadSpriteAnimation("FBZ/Button.bin", SCOPE_STAGE);
580
else if (RSDK.CheckSceneFolder("LRZ1"))
581
Button->aniFrames = RSDK.LoadSpriteAnimation("LRZ1/Button.bin", SCOPE_STAGE);
582
else if (RSDK.CheckSceneFolder("LRZ2"))
583
Button->aniFrames = RSDK.LoadSpriteAnimation("LRZ2/Button.bin", SCOPE_STAGE);
584
else if (RSDK.CheckSceneFolder("HCZ"))
585
Button->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Button.bin", SCOPE_STAGE);
586
else if (RSDK.CheckSceneFolder("TMZ3"))
587
Button->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/Button.bin", SCOPE_STAGE);
588
589
RSDK_ACTIVE_VAR(Button, type);
590
RSDK_ENUM_VAR("Floor", BUTTON_FLOOR);
591
RSDK_ENUM_VAR("Ceiling", BUTTON_ROOF);
592
RSDK_ENUM_VAR("Right Wall", BUTTON_RWALL);
593
RSDK_ENUM_VAR("Left Wall", BUTTON_LWALL);
594
}
595
#endif
596
597
void Button_Serialize(void)
598
{
599
RSDK_EDITABLE_VAR(Button, VAR_ENUM, type);
600
RSDK_EDITABLE_VAR(Button, VAR_BOOL, walkOnto);
601
RSDK_EDITABLE_VAR(Button, VAR_UINT8, tag);
602
}
603
604