Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/FBZ/Cylinder.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Cylinder Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectCylinder *Cylinder;
11
12
void Cylinder_Update(void)
13
{
14
RSDK_THIS(Cylinder);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Cylinder_LateUpdate(void) {}
20
21
void Cylinder_StaticUpdate(void) {}
22
23
void Cylinder_Draw(void) {}
24
25
void Cylinder_Create(void *data)
26
{
27
RSDK_THIS(Cylinder);
28
29
if (!SceneInfo->inEditor) {
30
self->active = ACTIVE_BOUNDS;
31
self->visible = false;
32
self->drawGroup = Zone->objectDrawGroup[0];
33
34
switch (self->type) {
35
case CYLINDER_TUBE_H:
36
self->updateRange.x = self->length << 16;
37
self->updateRange.y = self->radius << 16;
38
39
self->hitboxRange.left = -self->length;
40
self->hitboxRange.top = -self->radius;
41
self->hitboxRange.right = self->length;
42
self->hitboxRange.bottom = self->radius;
43
44
self->hitboxSize.left = -self->length;
45
self->hitboxSize.top = -self->radius;
46
self->hitboxSize.right = self->length;
47
self->hitboxSize.bottom = -self->radius + 8;
48
49
self->state = Cylinder_State_TubeH;
50
break;
51
52
case CYLINDER_TUBE_V:
53
self->updateRange.x = self->radius << 16;
54
self->updateRange.y = self->length << 16;
55
56
self->hitboxRange.left = -self->radius;
57
self->hitboxRange.top = -self->length;
58
self->hitboxRange.right = self->radius;
59
self->hitboxRange.bottom = self->length;
60
61
self->state = Cylinder_State_TubeV;
62
break;
63
64
case CYLINDER_SPIRAL_LR:
65
self->updateRange.x = (self->radius + 112) << 16;
66
self->updateRange.y = self->length << 16;
67
68
self->hitboxRange.left = -64 - self->radius;
69
self->hitboxRange.right = self->radius + 64;
70
self->hitboxRange.top = -self->length;
71
self->hitboxRange.bottom = self->length;
72
73
self->hitboxL.left = -112 - self->radius;
74
self->hitboxL.right = -self->radius;
75
self->hitboxL.top = -self->length;
76
self->hitboxL.bottom = 64 - self->length;
77
78
self->hitboxR.left = self->radius;
79
self->hitboxR.top = self->length - 64;
80
self->hitboxR.right = self->length + 112;
81
self->hitboxR.bottom = self->length;
82
83
self->state = Cylinder_State_Spiral;
84
break;
85
86
case CYLINDER_SPIRAL_RL:
87
self->updateRange.x = (self->radius + 112) << 16;
88
self->updateRange.y = self->length << 16;
89
90
self->hitboxRange.left = -64 - self->radius;
91
self->hitboxRange.top = -self->length;
92
self->hitboxRange.right = self->radius + 64;
93
self->hitboxRange.bottom = self->length;
94
95
self->hitboxL.left = -112 - self->radius;
96
self->hitboxL.top = self->length - 64;
97
self->hitboxL.right = -self->radius;
98
self->hitboxL.bottom = self->length;
99
100
self->hitboxR.left = self->radius;
101
self->hitboxR.top = -self->length;
102
self->hitboxR.right = self->radius + 112;
103
self->hitboxR.bottom = 64 - self->length;
104
105
self->state = Cylinder_State_Spiral;
106
break;
107
108
case CYLINDER_INKROLLER:
109
self->updateRange.x = self->length << 16;
110
self->updateRange.y = self->radius << 16;
111
112
self->hitboxRange.left = 16 - self->length;
113
self->hitboxRange.top = ~self->radius;
114
self->hitboxRange.right = self->length - 16;
115
self->hitboxRange.bottom = self->radius + 1;
116
117
self->hitboxSize.left = -self->length;
118
self->hitboxSize.top = -self->radius;
119
self->hitboxSize.right = self->length;
120
self->hitboxSize.bottom = self->radius;
121
122
self->state = Cylinder_State_InkRoller;
123
break;
124
125
case CYLINDER_PILLAR:
126
self->visible = true;
127
self->updateRange.x = self->radius << 17;
128
self->updateRange.y = self->length << 17;
129
130
self->hitboxRange.left = -16 - self->radius;
131
self->hitboxRange.top = -self->length;
132
self->hitboxRange.right = self->radius + 16;
133
self->hitboxRange.bottom = self->length;
134
self->length = 2 * self->length;
135
136
self->state = Cylinder_State_Pillar;
137
break;
138
139
default: break;
140
}
141
}
142
}
143
144
void Cylinder_StageLoad(void) {}
145
146
void Cylinder_State_TubeH(void)
147
{
148
RSDK_THIS(Cylinder);
149
150
foreach_active(Player, player)
151
{
152
Hitbox *playerHitbox = Player_GetHitbox(player);
153
int32 radius = (self->radius - playerHitbox->bottom) << 6;
154
155
if (self->playerStatus[player->playerID]) {
156
if (!Player_CheckCollisionTouch(player, self, &self->hitboxRange) || player->velocity.y <= -0x40000) {
157
if (((self->playerAngles[player->playerID] + 128) & 0x3FF) < 0x100)
158
player->velocity.y >>= 1;
159
else
160
player->velocity.y = 0;
161
162
if (!player->onGround && player->velocity.y >= 0 && player->state != Player_State_FlyCarried
163
&& player->animator.animationID != ANI_SKID) {
164
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true,
165
24 * self->playerAngles[player->playerID] / 1024);
166
}
167
168
player->onGround = false;
169
self->playerStatus[player->playerID] = false;
170
}
171
else {
172
self->playerAngles[player->playerID] = (self->playerAngles[player->playerID] + 16) & 0x3FF;
173
player->position.y = radius * RSDK.Cos1024(self->playerAngles[player->playerID]) + self->position.y;
174
175
if (player->state == Player_State_LookUp || player->state == Player_State_Crouch)
176
player->state = Player_State_Ground;
177
178
if (player->state != Player_State_Ground || player->onGround || player->animator.animationID == ANI_SKID) {
179
if (player->state == Player_State_Roll) {
180
if (player->velocity.x)
181
player->direction = player->velocity.x > 0;
182
}
183
184
player->onGround = true;
185
}
186
else {
187
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true,
188
24 * self->playerAngles[player->playerID] / 1024);
189
player->onGround = true;
190
}
191
}
192
}
193
else if (Player_CheckCollisionTouch(player, self, &self->hitboxRange)) {
194
if (player->position.y - self->position.y > radius << 10 && player->velocity.y >= 0) {
195
player->position.y = self->position.y + (radius << 10);
196
player->velocity.y = 0;
197
player->onGround = true;
198
self->playerAngles[player->playerID] = 0;
199
self->playerStatus[player->playerID] = true;
200
}
201
}
202
}
203
}
204
205
void Cylinder_State_TubeV(void)
206
{
207
RSDK_THIS(Cylinder);
208
209
foreach_active(Player, player)
210
{
211
Hitbox *playerHitbox = Player_GetHitbox(player);
212
int32 radius = (self->radius - playerHitbox->bottom) << 6;
213
214
if (self->playerStatus[player->playerID]) {
215
if (Player_CheckCollisionTouch(player, self, &self->hitboxRange)) {
216
self->playerAngles[player->playerID] = (self->playerAngles[player->playerID] + 16) & 0x3FF;
217
player->position.x = radius * RSDK.Cos1024(self->playerAngles[player->playerID]) + self->position.x;
218
player->rotation = 0x80;
219
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true,
220
(24 * self->playerAngles[player->playerID] / 1024 + 12) % 24);
221
player->animator.rotationStyle = ROTSTYLE_FULL;
222
player->direction = player->velocity.y < 0;
223
}
224
else {
225
if (player->collisionMode == CMODE_LWALL)
226
player->angle = 0x40;
227
else if (player->collisionMode == CMODE_RWALL)
228
player->angle = 0xC0;
229
230
player->onGround = false;
231
player->state = Player_State_Air;
232
self->playerStatus[player->playerID] = false;
233
}
234
}
235
else if (Player_CheckCollisionTouch(player, self, &self->hitboxRange)) {
236
if (abs(player->position.x - self->position.x) > (radius - 896) << 10) {
237
if (player->position.x - self->position.x <= 0) {
238
player->collisionMode = CMODE_RWALL;
239
self->playerAngles[player->playerID] = 0x200;
240
}
241
else {
242
player->collisionMode = CMODE_LWALL;
243
self->playerAngles[player->playerID] = 0x000;
244
}
245
246
player->state = Player_State_Air;
247
player->nextAirState = StateMachine_None;
248
player->nextGroundState = StateMachine_None;
249
self->playerStatus[player->playerID] = 1;
250
}
251
}
252
}
253
}
254
255
void Cylinder_State_Spiral(void)
256
{
257
RSDK_THIS(Cylinder);
258
259
foreach_active(Player, player)
260
{
261
Hitbox *playerHitbox = Player_GetHitbox(player);
262
int32 radius = (self->radius - playerHitbox->bottom - 12) << 6;
263
264
switch (self->playerStatus[player->playerID]) {
265
case 0:
266
if (player->onGround) {
267
bool32 collided = false;
268
if (Player_CheckCollisionTouch(player, self, &self->hitboxL) && player->groundVel > 0x30000)
269
collided = true;
270
if (Player_CheckCollisionTouch(player, self, &self->hitboxR) && player->groundVel < -0x30000)
271
collided = true;
272
273
if (collided) {
274
self->playerStatus[player->playerID] = 1;
275
player->state = Cylinder_PlayerState_Spiral;
276
}
277
}
278
break;
279
280
case 1:
281
if (player->groundVel <= 0x30000) {
282
if (player->groundVel >= -0x30000) {
283
player->onGround = false;
284
self->playerStatus[player->playerID] = 0;
285
}
286
else {
287
if (player->position.x <= self->position.x) {
288
self->playerAngles[player->playerID] = 768;
289
player->tileCollisions = TILECOLLISION_NONE;
290
self->playerStatus[player->playerID] = 2;
291
}
292
293
int32 distance = (player->position.x - self->position.x) >> 16;
294
int32 right = self->hitboxR.right - 48;
295
if (distance < right) {
296
player->rotation = 256;
297
player->direction = FLIP_NONE;
298
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true, 17 - 6 * distance / right);
299
player->animator.rotationStyle = ROTSTYLE_FULL;
300
}
301
302
player->onGround = true;
303
player->velocity.y = 0;
304
}
305
}
306
else {
307
if (player->position.x >= self->position.x) {
308
self->playerAngles[player->playerID] = 768;
309
player->tileCollisions = TILECOLLISION_NONE;
310
self->playerStatus[player->playerID] = 2;
311
}
312
313
int32 distance = (self->position.x - player->position.x) >> 16;
314
int32 right = -48 - self->hitboxL.left;
315
if (distance < right) {
316
player->rotation = 256;
317
player->direction = FLIP_X;
318
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true, 17 - 6 * distance / right);
319
player->animator.rotationStyle = ROTSTYLE_FULL;
320
player->onGround = true;
321
player->velocity.y = 0;
322
}
323
324
player->onGround = true;
325
player->velocity.y = 0;
326
}
327
break;
328
329
case 2: {
330
self->playerAngles[player->playerID] = (self->playerAngles[player->playerID] + (player->groundVel >> 15)) & 0x3FF;
331
player->position.x = radius * RSDK.Cos1024(self->playerAngles[player->playerID]) + self->position.x;
332
333
if (self->hitboxL.top >= self->hitboxR.top)
334
player->position.y -= (player->groundVel >> 2) & 0xFFFFE000;
335
else
336
player->position.y += (player->groundVel >> 2) & 0xFFFFE000;
337
player->direction = FLIP_X;
338
339
int32 frame = 0;
340
if (player->groundVel <= 0) {
341
player->rotation = 0x80;
342
frame = 35 - 24 * self->playerAngles[player->playerID] / 0x400;
343
}
344
else {
345
player->rotation = 0x180;
346
frame = 24 * self->playerAngles[player->playerID] / 0x400;
347
}
348
349
if (player->velocity.y < -0x40000) {
350
self->playerStatus[player->playerID] = 0;
351
player->tileCollisions = TILECOLLISION_DOWN;
352
}
353
else {
354
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true, frame % 24);
355
player->animator.rotationStyle = ROTSTYLE_FULL;
356
player->onGround = true;
357
player->velocity.y = 0;
358
359
if (player->groundVel <= 0) {
360
if (player->groundVel >= -0x30000) {
361
self->playerStatus[player->playerID] = 0;
362
player->tileCollisions = TILECOLLISION_DOWN;
363
}
364
else {
365
if (self->hitboxL.top < self->hitboxR.top) {
366
int32 maxY = self->position.y - (playerHitbox->bottom << 16) - self->updateRange.y + 0x400000;
367
if (player->position.y <= maxY) {
368
player->position.y = maxY;
369
self->playerStatus[player->playerID] = 3;
370
player->tileCollisions = TILECOLLISION_DOWN;
371
}
372
}
373
else if (player->position.y >= self->updateRange.y - (playerHitbox->bottom << 16) + self->position.y) {
374
player->position.y = self->updateRange.y - (playerHitbox->bottom << 16) + self->position.y;
375
self->playerStatus[player->playerID] = 3;
376
player->tileCollisions = TILECOLLISION_DOWN;
377
}
378
}
379
}
380
else {
381
if (player->groundVel <= 0x30000) {
382
self->playerStatus[player->playerID] = 0;
383
player->tileCollisions = TILECOLLISION_DOWN;
384
}
385
else if (self->hitboxL.top >= self->hitboxR.top) {
386
int32 maxY = self->position.y - (playerHitbox->bottom << 16) - self->updateRange.y + 0x400000;
387
if (player->position.y <= maxY) {
388
player->position.y = maxY;
389
self->playerStatus[player->playerID] = 3;
390
player->tileCollisions = TILECOLLISION_DOWN;
391
}
392
}
393
else if (player->position.y >= self->updateRange.y - (playerHitbox->bottom << 16) + self->position.y) {
394
player->position.y = self->updateRange.y - (playerHitbox->bottom << 16) + self->position.y;
395
self->playerStatus[player->playerID] = 3;
396
player->tileCollisions = TILECOLLISION_DOWN;
397
}
398
}
399
}
400
break;
401
}
402
403
case 3: {
404
if (Player_CheckCollisionTouch(player, self, &self->hitboxRange)) {
405
if (abs(player->groundVel) <= 0x30000) {
406
self->playerStatus[player->playerID] = 0;
407
player->state = Player_State_Ground;
408
409
if (player->groundVel <= 0) {
410
if (player->groundVel < 0)
411
player->direction = FLIP_X;
412
}
413
else {
414
player->direction = FLIP_NONE;
415
}
416
}
417
else {
418
player->onGround = true;
419
player->velocity.y = 0;
420
421
if (player->groundVel >= 0) {
422
int32 distance = (player->position.x - self->position.x) >> 16;
423
int32 right = self->hitboxR.right - 48;
424
if (distance < right) {
425
player->rotation = 256;
426
player->direction = FLIP_X;
427
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true, 17 - 6 * distance / right);
428
player->animator.rotationStyle = ROTSTYLE_FULL;
429
}
430
}
431
else {
432
int32 distance = (self->position.x - player->position.x) >> 16;
433
int32 right = -48 - self->hitboxL.left;
434
if (distance < right) {
435
player->rotation = 256;
436
player->direction = FLIP_NONE;
437
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true, 17 - 6 * distance / right);
438
player->animator.rotationStyle = ROTSTYLE_FULL;
439
}
440
}
441
}
442
}
443
else {
444
self->playerStatus[player->playerID] = 0;
445
player->state = Player_State_Ground;
446
if (player->groundVel <= 0) {
447
if (player->groundVel < 0)
448
player->direction = FLIP_X;
449
}
450
else {
451
player->direction = FLIP_NONE;
452
}
453
}
454
break;
455
}
456
457
default: break;
458
}
459
}
460
}
461
462
void Cylinder_State_InkRoller(void)
463
{
464
RSDK_THIS(Cylinder);
465
466
foreach_active(Player, player)
467
{
468
Hitbox *playerHitbox = Player_GetHitbox(player);
469
int32 radius = (self->radius + playerHitbox->bottom) << 6;
470
471
if (self->playerStatus[player->playerID]) {
472
int32 angle = (self->playerAngles[player->playerID] + 8) & 0x3FF;
473
if (Player_CheckCollisionTouch(player, self, &self->hitboxRange) && !player->onGround) {
474
if ((player->position.y < self->position.y && player->velocity.y >= 0)
475
|| (player->position.y >= self->position.y && player->velocity.y <= 0)) {
476
477
bool32 collided = true;
478
if (player->state == Cylinder_PlayerState_InkRoller_Stand) {
479
int32 frame = (24 - (24 * angle) / 1024) % 24;
480
if (player->groundVel)
481
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true, frame);
482
else
483
RSDK.SetSpriteAnimation(player->aniFrames, ANI_STAND_CS, &player->animator, true, frame);
484
485
player->animator.rotationStyle = ROTSTYLE_FULL;
486
player->rotation = 0x100;
487
488
if (player->velocity.x)
489
player->direction = player->velocity.x > 0;
490
}
491
else {
492
if (player->state != Cylinder_PlayerState_InkRoller_Roll) {
493
collided = false;
494
}
495
else if (!player->velocity.x)
496
player->direction = player->velocity.x >> 31;
497
}
498
499
if (collided) {
500
player->drawGroup = angle >= 0x200 ? Zone->playerDrawGroup[1] : Zone->playerDrawGroup[0];
501
self->playerAngles[player->playerID] = angle;
502
player->position.y = radius * RSDK.Cos1024(angle) + self->position.y;
503
player->abilityValue = player->position.y < self->position.y ? 0 : 0x80;
504
player->onGround = true;
505
}
506
else {
507
self->playerStatus[player->playerID] = 0;
508
}
509
}
510
}
511
else {
512
if (player->state != Player_State_FlyToPlayer && player->state != Player_State_ReturnToPlayer
513
&& player->state != Player_State_HoldRespawn) {
514
if (player->onGround || player->velocity.y < 0 || player->state == Player_State_FlyCarried
515
|| player->animator.animationID == ANI_SKID) {
516
if (player->onGround) {
517
if (player->animator.animationID != ANI_JUMP)
518
player->direction ^= FLIP_X;
519
520
player->state = Player_State_Ground;
521
}
522
}
523
else {
524
player->state = Player_State_Air;
525
}
526
527
player->onGround = false;
528
}
529
530
self->playerStatus[player->playerID] = 0;
531
}
532
}
533
else {
534
if (Player_CheckCollisionTouch(player, self, &self->hitboxRange) && !player->onGround) {
535
if (
536
#if MANIA_USE_PLUS
537
player->state == Player_State_MightyHammerDrop ||
538
#endif
539
player->state == Player_State_BubbleBounce) {
540
player->onGround = true;
541
}
542
else if ((player->position.y < self->position.y && player->velocity.y >= 0)
543
|| (player->position.y >= self->position.y && player->velocity.y <= 0)) {
544
if (player->position.y >= self->position.y) {
545
player->position.y = self->position.y + (radius << 10);
546
self->playerAngles[player->playerID] = 0x000;
547
}
548
else {
549
player->position.y = self->position.y - (radius << 10);
550
self->playerAngles[player->playerID] = 0x200;
551
}
552
553
player->onGround = true;
554
player->velocity.y = 0;
555
self->playerStatus[player->playerID] = 1;
556
557
int32 frame = (ANI_STAND_CS - 24 * ((self->playerAngles[player->playerID] + 8) & 0x3FF) / 1024) % ANI_STAND_CS;
558
if (player->groundVel)
559
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true, frame);
560
else
561
RSDK.SetSpriteAnimation(player->aniFrames, ANI_STAND_CS, &player->animator, true, frame);
562
player->animator.rotationStyle = ROTSTYLE_FULL;
563
564
player->rotation = 0x100;
565
player->direction ^= FLIP_X;
566
player->nextAirState = StateMachine_None;
567
player->nextGroundState = StateMachine_None;
568
player->state = Cylinder_PlayerState_InkRoller_Stand;
569
}
570
}
571
}
572
}
573
}
574
575
void Cylinder_State_Pillar(void)
576
{
577
RSDK_THIS(Cylinder);
578
579
foreach_active(Player, player)
580
{
581
Hitbox *playerHitbox = Player_GetHitbox(player);
582
int32 top = self->position.y + (self->hitboxRange.top << 16);
583
int32 radius = (self->radius + playerHitbox->bottom) << 6;
584
585
if (self->playerStatus[player->playerID]) {
586
bool32 hasInput = false;
587
if (player->groundVel > 0) {
588
if (player->left)
589
hasInput = true;
590
}
591
else if (player->groundVel < 0) {
592
if (!player->right) {
593
if (player->left)
594
hasInput = true;
595
}
596
else if (player->right) {
597
hasInput = true;
598
}
599
}
600
601
if (Player_CheckCollisionTouch(player, self, &self->hitboxRange)) {
602
if (player->onGround) {
603
if (hasInput) {
604
if (player->velocity.y > 0x18000)
605
player->velocity.y = player->velocity.y - 0x2000;
606
607
if (player->velocity.y < 0x18000)
608
player->velocity.y = 0x18000;
609
}
610
else {
611
if (player->velocity.y < 0x38000)
612
player->velocity.y = player->velocity.y + 0x2000;
613
614
if (player->velocity.y > 0x38000)
615
player->velocity.y = 0x38000;
616
}
617
618
player->position.y += player->velocity.y;
619
620
int32 len = MIN(abs(player->position.y - top) >> 16, self->length);
621
int32 frame = 0;
622
623
int32 angle = ((len << 10) / 0xC0 + (((uint32)player->groundVel >> 22) & 0x200)) & 0x3FF;
624
if (player->groundVel <= 0) {
625
frame = (24 - 24 * angle / 0x400) % 24;
626
player->direction = FLIP_NONE;
627
player->rotation = 0x80;
628
}
629
else {
630
angle = 0x3FF - angle;
631
frame = (24 * angle / 0x400 + 12) % 24;
632
player->direction = FLIP_X;
633
player->rotation = 0x180;
634
}
635
636
player->position.x = radius * RSDK.Cos1024(angle) + self->position.x;
637
self->playerAngles[player->playerID] = angle;
638
player->drawGroup = angle >= 0x200 ? Zone->playerDrawGroup[1] : Zone->playerDrawGroup[0];
639
640
RSDK.SetSpriteAnimation(player->aniFrames, ANI_SPRING_CS, &player->animator, true, frame);
641
player->animator.rotationStyle = ROTSTYLE_FULL;
642
643
player->abilityValue = player->position.x < self->position.x ? 0 : 0x80;
644
player->onGround = true;
645
646
if (player->jumpPress) {
647
RSDK.PlaySfx(Player->sfxJump, false, 255);
648
player->velocity.x = player->position.x < self->position.x ? -0x60000 : 0x60000;
649
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
650
player->onGround = false;
651
}
652
}
653
}
654
else {
655
if (!player->onGround && player->state != Player_State_FlyCarried) {
656
player->state = Player_State_Air;
657
player->onGround = false;
658
player->tileCollisions = TILECOLLISION_DOWN;
659
}
660
else if (player->onGround) {
661
player->state = Player_State_Ground;
662
663
if (player->position.x >= self->position.x) {
664
player->angle = 64;
665
player->direction = FLIP_NONE;
666
if (hasInput || player->groundVel < player->velocity.y)
667
player->groundVel = player->velocity.y;
668
}
669
else {
670
player->angle = 192;
671
player->direction = FLIP_X;
672
if (hasInput || player->groundVel > -player->velocity.y)
673
player->groundVel = -player->velocity.y;
674
}
675
676
if (player->animator.animationID == ANI_SPRING_CS) {
677
if (abs(player->groundVel) < 0xC0000) {
678
if (abs(player->groundVel) < 0x60000) {
679
if (abs(player->groundVel) < 0x40000)
680
RSDK.SetSpriteAnimation(player->aniFrames, ANI_WALK, &player->animator, false, 0);
681
else
682
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JOG, &player->animator, false, 0);
683
}
684
else {
685
RSDK.SetSpriteAnimation(player->aniFrames, ANI_RUN, &player->animator, false, 1);
686
}
687
}
688
else {
689
RSDK.SetSpriteAnimation(player->aniFrames, ANI_DASH, &player->animator, false, 1);
690
}
691
}
692
693
player->onGround = true;
694
player->tileCollisions = TILECOLLISION_DOWN;
695
}
696
697
self->playerStatus[player->playerID] = 0;
698
}
699
}
700
else if (Player_CheckCollisionTouch(player, self, &self->hitboxRange) && player->onGround) {
701
if ((player->angle == 0x40 && player->groundVel > 0) || (player->angle == 0xC0 && player->groundVel < 0)) {
702
if (player->angle == 0x40 && player->direction == FLIP_X)
703
player->direction = FLIP_NONE;
704
705
if (player->angle == 0xC0 && player->direction == FLIP_NONE)
706
player->direction = FLIP_X;
707
708
if (player->position.x >= self->position.x) {
709
player->position.x = self->position.x + (radius << 10);
710
self->playerAngles[player->playerID] = 0;
711
}
712
else {
713
player->position.x = self->position.x - (radius << 10);
714
self->playerAngles[player->playerID] = 512;
715
}
716
717
player->onGround = true;
718
player->velocity.x = 0;
719
self->playerStatus[player->playerID] = 1;
720
player->nextAirState = 0;
721
player->nextGroundState = 0;
722
player->state = Cylinder_PlayerState_Pillar;
723
player->tileCollisions = TILECOLLISION_NONE;
724
725
if (abs(player->groundVel) > 0x18000) {
726
if (abs(player->groundVel) >= 0x38000)
727
player->velocity.y = 0x38000;
728
else if (player->groundVel >= 0)
729
player->velocity.y = player->groundVel;
730
else
731
player->velocity.y = -player->groundVel;
732
}
733
else {
734
player->velocity.y = 0x18000;
735
}
736
}
737
}
738
}
739
}
740
741
void Cylinder_PlayerState_InkRoller_Stand(void)
742
{
743
RSDK_THIS(Player);
744
745
Player_HandleGroundMovement();
746
747
self->skidding = 0;
748
if (self->camera)
749
self->camera->disableYOffset = false;
750
751
self->jumpAbilityState = 0;
752
753
if (self->jumpPress) {
754
Player_Action_Jump(self);
755
756
if (self->abilityValue == 128)
757
self->velocity.y = -self->velocity.y;
758
759
self->direction ^= FLIP_X;
760
self->timer = 0;
761
}
762
else {
763
if (abs(self->groundVel) >= 0x8800 && !self->left && !self->right && self->down) {
764
if (self->abilityValue == 128)
765
self->position.y -= self->jumpOffset;
766
else
767
self->position.y += self->jumpOffset;
768
769
RSDK.SetSpriteAnimation(self->aniFrames, ANI_JUMP, &self->animator, false, 0);
770
self->direction ^= FLIP_X;
771
self->state = Cylinder_PlayerState_InkRoller_Roll;
772
RSDK.PlaySfx(Player->sfxRoll, false, 255);
773
}
774
}
775
}
776
777
void Cylinder_PlayerState_InkRoller_Roll(void)
778
{
779
RSDK_THIS(Player);
780
781
int32 angle = self->angle;
782
self->angle = 0;
783
Player_HandleRollDeceleration();
784
785
if (self->state == Player_State_Ground) {
786
self->direction ^= FLIP_X;
787
self->state = Cylinder_PlayerState_InkRoller_Stand;
788
}
789
790
if (self->characterID == ID_TAILS)
791
self->animator.speed = 120;
792
else
793
self->animator.speed = ((abs(self->groundVel) * 0xF0) / 0x60000) + 0x30;
794
795
if (self->animator.speed > 0xF0)
796
self->animator.speed = 0xF0;
797
798
if (self->camera)
799
self->camera->disableYOffset = false;
800
801
self->jumpAbilityState = 0;
802
self->angle = angle;
803
804
if (self->jumpPress) {
805
Player_Action_Jump(self);
806
807
if (self->abilityValue == 128)
808
self->velocity.y = -self->velocity.y;
809
810
self->timer = 0;
811
}
812
}
813
814
void Cylinder_PlayerState_Pillar(void)
815
{
816
RSDK_THIS(Player);
817
818
if (self->onGround)
819
self->rotation = self->angle << 1;
820
}
821
822
void Cylinder_PlayerState_Spiral(void)
823
{
824
RSDK_THIS(Player);
825
826
self->down = false;
827
Player_State_Ground();
828
}
829
830
#if GAME_INCLUDE_EDITOR
831
void Cylinder_EditorDraw(void)
832
{
833
RSDK_THIS(Cylinder);
834
835
RSDK.DrawSprite(&Cylinder->animator, NULL, false);
836
837
switch (self->type) {
838
case CYLINDER_TUBE_H:
839
self->updateRange.x = self->length << 16;
840
self->updateRange.y = self->radius << 16;
841
842
self->hitboxRange.left = -self->length;
843
self->hitboxRange.top = -self->radius;
844
self->hitboxRange.right = self->length;
845
self->hitboxRange.bottom = self->radius;
846
break;
847
848
case CYLINDER_TUBE_V:
849
self->updateRange.x = self->radius << 16;
850
self->updateRange.y = self->length << 16;
851
852
self->hitboxRange.left = -self->radius;
853
self->hitboxRange.top = -self->length;
854
self->hitboxRange.right = self->radius;
855
self->hitboxRange.bottom = self->length;
856
break;
857
858
case CYLINDER_SPIRAL_LR:
859
self->updateRange.x = (self->radius + 112) << 16;
860
self->updateRange.y = self->length << 16;
861
862
self->hitboxRange.left = -64 - self->radius;
863
self->hitboxRange.right = self->radius + 64;
864
self->hitboxRange.top = -self->length;
865
self->hitboxRange.bottom = self->length;
866
867
self->hitboxL.left = -112 - self->radius;
868
self->hitboxL.right = -self->radius;
869
self->hitboxL.top = -self->length;
870
self->hitboxL.bottom = 64 - self->length;
871
872
self->hitboxR.left = self->radius;
873
self->hitboxR.top = self->length - 64;
874
self->hitboxR.right = self->length + 112;
875
self->hitboxR.bottom = self->length;
876
break;
877
878
case CYLINDER_SPIRAL_RL:
879
self->updateRange.x = (self->radius + 112) << 16;
880
self->updateRange.y = self->length << 16;
881
882
self->hitboxRange.left = -64 - self->radius;
883
self->hitboxRange.top = -self->length;
884
self->hitboxRange.right = self->radius + 64;
885
self->hitboxRange.bottom = self->length;
886
887
self->hitboxL.left = -112 - self->radius;
888
self->hitboxL.top = self->length - 64;
889
self->hitboxL.right = -self->radius;
890
self->hitboxL.bottom = self->length;
891
892
self->hitboxR.left = self->radius;
893
self->hitboxR.top = -self->length;
894
self->hitboxR.right = self->radius + 112;
895
self->hitboxR.bottom = 64 - self->length;
896
break;
897
898
case CYLINDER_INKROLLER:
899
self->updateRange.x = self->length << 16;
900
self->updateRange.y = self->radius << 16;
901
902
self->hitboxRange.left = 16 - self->length;
903
self->hitboxRange.top = ~self->radius;
904
self->hitboxRange.right = self->length - 16;
905
self->hitboxRange.bottom = self->radius + 1;
906
break;
907
908
case CYLINDER_PILLAR:
909
self->updateRange.x = self->radius << 17;
910
self->updateRange.y = self->length << 17;
911
912
self->hitboxRange.left = -16 - self->radius;
913
self->hitboxRange.top = -self->length;
914
self->hitboxRange.right = self->radius + 16;
915
self->hitboxRange.bottom = self->length;
916
break;
917
918
default: break;
919
}
920
921
if (showGizmos()) {
922
RSDK_DRAWING_OVERLAY(true);
923
924
DrawHelpers_DrawHitboxOutline(self->position.x, self->position.y, &self->hitboxRange, FLIP_NONE, 0xFFFF00);
925
926
if (self->type == CYLINDER_SPIRAL_LR || self->type == CYLINDER_SPIRAL_RL) {
927
DrawHelpers_DrawHitboxOutline(self->position.x, self->position.y, &self->hitboxL, FLIP_NONE, 0xFF0000);
928
DrawHelpers_DrawHitboxOutline(self->position.x, self->position.y, &self->hitboxR, FLIP_NONE, 0xFF0000);
929
}
930
931
RSDK_DRAWING_OVERLAY(false);
932
}
933
}
934
935
void Cylinder_EditorLoad(void)
936
{
937
Cylinder->aniFrames = RSDK.LoadSpriteAnimation("FBZ/Cylinder.bin", SCOPE_STAGE);
938
RSDK.SetSpriteAnimation(Cylinder->aniFrames, 0, &Cylinder->animator, true, 0);
939
940
RSDK_ACTIVE_VAR(Cylinder, type);
941
RSDK_ENUM_VAR("Tube H", CYLINDER_TUBE_H);
942
RSDK_ENUM_VAR("Tube V", CYLINDER_TUBE_V);
943
RSDK_ENUM_VAR("FBZ Spiral - LR", CYLINDER_SPIRAL_LR);
944
RSDK_ENUM_VAR("FBZ Spiral - RL", CYLINDER_SPIRAL_RL);
945
RSDK_ENUM_VAR("Ink Roller", CYLINDER_INKROLLER);
946
RSDK_ENUM_VAR("Fixed V - L (Unused)", CYLINDER_FIXED_V_L);
947
RSDK_ENUM_VAR("Fixed V - R (Unused)", CYLINDER_FIXED_V_R);
948
RSDK_ENUM_VAR("SSZ1 Pillar", CYLINDER_PILLAR);
949
}
950
#endif
951
952
void Cylinder_Serialize(void)
953
{
954
RSDK_EDITABLE_VAR(Cylinder, VAR_UINT8, type);
955
RSDK_EDITABLE_VAR(Cylinder, VAR_ENUM, length);
956
RSDK_EDITABLE_VAR(Cylinder, VAR_ENUM, radius);
957
}
958
959