Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/SSZ/Dango.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Dango Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectDango *Dango;
11
12
void Dango_Update(void)
13
{
14
RSDK_THIS(Dango);
15
16
StateMachine_Run(self->state);
17
18
if (self->rollDelay > 0)
19
self->rollDelay--;
20
}
21
22
void Dango_LateUpdate(void) {}
23
24
void Dango_StaticUpdate(void) {}
25
26
void Dango_Draw(void)
27
{
28
RSDK_THIS(Dango);
29
30
RSDK.DrawSprite(&self->animator, NULL, false);
31
}
32
33
void Dango_Create(void *data)
34
{
35
RSDK_THIS(Dango);
36
37
self->visible = true;
38
self->drawGroup = Zone->objectDrawGroup[0];
39
self->drawFX |= FX_FLIP;
40
self->startPos = self->position;
41
self->startDir = self->direction;
42
self->active = ACTIVE_BOUNDS;
43
self->updateRange.x = 0x800000;
44
self->updateRange.y = 0x800000;
45
46
RSDK.SetSpriteAnimation(Dango->aniFrames, 1, &self->animator, true, 0);
47
self->state = Dango_State_Init;
48
}
49
50
void Dango_StageLoad(void)
51
{
52
if (RSDK.CheckSceneFolder("SSZ1"))
53
Dango->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Dango.bin", SCOPE_STAGE);
54
else if (RSDK.CheckSceneFolder("SSZ2"))
55
Dango->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/Dango.bin", SCOPE_STAGE);
56
57
Dango->hitboxBadnik.top = -14;
58
Dango->hitboxBadnik.left = -14;
59
Dango->hitboxBadnik.right = 14;
60
Dango->hitboxBadnik.bottom = 14;
61
62
Dango->hitboxCurlRange.top = -128;
63
Dango->hitboxCurlRange.left = -112;
64
Dango->hitboxCurlRange.right = -18;
65
Dango->hitboxCurlRange.bottom = 128;
66
67
Dango->sfxBumper = RSDK.GetSfx("Stage/Bumper3.wav");
68
69
DEBUGMODE_ADD_OBJ(Dango);
70
}
71
72
void Dango_DebugSpawn(void)
73
{
74
RSDK_THIS(DebugMode);
75
76
EntityDango *dango = CREATE_ENTITY(Dango, NULL, self->position.x, self->position.y);
77
RSDK.SetSpriteAnimation(Dango->aniFrames, 2, &dango->animator, true, 0);
78
79
dango->state = Dango_State_Falling_Curled;
80
dango->groundVel = dango->direction == FLIP_NONE ? -0x20000 : 0x20000;
81
}
82
83
void Dango_DebugDraw(void)
84
{
85
RSDK.SetSpriteAnimation(Dango->aniFrames, 0, &DebugMode->animator, true, 0);
86
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
87
}
88
89
void Dango_CheckOffScreen(void)
90
{
91
RSDK_THIS(Dango);
92
93
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
94
self->position = self->startPos;
95
self->direction = self->startDir;
96
Dango_Create(NULL);
97
}
98
}
99
100
void Dango_CheckPlayerCollisions(void)
101
{
102
RSDK_THIS(Dango);
103
104
foreach_active(Player, player)
105
{
106
if (Player_CheckBadnikTouch(player, self, &Dango->hitboxBadnik)) {
107
int32 anim = player->animator.animationID;
108
109
bool32 bumpPlayer = anim == ANI_JUMP || anim == ANI_SPINDASH || anim == ANI_DROPDASH;
110
bumpPlayer &= self->state == Dango_State_Rolling;
111
#if MANIA_USE_PLUS
112
if (player->characterID == ID_MIGHTY)
113
bumpPlayer |= anim == ANI_CROUCH || player->jumpAbilityState > 1;
114
bumpPlayer &= player->state != Player_State_MightyHammerDrop;
115
#endif
116
117
if (bumpPlayer) {
118
if (anim != ANI_JUMP)
119
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
120
RSDK.PlaySfx(Dango->sfxBumper, false, 0xFF);
121
122
if (player->velocity.x <= 0) {
123
if (self->groundVel > player->velocity.x) {
124
if (self->groundVel > -0x20000)
125
self->groundVel = -0x20000;
126
}
127
}
128
else if (self->groundVel < player->velocity.x) {
129
self->groundVel = player->velocity.x;
130
if (self->groundVel < 0x20000)
131
self->groundVel = 0x20000;
132
}
133
134
self->velocity.x = self->groundVel;
135
136
#if MANIA_USE_PLUS
137
if (!(player->characterID == ID_MIGHTY && player->jumpAbilityState > 1)) {
138
#endif
139
player->groundVel = (player->position.x - self->position.x) >> 2;
140
player->velocity.x = player->groundVel;
141
player->velocity.y = (player->position.y - self->position.y) >> 2;
142
player->onGround = false;
143
#if MANIA_USE_PLUS
144
}
145
#endif
146
147
if ((self->position.x > player->position.x && self->velocity.x < 0)
148
|| (self->position.x < player->position.x && self->velocity.x > 0)) {
149
self->groundVel = -self->groundVel;
150
self->velocity.x = -self->velocity.x;
151
}
152
}
153
else {
154
Player_CheckBadnikBreak(player, self, true);
155
}
156
}
157
}
158
}
159
160
bool32 Dango_HandleMovement(StateMachine(nextState), uint8 anim)
161
{
162
RSDK_THIS(Dango);
163
164
bool32 changeState = false;
165
166
int32 storeX = self->position.x;
167
int32 storeY = self->position.y;
168
self->position.x += self->groundVel;
169
170
bool32 collidedWall = false;
171
if (self->groundVel <= 0)
172
collidedWall = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_RWALL, 0, Dango->hitboxBadnik.left << 16, 0, 4);
173
else
174
collidedWall = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_LWALL, 0, Dango->hitboxBadnik.right << 16, 0, 4);
175
176
if (RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xD0000, 2)) {
177
uint16 tile = RSDK.GetTile(Zone->fgLayer[0], self->position.x >> 16, (self->position.y + 0xD0000) >> 16);
178
self->angle = RSDK.GetTileAngle(tile, 0, 0);
179
180
if (self->groundVel <= 0) {
181
if (self->angle < 0x80 && self->angle > 0x10)
182
changeState = true;
183
else
184
self->velocity.x = (self->groundVel >> 8) * RSDK.Cos256(self->angle);
185
}
186
else {
187
if ((uint32)(self->angle - 0x81) <= 0x6E)
188
changeState = true;
189
else
190
self->velocity.x = (self->groundVel >> 8) * RSDK.Cos256(self->angle);
191
}
192
}
193
else {
194
changeState = true;
195
}
196
197
if (collidedWall)
198
changeState = true;
199
200
if (self->preventStateChange)
201
changeState = false;
202
203
if (changeState) {
204
self->position.x = storeX;
205
self->position.y = storeY;
206
RSDK.SetSpriteAnimation(Dango->aniFrames, anim, &self->animator, true, 0);
207
208
self->state = nextState;
209
self->preventStateChange = true;
210
}
211
212
return changeState;
213
}
214
215
void Dango_State_Init(void)
216
{
217
RSDK_THIS(Dango);
218
219
self->active = ACTIVE_NORMAL;
220
self->groundVel = self->direction == FLIP_NONE ? -0x6000 : 0x6000;
221
self->velocity.y = 0;
222
223
self->state = Dango_State_Walking;
224
Dango_State_Walking();
225
}
226
227
void Dango_State_Walking(void)
228
{
229
RSDK_THIS(Dango);
230
231
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xD0000, false)) {
232
RSDK.ProcessAnimation(&self->animator);
233
234
Dango_CheckPlayerCollisions();
235
Dango_CheckOffScreen();
236
237
if (!Dango_HandleMovement(Dango_State_Turning, 5) && self->rollDelay <= 0) {
238
foreach_active(Player, player)
239
{
240
if (Player_CheckCollisionTouch(player, self, &Dango->hitboxCurlRange)) {
241
RSDK.SetSpriteAnimation(Dango->aniFrames, 3, &self->animator, true, 0);
242
self->state = Dango_State_Curling;
243
}
244
}
245
}
246
}
247
else {
248
self->state = Dango_State_Falling_Uncurled;
249
Dango_State_Falling_Uncurled();
250
}
251
}
252
253
void Dango_State_Turning(void)
254
{
255
RSDK_THIS(Dango);
256
257
RSDK.ProcessAnimation(&self->animator);
258
259
if (self->animator.frameID == self->animator.frameCount - 1) {
260
RSDK.SetSpriteAnimation(Dango->aniFrames, 1, &self->animator, true, 0);
261
self->preventStateChange = false;
262
self->groundVel = -self->groundVel;
263
self->velocity.x = -self->velocity.x;
264
265
self->state = Dango_State_Walking;
266
self->direction ^= FLIP_X;
267
}
268
else {
269
Dango_CheckPlayerCollisions();
270
Dango_CheckOffScreen();
271
}
272
}
273
274
void Dango_State_Falling_Uncurled(void)
275
{
276
RSDK_THIS(Dango);
277
278
RSDK.ProcessAnimation(&self->animator);
279
280
self->position.x += self->groundVel;
281
self->position.y += self->velocity.y;
282
self->velocity.y += 0x3800;
283
284
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xD0000, true)) {
285
self->velocity.y = 0;
286
RSDK.SetSpriteAnimation(Dango->aniFrames, 1, &self->animator, true, 0);
287
288
self->state = Dango_State_Walking;
289
}
290
else {
291
Dango_CheckPlayerCollisions();
292
Dango_CheckOffScreen();
293
}
294
}
295
296
void Dango_State_Curling(void)
297
{
298
RSDK_THIS(Dango);
299
300
RSDK.ProcessAnimation(&self->animator);
301
if (self->animator.frameID == self->animator.frameCount - 1) {
302
RSDK.SetSpriteAnimation(Dango->aniFrames, 2, &self->animator, true, 0);
303
self->state = Dango_State_Rolling;
304
self->groundVel = self->direction == FLIP_NONE ? -0x20000 : 0x20000;
305
}
306
else {
307
Dango_CheckPlayerCollisions();
308
Dango_CheckOffScreen();
309
}
310
}
311
312
void Dango_State_Rolling(void)
313
{
314
RSDK_THIS(Dango);
315
316
RSDK.ProcessAnimation(&self->animator);
317
318
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xD0000, false)) {
319
Dango_CheckPlayerCollisions();
320
Dango_CheckOffScreen();
321
322
Dango_HandleMovement(Dango_State_Uncurling, 4);
323
}
324
else {
325
self->state = Dango_State_Falling_Curled;
326
Dango_State_Falling_Curled();
327
}
328
}
329
330
void Dango_State_Falling_Curled(void)
331
{
332
RSDK_THIS(Dango);
333
334
RSDK.ProcessAnimation(&self->animator);
335
336
self->position.x += self->groundVel;
337
self->position.y += self->velocity.y;
338
self->velocity.y += 0x3800;
339
340
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xD0000, true)) {
341
self->velocity.y = 0;
342
self->state = Dango_State_Rolling;
343
}
344
else {
345
Dango_CheckPlayerCollisions();
346
Dango_CheckOffScreen();
347
}
348
}
349
350
void Dango_State_Uncurling(void)
351
{
352
RSDK_THIS(Dango);
353
354
RSDK.ProcessAnimation(&self->animator);
355
356
if (self->animator.frameID == self->animator.frameCount - 1) {
357
RSDK.SetSpriteAnimation(Dango->aniFrames, 1, &self->animator, true, 0);
358
self->preventStateChange = false;
359
self->rollDelay = 30;
360
self->groundVel = self->direction == FLIP_NONE ? -0x6000 : 0x6000;
361
self->state = Dango_State_Walking;
362
}
363
else {
364
Dango_CheckPlayerCollisions();
365
Dango_CheckOffScreen();
366
}
367
}
368
369
#if MANIA_USE_PLUS
370
void Dango_StateTaunt_Setup(void)
371
{
372
RSDK_THIS(Dango);
373
374
if (++self->timer == 180) {
375
self->timer = 0;
376
self->groundVel = 0x60000;
377
self->state = Dango_StateTaunt_RollIn;
378
379
RSDK.SetSpriteAnimation(Dango->aniFrames, 2, &self->animator, true, 0);
380
}
381
}
382
383
void Dango_StateTaunt_RollIn(void)
384
{
385
RSDK_THIS(Dango);
386
387
RSDK.ProcessAnimation(&self->animator);
388
389
self->position.x += self->groundVel;
390
RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xE0000, 14);
391
392
foreach_active(PhantomRuby, ruby)
393
{
394
if (abs(self->position.x - ruby->position.x) < 0x120000) {
395
RSDK.PlaySfx(Dango->sfxBumper, false, 255);
396
self->state = Dango_StateTaunt_KnockedRuby;
397
ruby->state = PhantomRuby_State_MoveGravity;
398
ruby->velocity.x = self->groundVel;
399
ruby->velocity.y = -0x80000;
400
401
RSDK.SetSpriteAnimation(Dango->aniFrames, 4, &self->animator, true, 0);
402
}
403
}
404
}
405
406
void Dango_StateTaunt_KnockedRuby(void)
407
{
408
RSDK_THIS(Dango);
409
410
RSDK.ProcessAnimation(&self->animator);
411
412
self->groundVel -= self->groundVel >> 2;
413
self->position.x += self->groundVel;
414
415
if (self->groundVel < 0x8000) {
416
RSDK.SetSpriteAnimation(Dango->aniFrames, 6, &self->animator, true, 0);
417
self->state = Dango_StateTaunt_Taunting;
418
}
419
}
420
421
void Dango_StateTaunt_Taunting(void)
422
{
423
RSDK_THIS(Dango);
424
425
RSDK.ProcessAnimation(&self->animator);
426
427
if (self->animator.frameID == self->animator.frameCount - 1)
428
++self->timer;
429
430
if (self->timer == 32) {
431
RSDK.SetSpriteAnimation(Dango->aniFrames, 5, &self->animator, true, 0);
432
self->timer = 0;
433
self->state = Dango_StateTaunt_Turning;
434
}
435
}
436
437
void Dango_StateTaunt_Turning(void)
438
{
439
RSDK_THIS(Dango);
440
441
RSDK.ProcessAnimation(&self->animator);
442
443
if (self->animator.frameID == self->animator.frameCount - 1) {
444
RSDK.SetSpriteAnimation(Dango->aniFrames, 3, &self->animator, true, 0);
445
self->direction = FLIP_NONE;
446
self->state = Dango_StateTaunt_RollOut;
447
}
448
}
449
450
void Dango_StateTaunt_RollOut(void)
451
{
452
RSDK_THIS(Dango);
453
454
RSDK.ProcessAnimation(&self->animator);
455
456
if (self->animator.animationID == 3) {
457
if (self->animator.frameID == self->animator.frameCount - 1)
458
RSDK.SetSpriteAnimation(Dango->aniFrames, 2, &self->animator, true, 0);
459
}
460
else {
461
self->position.x -= 0x40000;
462
}
463
464
if (!RSDK.CheckOnScreen(self, NULL))
465
destroyEntity(self);
466
}
467
#endif
468
469
#if GAME_INCLUDE_EDITOR
470
void Dango_EditorDraw(void) { Dango_Draw(); }
471
472
void Dango_EditorLoad(void)
473
{
474
if (RSDK.CheckSceneFolder("SSZ1"))
475
Dango->aniFrames = RSDK.LoadSpriteAnimation("SSZ1/Dango.bin", SCOPE_STAGE);
476
else if (RSDK.CheckSceneFolder("SSZ2"))
477
Dango->aniFrames = RSDK.LoadSpriteAnimation("SSZ2/Dango.bin", SCOPE_STAGE);
478
}
479
#endif
480
481
void Dango_Serialize(void) {}
482
483