Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/TMZ/TurboTurtle.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: TurboTurtle Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectTurboTurtle *TurboTurtle;
11
12
void TurboTurtle_Update(void)
13
{
14
RSDK_THIS(TurboTurtle);
15
16
RSDK.ProcessAnimation(&self->animator);
17
18
if (self->animator.animationID == 1) {
19
if (!self->animator.frameID && self->animator.timer == 1)
20
RSDK.PlaySfx(TurboTurtle->sfxWalk, false, 255);
21
22
if (self->animator.frameID == 5 && self->animator.timer == 1)
23
RSDK.PlaySfx(TurboTurtle->sfxWalk2, false, 255);
24
}
25
26
self->fanActiveTop = false;
27
self->leftFanActive = false;
28
self->rightFanActive = false;
29
30
StateMachine_Run(self->state);
31
32
TurboTurtle_CheckPlayerCollisions();
33
34
if (self->state != TurboTurtle_State_Init) {
35
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
36
self->direction = self->startDir;
37
self->position = self->startPos;
38
TurboTurtle_Create(NULL);
39
}
40
}
41
}
42
43
void TurboTurtle_LateUpdate(void) {}
44
45
void TurboTurtle_StaticUpdate(void) {}
46
47
void TurboTurtle_Draw(void)
48
{
49
RSDK_THIS(TurboTurtle);
50
51
RSDK.DrawSprite(&self->animator, NULL, false);
52
}
53
54
void TurboTurtle_Create(void *data)
55
{
56
RSDK_THIS(TurboTurtle);
57
58
self->visible = true;
59
self->drawGroup = Zone->objectDrawGroup[0];
60
self->startPos = self->position;
61
self->startDir = self->direction;
62
self->drawFX = FX_FLIP;
63
self->active = ACTIVE_BOUNDS;
64
self->updateRange.x = 0x800000;
65
self->updateRange.y = 0x800000;
66
67
self->updateRange.x = abs(0x70000 * (self->stepCount * (2 * (self->initialSide == 0) - 1) + self->startPos.x - self->startPos.x)) + 0x800000;
68
69
if (!self->leftFanDuration)
70
self->leftFanDuration = 60;
71
72
if (!self->rightFanDuration)
73
self->rightFanDuration = 60;
74
75
if (!self->leftFanLength)
76
self->leftFanLength = 128;
77
78
if (!self->rightFanLength)
79
self->rightFanLength = 128;
80
81
if (!self->leftFanStrength)
82
self->leftFanStrength = 18;
83
84
if (!self->rightFanStrength)
85
self->rightFanStrength = 18;
86
87
self->hitboxFanT.left = -24;
88
self->hitboxFanT.top = -19;
89
self->hitboxFanT.right = 24;
90
self->hitboxFanT.bottom = -19;
91
92
self->hitboxFanR.left = -19;
93
self->hitboxFanR.top = -24;
94
self->hitboxFanR.right = 19;
95
self->hitboxFanR.bottom = 24;
96
97
self->hitboxFanL.left = -20;
98
self->hitboxFanL.top = -24;
99
self->hitboxFanL.right = -20;
100
self->hitboxFanL.bottom = 24;
101
102
self->state = TurboTurtle_State_Init;
103
}
104
105
void TurboTurtle_StageLoad(void)
106
{
107
TurboTurtle->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/TurboTurtle.bin", SCOPE_STAGE);
108
109
TurboTurtle->hitboxBadnik.left = -13;
110
TurboTurtle->hitboxBadnik.top = -12;
111
TurboTurtle->hitboxBadnik.right = 13;
112
TurboTurtle->hitboxBadnik.bottom = 16;
113
114
DEBUGMODE_ADD_OBJ(TurboTurtle);
115
116
TurboTurtle->sfxWalk = RSDK.GetSfx("TMZ1/TurtleWalk.wav");
117
TurboTurtle->sfxWalk2 = RSDK.GetSfx("TMZ1/TurtleWalk2.wav");
118
119
Soundboard_LoadSfx("HCZ/SmallFan.wav", 37404, TurboTurtle_SfxCheck_SmallFan, StateMachine_None);
120
}
121
122
void TurboTurtle_DebugSpawn(void)
123
{
124
RSDK_THIS(DebugMode);
125
126
EntityTurboTurtle *turboTurtle = CREATE_ENTITY(TurboTurtle, NULL, self->position.x, self->position.y);
127
turboTurtle->direction = self->direction;
128
turboTurtle->startDir = self->direction;
129
}
130
131
void TurboTurtle_DebugDraw(void)
132
{
133
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 0, &DebugMode->animator, true, 0);
134
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
135
}
136
137
void TurboTurtle_CheckPlayerCollisions(void)
138
{
139
RSDK_THIS(TurboTurtle);
140
141
foreach_active(Player, player)
142
{
143
if (Player_CheckBadnikTouch(player, self, &TurboTurtle->hitboxBadnik))
144
Player_CheckBadnikBreak(player, self, true);
145
}
146
}
147
148
void TurboTurtle_SetupState(void)
149
{
150
RSDK_THIS(TurboTurtle);
151
152
int32 dir = self->currentSide ? self->rightFanDir : self->leftFanDir;
153
self->timer = 0;
154
155
switch (dir) {
156
case TURBOTURTLE_FANDIR_TOP:
157
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 2, &self->animator, true, 0);
158
self->state = TurboTurtle_State_FanTop;
159
break;
160
161
case TURBOTURTLE_FANDIR_RIGHT:
162
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 4, &self->animator, true, 0);
163
self->direction = FLIP_NONE;
164
self->state = TurboTurtle_State_TurnFanRight;
165
break;
166
167
case TURBOTURTLE_FANDIR_LEFT:
168
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 4, &self->animator, true, 0);
169
self->direction = FLIP_X;
170
self->state = TurboTurtle_State_TurnFanLeft;
171
break;
172
}
173
}
174
175
void TurboTurtle_HandleFans(void)
176
{
177
RSDK_THIS(TurboTurtle);
178
179
int32 storeDir = self->direction;
180
self->direction = FLIP_NONE;
181
182
int32 strength = self->currentSide ? self->rightFanStrength : self->leftFanStrength;
183
184
int32 length = self->currentSide ? self->rightFanLength : self->leftFanLength;
185
186
if (self->fanActiveTop) {
187
length += RSDK.Sin256(2 * Zone->timer) >> 5;
188
self->hitboxFanT.top = self->hitboxFanT.bottom - length;
189
190
foreach_active(Player, player)
191
{
192
if (Player_CheckCollisionTouch(player, self, &self->hitboxFanT)) {
193
int32 anim = player->animator.animationID;
194
if (anim != ANI_CLING && anim != ANI_SHAFT_SWING) {
195
if (!player->onGround) {
196
player->velocity.y -= player->gravityStrength;
197
if (player->velocity.y > 0)
198
player->velocity.y -= (player->velocity.y >> 3);
199
}
200
201
int32 thisY = self->position.y;
202
int32 bottom = thisY + (self->hitboxFanT.bottom << 16);
203
int32 top = (self->hitboxFanT.top << 16) + thisY;
204
if (player->position.y > top)
205
top = player->position.y;
206
207
player->position.y -= ((strength * (((length << 16) - bottom + top != 0 ? (length << 16) - bottom + top : 0) / length)) >> 1);
208
}
209
}
210
}
211
212
TurboTurtle_HandleFanParticles(TURBOTURTLE_FANDIR_TOP, strength, length << 16);
213
}
214
215
if (self->leftFanActive) {
216
self->hitboxFanL.left = self->hitboxFanL.right - length;
217
218
foreach_active(Player, player)
219
{
220
if (Player_CheckCollisionTouch(player, self, &self->hitboxFanL)) {
221
int32 anim = player->animator.animationID;
222
if (anim != ANI_CLING && anim != ANI_SHAFT_SWING) {
223
int32 left = (self->hitboxFanL.left << 16) + self->position.x;
224
if (player->position.x > left)
225
left = player->position.x;
226
227
int32 pos = (length << 16) - (self->position.x + (self->hitboxFanL.right << 16)) + left;
228
player->position.x -= (strength * ((pos & -(pos != 0)) / length)) >> 1;
229
}
230
}
231
}
232
233
TurboTurtle_HandleFanParticles(TURBOTURTLE_FANDIR_LEFT, strength, length << 16);
234
}
235
236
if (self->rightFanActive) {
237
self->hitboxFanR.right = length + self->hitboxFanR.left;
238
239
foreach_active(Player, player)
240
{
241
if (Player_CheckCollisionTouch(player, self, &self->hitboxFanR)) {
242
int32 anim = player->animator.animationID;
243
if (anim != ANI_CLING && anim != ANI_SHAFT_SWING) {
244
int32 right = (self->hitboxFanR.right << 16) + self->position.x;
245
if (player->position.x < right)
246
right = player->position.x;
247
248
int32 pos = self->position.x + (self->hitboxFanR.left << 16);
249
player->position.x += (strength * ((((length << 16) - right + pos != 0) ? (length << 16) - right + pos : 0) / length)) >> 1;
250
}
251
}
252
}
253
254
TurboTurtle_HandleFanParticles(TURBOTURTLE_FANDIR_RIGHT, strength, length << 16);
255
}
256
257
self->direction = storeDir;
258
}
259
260
void TurboTurtle_HandleFanParticles(uint8 type, int32 strength, int32 length)
261
{
262
RSDK_THIS(TurboTurtle);
263
264
if (!(Zone->timer % 3)) {
265
for (int32 i = 0; i < RSDK.Rand(1, 2); ++i) {
266
int32 timer = 0;
267
int32 anim = (RSDK.Rand(0, 10) > 7) + 6;
268
int32 frame = RSDK.Rand(0, 3);
269
270
int32 spawnX = 0, spawnY = 0;
271
int32 velX = 0, velY = 0;
272
273
switch (type) {
274
case TURBOTURTLE_FANDIR_TOP:
275
spawnY = self->position.y + (self->hitboxFanT.bottom << 16);
276
spawnX = (RSDK.Rand(-13, 13) << 16) + self->position.x;
277
velX = (spawnX - self->position.x) >> 7;
278
RSDK.Rand(0, 4);
279
velY = -0x8000 * strength;
280
timer = length / abs(-0x8000 * strength);
281
break;
282
283
case TURBOTURTLE_FANDIR_RIGHT:
284
spawnX = self->position.x + (self->hitboxFanR.left << 16);
285
spawnY = (RSDK.Rand(-13, 13) << 16) + self->position.y;
286
RSDK.Rand(0, 4);
287
velX = strength << 15;
288
velY = (spawnY - self->position.y) >> 7;
289
timer = length / abs(strength << 15);
290
break;
291
292
case TURBOTURTLE_FANDIR_LEFT:
293
spawnX = self->position.x - (self->hitboxFanR.left << 16);
294
spawnY = (RSDK.Rand(-13, 13) << 16) + self->position.y;
295
RSDK.Rand(0, 4);
296
velX = -0x8000 * strength;
297
velY = (spawnY - self->position.y) >> 7;
298
timer = length / abs(-0x8000 * strength);
299
break;
300
default: break;
301
}
302
303
timer += RSDK.Rand(-5, 5);
304
305
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, spawnX, spawnY);
306
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, anim, &debris->animator, true, frame);
307
debris->velocity.x = velX;
308
debris->velocity.y = velY;
309
debris->drawGroup = Zone->objectDrawGroup[0] - 1;
310
debris->timer = timer;
311
}
312
}
313
}
314
315
bool32 TurboTurtle_SfxCheck_SmallFan(void)
316
{
317
int32 count = 0;
318
319
foreach_all(TurboTurtle, turtle)
320
{
321
if (turtle->state == TurboTurtle_State_FanTop || turtle->state == TurboTurtle_State_FanRight || turtle->state == TurboTurtle_State_FanLeft)
322
++count;
323
}
324
325
return count > 0;
326
}
327
328
void TurboTurtle_State_Init(void)
329
{
330
RSDK_THIS(TurboTurtle);
331
332
self->active = ACTIVE_NORMAL;
333
334
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 0, &self->animator, true, 0);
335
self->direction = self->startDir;
336
self->position = self->startPos;
337
self->currentSide = self->initialSide;
338
339
TurboTurtle_SetupState();
340
}
341
342
void TurboTurtle_State_Walking(void)
343
{
344
RSDK_THIS(TurboTurtle);
345
346
int32 offsets[] = { 0, 0, 0, 0, 1, 1, 0, 0 };
347
348
self->position.x += (2 * (self->currentSide == 1) - 1) * (offsets[self->animator.frameID] << 16);
349
if (!RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, 2)) {
350
self->stepTimer = 0;
351
TurboTurtle_SetupState();
352
}
353
else if (self->animator.frameID == self->animator.frameCount - 1) {
354
if (self->animator.timer == self->animator.frameDuration) {
355
if (self->stepTimer < self->stepCount) {
356
self->stepTimer++;
357
}
358
else {
359
self->stepTimer = 0;
360
TurboTurtle_SetupState();
361
}
362
}
363
}
364
}
365
366
void TurboTurtle_State_TurnFanUp(void)
367
{
368
RSDK_THIS(TurboTurtle);
369
370
if (self->animator.animationID == 5) {
371
if (self->animator.frameID == self->animator.frameCount - 1) {
372
uint8 dir = self->currentSide != FLIP_NONE;
373
self->currentSide = !self->currentSide;
374
self->direction = dir;
375
self->stepTimer = 0;
376
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 1, &self->animator, true, 0);
377
self->state = TurboTurtle_State_Walking;
378
}
379
}
380
}
381
382
void TurboTurtle_State_FanTop(void)
383
{
384
RSDK_THIS(TurboTurtle);
385
386
int32 duration = self->currentSide ? self->rightFanDuration : self->leftFanDuration;
387
388
if (self->stationary || self->timer < duration) {
389
self->fanActiveTop = true;
390
TurboTurtle_HandleFans();
391
392
if (!self->stationary)
393
++self->timer;
394
}
395
else {
396
uint8 dir = self->currentSide != 0;
397
self->currentSide = !self->currentSide;
398
self->direction = dir;
399
self->stepTimer = 0;
400
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 1, &self->animator, true, 0);
401
self->state = TurboTurtle_State_Walking;
402
}
403
}
404
405
void TurboTurtle_State_TurnFanRight(void)
406
{
407
RSDK_THIS(TurboTurtle);
408
409
if (self->animator.animationID == 4) {
410
if (self->animator.frameID == self->animator.frameCount - 1) {
411
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 3, &self->animator, true, 0);
412
self->state = TurboTurtle_State_FanRight;
413
}
414
}
415
}
416
417
void TurboTurtle_State_FanRight(void)
418
{
419
RSDK_THIS(TurboTurtle);
420
421
int32 duration = self->currentSide ? self->rightFanDuration : self->leftFanDuration;
422
423
if (self->stationary || self->timer < duration) {
424
self->rightFanActive = true;
425
TurboTurtle_HandleFans();
426
427
if (!self->stationary)
428
++self->timer;
429
}
430
else {
431
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 5, &self->animator, true, 0);
432
self->state = TurboTurtle_State_TurnFanUp;
433
}
434
}
435
436
void TurboTurtle_State_TurnFanLeft(void)
437
{
438
RSDK_THIS(TurboTurtle);
439
440
if (self->animator.animationID == 4) {
441
if (self->animator.frameID == self->animator.frameCount - 1) {
442
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 3, &self->animator, true, 0);
443
self->state = TurboTurtle_State_FanLeft;
444
}
445
}
446
}
447
448
void TurboTurtle_State_FanLeft(void)
449
{
450
RSDK_THIS(TurboTurtle);
451
452
int32 duration = self->currentSide ? self->rightFanDuration : self->leftFanDuration;
453
454
if (self->stationary || self->timer < duration) {
455
self->leftFanActive = true;
456
TurboTurtle_HandleFans();
457
458
if (!self->stationary)
459
++self->timer;
460
}
461
else {
462
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 5, &self->animator, true, 0);
463
self->state = TurboTurtle_State_TurnFanUp;
464
}
465
}
466
467
#if GAME_INCLUDE_EDITOR
468
void TurboTurtle_EditorDraw(void)
469
{
470
RSDK_THIS(TurboTurtle);
471
472
self->visible = true;
473
self->drawGroup = Zone->objectDrawGroup[0];
474
self->startPos = self->position;
475
self->direction = self->initialSide ^ FLIP_X;
476
self->startDir = self->direction;
477
478
self->updateRange.x = abs(0x70000 * (self->stepCount * (2 * (self->initialSide == 0) - 1) + self->startPos.x - self->startPos.x)) + 0x800000;
479
480
RSDK.SetSpriteAnimation(TurboTurtle->aniFrames, 0, &self->animator, true, 0);
481
self->direction = self->startDir;
482
483
TurboTurtle_Draw();
484
}
485
486
void TurboTurtle_EditorLoad(void)
487
{
488
TurboTurtle->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/TurboTurtle.bin", SCOPE_STAGE);
489
490
RSDK_ACTIVE_VAR(TurboTurtle, initialSide);
491
RSDK_ENUM_VAR("Left", FLIP_NONE);
492
RSDK_ENUM_VAR("Right", FLIP_X);
493
494
RSDK_ACTIVE_VAR(TurboTurtle, leftFanDir);
495
RSDK_ENUM_VAR("Top", TURBOTURTLE_FANDIR_TOP);
496
RSDK_ENUM_VAR("Right", TURBOTURTLE_FANDIR_RIGHT);
497
RSDK_ENUM_VAR("Left", TURBOTURTLE_FANDIR_LEFT);
498
499
RSDK_ACTIVE_VAR(TurboTurtle, rightFanDir);
500
RSDK_ENUM_VAR("Top", TURBOTURTLE_FANDIR_TOP);
501
RSDK_ENUM_VAR("Right", TURBOTURTLE_FANDIR_RIGHT);
502
RSDK_ENUM_VAR("Left", TURBOTURTLE_FANDIR_LEFT);
503
}
504
#endif
505
506
void TurboTurtle_Serialize(void)
507
{
508
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT16, stepCount);
509
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT8, initialSide);
510
RSDK_EDITABLE_VAR(TurboTurtle, VAR_BOOL, stationary);
511
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT8, leftFanDir);
512
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, leftFanDuration);
513
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, leftFanStrength);
514
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, leftFanLength);
515
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT8, rightFanDir);
516
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, rightFanDuration);
517
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, rightFanStrength);
518
RSDK_EDITABLE_VAR(TurboTurtle, VAR_UINT32, rightFanLength);
519
}
520
521