Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/Common/SpinBooster.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: SpinBooster Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectSpinBooster *SpinBooster;
11
12
void SpinBooster_Update(void)
13
{
14
RSDK_THIS(SpinBooster);
15
16
int32 negAngle = -self->angle & 0xFF;
17
18
foreach_active(Player, player)
19
{
20
int32 playerID = 1 << RSDK.GetEntitySlot(player);
21
22
Vector2 pivotPos = player->position;
23
Zone_RotateOnPivot(&pivotPos, &self->position, negAngle);
24
25
if (abs(pivotPos.x - self->position.x) < TO_FIXED(24) && abs(pivotPos.y - self->position.y) < self->size << 19) {
26
if (pivotPos.x >= self->position.x) {
27
if (!(playerID & self->activePlayers)) {
28
SpinBooster_HandleForceRoll(player);
29
self->activePlayers |= playerID;
30
}
31
}
32
else {
33
// Exit Tube
34
if ((playerID & self->activePlayers) && !self->forwardOnly) {
35
if (player->state == Player_State_TubeRoll || player->state == Player_State_TubeAirRoll) {
36
player->nextAirState = StateMachine_None;
37
player->nextGroundState = StateMachine_None;
38
39
if (!self->allowTubeInput)
40
player->controlLock = 0;
41
42
player->tileCollisions = TILECOLLISION_DOWN;
43
player->state = player->onGround ? Player_State_Roll : Player_State_Air;
44
}
45
}
46
47
self->activePlayers &= ~playerID;
48
}
49
}
50
else {
51
if (pivotPos.x >= self->position.x)
52
self->activePlayers |= playerID;
53
else
54
self->activePlayers &= ~playerID;
55
}
56
}
57
58
self->visible = DebugMode->debugActive;
59
}
60
61
void SpinBooster_LateUpdate(void) {}
62
63
void SpinBooster_StaticUpdate(void) {}
64
65
void SpinBooster_Draw(void) { SpinBooster_DrawSprites(); }
66
67
void SpinBooster_Create(void *data)
68
{
69
RSDK_THIS(SpinBooster);
70
71
RSDK.SetSpriteAnimation(SpinBooster->aniFrames, 0, &self->animator, true, 0);
72
self->drawFX |= FX_FLIP;
73
self->animator.frameID = 4;
74
self->activePlayers = 0;
75
76
if (SceneInfo->inEditor) {
77
if (!self->boostPower)
78
self->boostPower = 15;
79
}
80
else {
81
switch (self->direction) {
82
case FLIP_NONE: self->angle = 0x00; break;
83
case FLIP_X: self->angle = 0x40; break;
84
case FLIP_Y: self->angle = 0x80; break;
85
case FLIP_XY: self->angle = 0xC0; break;
86
}
87
88
self->active = ACTIVE_BOUNDS;
89
90
self->updateRange.x = self->size * abs(RSDK.Sin256(self->angle)) << 11;
91
self->updateRange.x += 0x200000;
92
93
self->updateRange.y = self->size * abs(RSDK.Cos256(self->angle)) << 11;
94
self->updateRange.y += 0x200000;
95
self->visible = false;
96
self->drawGroup = Zone->objectDrawGroup[0];
97
}
98
}
99
100
void SpinBooster_StageLoad(void) { SpinBooster->aniFrames = RSDK.LoadSpriteAnimation("Global/PlaneSwitch.bin", SCOPE_STAGE); }
101
102
int32 SpinBooster_GetRollDir(EntityPlayer *player)
103
{
104
RSDK_THIS(SpinBooster);
105
106
switch (self->direction) {
107
case FLIP_NONE:
108
if (self->autoGrip != 5) {
109
if ((self->autoGrip == 7 || self->autoGrip == 8) && player->up)
110
return CMODE_ROOF;
111
112
return CMODE_FLOOR;
113
}
114
115
if (player->down)
116
return CMODE_FLOOR;
117
118
if (player->up)
119
return CMODE_ROOF;
120
121
return !self->bias ? CMODE_FLOOR : CMODE_ROOF;
122
123
case FLIP_X:
124
if (self->autoGrip != 5) {
125
if (self->autoGrip == 7) {
126
if (!player->left)
127
return -1;
128
129
return CMODE_RWALL;
130
}
131
132
if (self->autoGrip == 6) {
133
if (!player->right)
134
return -1;
135
136
return CMODE_LWALL;
137
}
138
139
if (self->autoGrip != 8)
140
return -1;
141
142
if (!player->left) {
143
if (!player->right)
144
return -1;
145
146
return CMODE_LWALL;
147
}
148
else {
149
return CMODE_RWALL;
150
}
151
}
152
else {
153
if (player->left)
154
return CMODE_RWALL;
155
156
if (player->right)
157
return CMODE_LWALL;
158
159
return !self->bias ? CMODE_LWALL : CMODE_RWALL;
160
}
161
162
case FLIP_Y:
163
if (self->autoGrip != 5) {
164
if ((self->autoGrip == 6 || self->autoGrip == 8) && player->up)
165
return CMODE_ROOF;
166
167
return CMODE_FLOOR;
168
}
169
170
if (player->down)
171
return CMODE_FLOOR;
172
173
if (player->up)
174
return CMODE_ROOF;
175
176
return !self->bias ? CMODE_ROOF : CMODE_FLOOR;
177
178
case FLIP_XY:
179
if (self->autoGrip == 5) {
180
return !player->left ? CMODE_LWALL : CMODE_RWALL;
181
}
182
else if (self->autoGrip == 6) {
183
if (!player->left)
184
return -1;
185
186
return CMODE_RWALL;
187
}
188
else {
189
if (self->autoGrip == 7) {
190
if (!player->right)
191
return -1;
192
193
return CMODE_LWALL;
194
}
195
196
if (self->autoGrip != 8)
197
return -1;
198
199
if (!player->left) {
200
if (!player->right)
201
return -1;
202
203
return CMODE_LWALL;
204
}
205
else {
206
return CMODE_RWALL;
207
}
208
}
209
210
default: break;
211
}
212
213
return -1;
214
}
215
void SpinBooster_HandleRollDir(EntityPlayer *player)
216
{
217
RSDK_THIS(SpinBooster);
218
219
if (self->autoGrip) {
220
int8 cMode = self->autoGrip - 1;
221
if (self->autoGrip >= 5)
222
cMode = SpinBooster_GetRollDir(player);
223
224
if (cMode < 0) {
225
player->onGround = false;
226
return;
227
}
228
229
int32 offsetX = 0;
230
int32 offsetY = 0;
231
int32 plrAngle = 0;
232
int32 angle = 0;
233
234
switch (cMode) {
235
case CMODE_FLOOR:
236
plrAngle = 0x00;
237
angle = 0x40;
238
break;
239
240
case CMODE_LWALL:
241
plrAngle = -0x40;
242
angle = 0x00;
243
break;
244
245
case CMODE_ROOF:
246
plrAngle = -0x80;
247
angle = -0x40;
248
break;
249
250
case CMODE_RWALL:
251
plrAngle = 0x40;
252
angle = -0x80;
253
break;
254
255
default:
256
plrAngle = 0x00;
257
angle = 0x00;
258
break;
259
}
260
261
Hitbox *playerHitbox = Player_GetHitbox(player);
262
switch (cMode) {
263
case CMODE_FLOOR: offsetY = playerHitbox->bottom << 16; break;
264
case CMODE_LWALL: offsetX = playerHitbox->right << 16; break;
265
case CMODE_ROOF: offsetY = playerHitbox->top << 16; break;
266
case CMODE_RWALL: offsetX = playerHitbox->left << 16; break;
267
default: break;
268
}
269
270
player->position.x += RSDK.Cos256(angle) << 8;
271
player->position.y += RSDK.Sin256(angle) << 8;
272
RSDK.ObjectTileGrip(player, Zone->collisionLayers, cMode, 0, offsetX, offsetY, 1);
273
274
player->angle = plrAngle;
275
if (player->onGround) {
276
uint8 mode = 0;
277
switch (player->collisionMode) {
278
case CMODE_FLOOR: mode = CMODE_ROOF; break;
279
case CMODE_LWALL: mode = CMODE_RWALL; break;
280
case CMODE_ROOF: mode = CMODE_FLOOR; break;
281
case CMODE_RWALL: mode = CMODE_LWALL; break;
282
}
283
284
if (cMode == mode)
285
player->groundVel = -player->groundVel;
286
}
287
else {
288
switch (cMode) {
289
case CMODE_FLOOR: player->groundVel = player->velocity.x; break;
290
case CMODE_LWALL: player->groundVel = -player->velocity.y; break;
291
case CMODE_ROOF: player->groundVel = -player->velocity.x; break;
292
case CMODE_RWALL: player->groundVel = player->velocity.y; break;
293
default: break;
294
}
295
}
296
297
player->collisionMode = cMode;
298
player->onGround = true;
299
}
300
}
301
void SpinBooster_ApplyRollVelocity(EntityPlayer *player)
302
{
303
RSDK_THIS(SpinBooster);
304
305
if (player->onGround) {
306
int32 entAng = RSDK.Cos256(self->angle) + RSDK.Sin256(self->angle);
307
int32 plrAng = RSDK.Cos256(player->angle) - RSDK.Sin256(player->angle);
308
int32 power = (self->boostPower << 15) * ((plrAng > 0) - (plrAng < 0)) * ((entAng > 0) - (entAng < 0));
309
310
if (self->boostPower >= 0)
311
player->groundVel += power;
312
else
313
player->groundVel = power;
314
}
315
else {
316
int32 x = (0x80 * RSDK.Cos256(self->angle)) * self->boostPower;
317
int32 y = (-0x80 * RSDK.Sin256(self->angle)) * self->boostPower;
318
319
if (self->boostPower >= 0) {
320
player->velocity.x += x;
321
player->velocity.y += y;
322
}
323
else {
324
player->velocity.x = x;
325
player->velocity.y = y;
326
}
327
}
328
329
if (self->boostPower < 0 && !self->forwardOnly) {
330
if (player->state == Player_State_TubeRoll || player->state == Player_State_TubeAirRoll) {
331
player->nextAirState = StateMachine_None;
332
player->nextGroundState = StateMachine_None;
333
334
if (!self->allowTubeInput)
335
player->controlLock = 0;
336
337
player->tileCollisions = TILECOLLISION_DOWN;
338
player->state = player->onGround ? Player_State_Roll : Player_State_Air;
339
}
340
}
341
}
342
void SpinBooster_DrawArrow(int32 x1, int32 y1, int32 x2, int32 y2, uint32 color)
343
{
344
int32 angle = RSDK.ATan2(x1 - x2, y1 - y2);
345
346
RSDK.DrawLine(x1, y1, x2, y2, color, 0x7F, INK_ADD, false);
347
RSDK.DrawLine(x2, y2, x2 + (RSDK.Cos256(angle + 12) << 12), y2 + (RSDK.Sin256(angle + 12) << 12), color, 0x7F, INK_ADD, false);
348
RSDK.DrawLine(x2, y2, x2 + (RSDK.Cos256(angle - 12) << 12), y2 + (RSDK.Sin256(angle - 12) << 12), color, 0x7F, INK_ADD, false);
349
}
350
void SpinBooster_DrawSprites(void)
351
{
352
RSDK_THIS(SpinBooster);
353
354
Vector2 drawPos;
355
drawPos.x = self->position.x;
356
drawPos.y = self->position.y - (self->size << 19);
357
Zone_RotateOnPivot(&drawPos, &self->position, self->angle);
358
359
for (int32 i = 0; i < self->size; ++i) {
360
RSDK.DrawSprite(&self->animator, &drawPos, false);
361
drawPos.x += RSDK.Sin256(self->angle) << 12;
362
drawPos.y += RSDK.Cos256(self->angle) << 12;
363
}
364
365
if (SceneInfo->inEditor) {
366
uint8 negAngle = -self->angle & 0xFF;
367
int32 power = self->boostPower;
368
int32 x = self->position.x;
369
int32 y = self->position.y;
370
int32 clr = ((power >> 31) & 0xFE0001) + 0xFFFF;
371
if (!power)
372
power = 1;
373
374
int32 x2 = power * (RSDK.Cos256(negAngle) << 11) + self->position.x;
375
int32 y2 = power * (RSDK.Sin256(negAngle) << 11) + self->position.y;
376
SpinBooster_DrawArrow(x, y, x2, y2, clr);
377
378
switch (self->autoGrip) {
379
default: break;
380
case 1:
381
case 2:
382
case 3:
383
case 4: {
384
int8 angle = 0;
385
386
switch (self->autoGrip) {
387
default: break;
388
case 1: angle = 0x40; break;
389
case 2: angle = 0x00; break;
390
case 3: angle = 0xC0; break;
391
case 4: angle = 0x80; break;
392
}
393
394
x2 = (RSDK.Cos256(angle) << 14) + self->position.x;
395
y2 = (RSDK.Sin256(angle) << 14) + self->position.y;
396
SpinBooster_DrawArrow(x, y, x2, y2, 0x00FF00);
397
break;
398
}
399
400
case 5:
401
clr = !self->bias ? 0x00FF00 : 0xFFFF00;
402
403
x2 = (RSDK.Cos256((negAngle + 64) & 0xFF) << 14) + self->position.x;
404
y2 = (RSDK.Sin256((negAngle + 64) & 0xFF) << 14) + self->position.y;
405
SpinBooster_DrawArrow(x, y, x2, y2, clr);
406
407
x2 = (RSDK.Cos256((negAngle - 64) & 0xFF) << 14) + self->position.x;
408
y2 = (RSDK.Sin256((negAngle - 64) & 0xFF) << 14) + self->position.y;
409
SpinBooster_DrawArrow(x, y, x2, y2, clr);
410
break;
411
412
case 6:
413
clr = 0xFFFF00;
414
415
x2 = (RSDK.Cos256((negAngle + 64) & 0xFF) << 14) + self->position.x;
416
y2 = (RSDK.Sin256((negAngle + 64) & 0xFF) << 14) + self->position.y;
417
SpinBooster_DrawArrow(x, y, x2, y2, clr);
418
419
x2 = (RSDK.Cos256(negAngle) << 14) + self->position.x;
420
y2 = (RSDK.Sin256(negAngle) << 14) + self->position.y;
421
SpinBooster_DrawArrow(x, y, x2, y2, 0x00FF00);
422
break;
423
424
case 0:
425
case 7:
426
clr = 0xFFFF00;
427
428
x2 = (RSDK.Cos256((negAngle - 64) & 0xFF) << 14) + self->position.x;
429
y2 = (RSDK.Sin256((negAngle - 64) & 0xFF) << 14) + self->position.y;
430
SpinBooster_DrawArrow(x, y, x2, y2, clr);
431
432
x2 = (RSDK.Cos256(negAngle) << 14) + self->position.x;
433
y2 = (RSDK.Sin256(negAngle) << 14) + self->position.y;
434
SpinBooster_DrawArrow(x, y, x2, y2, 0x00FF00);
435
break;
436
437
case 8:
438
clr = 0xFFFF00;
439
440
x2 = (RSDK.Cos256((negAngle + 64) & 0xFF) << 14) + self->position.x;
441
y2 = (RSDK.Sin256((negAngle + 64) & 0xFF) << 14) + self->position.y;
442
SpinBooster_DrawArrow(x, y, x2, y2, clr);
443
444
x2 = (RSDK.Cos256((negAngle - 64) & 0xFF) << 14) + self->position.x;
445
y2 = (RSDK.Sin256((negAngle - 64) & 0xFF) << 14) + self->position.y;
446
SpinBooster_DrawArrow(x, y, x2, y2, clr);
447
448
x2 = (RSDK.Cos256(negAngle) << 14) + self->position.x;
449
y2 = (RSDK.Sin256(negAngle) << 14) + self->position.y;
450
SpinBooster_DrawArrow(x, y, x2, y2, 0x00FF00);
451
break;
452
}
453
}
454
}
455
void SpinBooster_HandleForceRoll(EntityPlayer *player)
456
{
457
RSDK_THIS(SpinBooster);
458
459
player->tileCollisions = TILECOLLISION_DOWN;
460
SpinBooster_HandleRollDir(player);
461
462
if (player->state == Player_State_TubeRoll || player->state == Player_State_TubeAirRoll) {
463
if (self->boostAlways)
464
SpinBooster_ApplyRollVelocity(player);
465
}
466
else {
467
if (self->playSound)
468
RSDK.PlaySfx(Player->sfxRoll, false, 0xFF);
469
470
if (player->animator.animationID != ANI_JUMP) {
471
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
472
if (!player->collisionMode && player->onGround)
473
player->position.y += player->jumpOffset;
474
player->pushing = false;
475
}
476
477
player->nextAirState = StateMachine_None;
478
player->nextGroundState = StateMachine_None;
479
480
if (!self->allowTubeInput)
481
player->controlLock = 0xFFFF;
482
483
player->state = player->onGround ? Player_State_TubeRoll : Player_State_TubeAirRoll;
484
485
if (abs(player->groundVel) < TO_FIXED(1))
486
player->groundVel = (self->direction & FLIP_X) ? -TO_FIXED(4) : TO_FIXED(4);
487
488
SpinBooster_ApplyRollVelocity(player);
489
}
490
}
491
492
#if GAME_INCLUDE_EDITOR
493
void SpinBooster_EditorDraw(void) { SpinBooster_DrawSprites(); }
494
495
void SpinBooster_EditorLoad(void)
496
{
497
SpinBooster->aniFrames = RSDK.LoadSpriteAnimation("Global/PlaneSwitch.bin", SCOPE_STAGE);
498
499
RSDK_ACTIVE_VAR(SpinBooster, direction);
500
RSDK_ENUM_VAR("No Flip", FLIP_NONE);
501
RSDK_ENUM_VAR("Flip X", FLIP_X);
502
RSDK_ENUM_VAR("Flip Y", FLIP_Y);
503
RSDK_ENUM_VAR("Flip XY", FLIP_XY);
504
505
RSDK_ACTIVE_VAR(SpinBooster, bias);
506
RSDK_ENUM_VAR("No Bias", false);
507
RSDK_ENUM_VAR("Has Bias", true);
508
}
509
#endif
510
511
void SpinBooster_Serialize(void)
512
{
513
RSDK_EDITABLE_VAR(SpinBooster, VAR_UINT8, direction);
514
RSDK_EDITABLE_VAR(SpinBooster, VAR_UINT8, autoGrip);
515
RSDK_EDITABLE_VAR(SpinBooster, VAR_UINT8, bias);
516
RSDK_EDITABLE_VAR(SpinBooster, VAR_ENUM, size);
517
RSDK_EDITABLE_VAR(SpinBooster, VAR_INT32, boostPower);
518
RSDK_EDITABLE_VAR(SpinBooster, VAR_BOOL, boostAlways);
519
RSDK_EDITABLE_VAR(SpinBooster, VAR_BOOL, forwardOnly);
520
RSDK_EDITABLE_VAR(SpinBooster, VAR_BOOL, playSound);
521
RSDK_EDITABLE_VAR(SpinBooster, VAR_BOOL, allowTubeInput);
522
}
523
524