Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/FBZ/Crane.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Crane Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectCrane *Crane;
11
12
void Crane_Update(void)
13
{
14
RSDK_THIS(Crane);
15
16
StateMachine_Run(self->state);
17
18
RSDK.ProcessAnimation(&self->frontAnimator);
19
RSDK.ProcessAnimation(&self->backAnimator);
20
}
21
22
void Crane_LateUpdate(void) {}
23
24
void Crane_StaticUpdate(void)
25
{
26
foreach_active(Crane, crane) { RSDK.AddDrawListRef(Zone->playerDrawGroup[0] + 1, RSDK.GetEntitySlot(crane)); }
27
}
28
29
void Crane_Draw(void)
30
{
31
RSDK_THIS(Crane);
32
33
if (SceneInfo->currentDrawGroup == self->drawGroup) {
34
SpriteFrame *frame = RSDK.GetFrame(Crane->aniFrames, 4, 0);
35
int32 height = (self->position.y - self->startPos.y) >> 16;
36
frame->sprY = 230 - height;
37
frame->height = height;
38
frame->pivotY = -16 - height;
39
RSDK.DrawSprite(&self->chainAnimator, NULL, false);
40
RSDK.DrawSprite(&self->backAnimator, NULL, false);
41
}
42
else {
43
RSDK.DrawSprite(&self->frontAnimator, NULL, false);
44
}
45
}
46
47
void Crane_Create(void *data)
48
{
49
RSDK_THIS(Crane);
50
51
self->visible = true;
52
self->drawGroup = Zone->objectDrawGroup[0];
53
self->startPos = self->position;
54
self->startDir = self->direction;
55
self->active = ACTIVE_BOUNDS;
56
self->updateRange.x = 0x800000;
57
self->updateRange.y = 0x800000;
58
self->drawFX = FX_FLIP;
59
60
// Frame 3???? that doesn't exist
61
// Note: it *does* for anim 0 & 1 though, likely where the cause stems from
62
RSDK.SetSpriteAnimation(Crane->aniFrames, 2, &self->frontAnimator, true, 3);
63
RSDK.SetSpriteAnimation(Crane->aniFrames, 3, &self->backAnimator, true, 3);
64
RSDK.SetSpriteAnimation(Crane->aniFrames, 4, &self->chainAnimator, true, 0);
65
self->state = Crane_State_Init;
66
}
67
68
void Crane_StageLoad(void)
69
{
70
Crane->aniFrames = RSDK.LoadSpriteAnimation("FBZ/Crane.bin", SCOPE_STAGE);
71
72
Crane->hitboxUnused.left = -8;
73
Crane->hitboxUnused.top = -8;
74
Crane->hitboxUnused.right = 8;
75
Crane->hitboxUnused.bottom = 8;
76
77
Crane->hitboxRange.left = -8;
78
Crane->hitboxRange.top = 0;
79
Crane->hitboxRange.right = 8;
80
Crane->hitboxRange.bottom = 128;
81
82
Crane->hitboxGrab.left = -8;
83
Crane->hitboxGrab.top = 0;
84
Crane->hitboxGrab.right = 8;
85
Crane->hitboxGrab.bottom = 16;
86
87
Crane->active = ACTIVE_ALWAYS;
88
89
Crane->sfxGrab = RSDK.GetSfx("Global/Grab.wav");
90
91
DEBUGMODE_ADD_OBJ(Crane);
92
}
93
94
void Crane_DebugSpawn(void)
95
{
96
RSDK_THIS(Crane);
97
98
EntityCrane *crane = CREATE_ENTITY(Crane, NULL, self->position.x, self->position.y);
99
crane->direction = self->direction;
100
crane->startDir = self->direction;
101
}
102
103
void Crane_DebugDraw(void)
104
{
105
RSDK.SetSpriteAnimation(Crane->aniFrames, 0, &DebugMode->animator, true, 0);
106
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
107
}
108
109
void Crane_HandlePlayerInteractions(void)
110
{
111
RSDK_THIS(Crane);
112
113
foreach_active(Player, player)
114
{
115
if (!self->grabbedPlayer) {
116
if ((self->playerType != CRANE_PLAYER1_ONLY || !player->sidekick) && (self->playerType != CRANE_PLAYER2_ONLY || player->sidekick)) {
117
if (Player_CheckCollisionTouch(player, self, &Crane->hitboxGrab)) {
118
RSDK.PlaySfx(Crane->sfxGrab, false, 255);
119
self->state = Crane_State_RiseUp;
120
self->isPermanent = true;
121
RSDK.SetSpriteAnimation(Crane->aniFrames, 0, &self->frontAnimator, true, 0);
122
RSDK.SetSpriteAnimation(Crane->aniFrames, 1, &self->backAnimator, true, 0);
123
self->grabbedPlayer = player;
124
player->velocity.x = 0;
125
player->velocity.y = 0;
126
player->groundVel = 0;
127
player->state = Player_State_Static;
128
player->nextGroundState = StateMachine_None;
129
player->nextAirState = StateMachine_None;
130
player->onGround = false;
131
player->direction = self->direction;
132
RSDK.SetSpriteAnimation(player->aniFrames, ANI_FAN, &player->animator, true, 0);
133
player->animator.speed = 0;
134
}
135
}
136
}
137
}
138
}
139
140
void Crane_CheckOffScreen(void)
141
{
142
RSDK_THIS(Crane);
143
144
if (!RSDK.CheckOnScreen(self, &self->updateRange)) {
145
int32 x = self->position.x;
146
int32 y = self->position.y;
147
self->position.x = self->startPos.x;
148
self->position.y = self->startPos.y;
149
if (RSDK.CheckOnScreen(self, &self->updateRange)) {
150
self->position.x = x;
151
self->position.y = y;
152
}
153
else {
154
self->grabbedPlayer = NULL;
155
self->delay = 0;
156
self->timer = 0;
157
self->direction = self->startDir;
158
self->visible = false;
159
self->state = Crane_State_CheckOffScreen;
160
}
161
}
162
}
163
164
void Crane_State_CheckOffScreen(void)
165
{
166
RSDK_THIS(Crane);
167
168
if (!RSDK.CheckOnScreen(self, &self->updateRange)) {
169
self->state = Crane_State_Init;
170
Crane_Create(NULL);
171
}
172
}
173
174
void Crane_State_Init(void)
175
{
176
RSDK_THIS(Crane);
177
178
self->active = ACTIVE_NORMAL;
179
if (!self->startType) {
180
self->state = Crane_State_CheckForPlayers;
181
Crane_State_CheckForPlayers();
182
}
183
else {
184
self->position.y += 0x400000;
185
self->timer = -1;
186
self->state = Crane_State_CheckGrab;
187
188
Crane_HandlePlayerInteractions();
189
Crane_CheckOffScreen();
190
}
191
}
192
193
void Crane_State_CheckForPlayers(void)
194
{
195
RSDK_THIS(Crane);
196
197
foreach_active(Player, player)
198
{
199
if (Player_CheckCollisionTouch(player, self, &Crane->hitboxRange)) {
200
self->timer = 32;
201
self->state = Crane_State_LowerToGrab;
202
}
203
}
204
205
Crane_CheckOffScreen();
206
}
207
208
void Crane_State_LowerToGrab(void)
209
{
210
RSDK_THIS(Crane);
211
212
Crane_HandlePlayerInteractions();
213
Crane_CheckOffScreen();
214
215
--self->timer;
216
if (self->state == Crane_State_LowerToGrab) {
217
if (self->timer >= 0)
218
self->position.y += 0x20000;
219
else
220
self->state = Crane_State_CheckGrab;
221
}
222
}
223
224
void Crane_State_CheckGrab(void)
225
{
226
Crane_HandlePlayerInteractions();
227
Crane_CheckOffScreen();
228
}
229
230
void Crane_State_RiseUp(void)
231
{
232
RSDK_THIS(Crane);
233
if (++self->timer < 32) {
234
self->position.y -= 0x20000;
235
236
EntityPlayer *player = self->grabbedPlayer;
237
if (player) {
238
if (Player_CheckValidState(player)) {
239
player->animator.speed = 0;
240
player->position.x = self->position.x;
241
player->position.y = self->position.y;
242
if (self->direction) {
243
player->position.x += 0x20000;
244
player->position.y += 0xE0000;
245
}
246
else {
247
player->position.x -= 0x20000;
248
player->position.y += 0xE0000;
249
}
250
}
251
else {
252
self->grabbedPlayer = NULL;
253
}
254
}
255
}
256
else {
257
self->delay = 1;
258
self->timer = 16;
259
self->velocity.x = 0;
260
self->state = Crane_State_ToDest1stHalf;
261
}
262
263
Crane_CheckOffScreen();
264
}
265
266
void Crane_State_ToDest1stHalf(void)
267
{
268
RSDK_THIS(Crane);
269
270
self->velocity.x += 0x1000;
271
if (self->direction == FLIP_NONE) {
272
self->position.x += self->velocity.x;
273
if (self->position.x >= self->startPos.x + (self->distance << 15))
274
self->state = Crane_State_ToDest2ndHalf;
275
}
276
else {
277
self->position.x -= self->velocity.x;
278
if (self->position.x <= self->startPos.x - (self->distance << 15))
279
self->state = Crane_State_ToDest2ndHalf;
280
}
281
282
EntityPlayer *player = self->grabbedPlayer;
283
if (player) {
284
if (Player_CheckValidState(player)) {
285
player->animator.speed = 0;
286
player->position.x = self->position.x;
287
player->position.y = self->position.y;
288
if (self->direction) {
289
player->position.x += 0x20000;
290
player->position.y += 0xE0000;
291
}
292
else {
293
player->position.x -= 0x20000;
294
player->position.y += 0xE0000;
295
}
296
}
297
else {
298
self->grabbedPlayer = NULL;
299
}
300
}
301
302
Crane_CheckOffScreen();
303
}
304
305
void Crane_State_ToDest2ndHalf(void)
306
{
307
RSDK_THIS(Crane);
308
309
EntityPlayer *player = self->grabbedPlayer;
310
311
self->velocity.x -= 0x1000;
312
if (self->direction == FLIP_NONE)
313
self->position.x += self->velocity.x;
314
else
315
self->position.x -= self->velocity.x;
316
317
if (self->velocity.x <= 0) {
318
if (player) {
319
if (Player_CheckValidState(player))
320
player->state = Player_State_Air;
321
else
322
self->grabbedPlayer = NULL;
323
}
324
325
RSDK.SetSpriteAnimation(Crane->aniFrames, 2, &self->frontAnimator, true, 0);
326
RSDK.SetSpriteAnimation(Crane->aniFrames, 3, &self->backAnimator, true, 0);
327
self->delay = 30;
328
self->state = Crane_State_DropDelay;
329
self->isPermanent = false;
330
}
331
332
if (player) {
333
if (Player_CheckValidState(player)) {
334
player->animator.speed = 0;
335
player->position.x = self->position.x;
336
player->position.y = self->position.y;
337
if (self->direction) {
338
player->position.x += 0x20000;
339
player->position.y += 0xE0000;
340
}
341
else {
342
player->position.x -= 0x20000;
343
player->position.y += 0xE0000;
344
}
345
}
346
else {
347
self->grabbedPlayer = NULL;
348
}
349
}
350
351
Crane_CheckOffScreen();
352
}
353
354
void Crane_State_DropDelay(void)
355
{
356
RSDK_THIS(Crane);
357
358
if (--self->delay <= 0)
359
self->state = Crane_State_ToStart1stHalf;
360
361
Crane_HandlePlayerInteractions();
362
Crane_CheckOffScreen();
363
}
364
365
void Crane_State_ToStart1stHalf(void)
366
{
367
RSDK_THIS(Crane);
368
369
self->velocity.x -= 0x1000;
370
if (self->direction) {
371
self->position.x -= self->velocity.x;
372
if (self->position.x >= self->startPos.x - (self->distance << 15))
373
self->state = Crane_State_ToStart2ndHalf;
374
}
375
else {
376
self->position.x += self->velocity.x;
377
if (self->position.x <= self->startPos.x + (self->distance << 15))
378
self->state = Crane_State_ToStart2ndHalf;
379
}
380
381
Crane_CheckOffScreen();
382
}
383
384
void Crane_State_ToStart2ndHalf(void)
385
{
386
RSDK_THIS(Crane);
387
self->velocity.x += 0x1000;
388
389
if (self->direction)
390
self->position.x -= self->velocity.x;
391
else
392
self->position.x += self->velocity.x;
393
394
if (self->velocity.x >= 0) {
395
if (self->startType) {
396
self->timer = 32;
397
self->state = Crane_State_LowerToGrab;
398
self->grabbedPlayer = NULL;
399
}
400
else {
401
self->state = Crane_State_CheckForPlayers;
402
self->grabbedPlayer = NULL;
403
}
404
}
405
406
Crane_CheckOffScreen();
407
}
408
409
#if GAME_INCLUDE_EDITOR
410
void Crane_EditorDraw(void)
411
{
412
RSDK_THIS(Crane);
413
414
RSDK.SetSpriteAnimation(Crane->aniFrames, 2, &self->frontAnimator, true, 2);
415
RSDK.SetSpriteAnimation(Crane->aniFrames, 3, &self->backAnimator, true, 2);
416
RSDK.SetSpriteAnimation(Crane->aniFrames, 4, &self->chainAnimator, true, 0);
417
418
Vector2 drawPos = self->position;
419
if (self->startType)
420
drawPos.y += 0x400000;
421
422
RSDK.DrawSprite(&self->chainAnimator, &drawPos, false);
423
RSDK.DrawSprite(&self->backAnimator, &drawPos, false);
424
RSDK.DrawSprite(&self->frontAnimator, &drawPos, false);
425
426
if (showGizmos()) {
427
self->inkEffect = INK_BLEND;
428
429
uint8 mode = 0;
430
self->velocity.x = 0;
431
while (true) {
432
switch (mode) {
433
default: break;
434
case 0:
435
self->velocity.x += 0x1000;
436
if (self->direction == FLIP_NONE) {
437
drawPos.x += self->velocity.x;
438
if (drawPos.x >= self->position.x + (self->distance << 15))
439
mode = 1;
440
}
441
else {
442
drawPos.x -= self->velocity.x;
443
if (drawPos.x <= self->position.x - (self->distance << 15))
444
mode = 1;
445
}
446
break;
447
448
case 1:
449
self->velocity.x -= 0x1000;
450
if (self->direction == FLIP_NONE)
451
drawPos.x += self->velocity.x;
452
else
453
drawPos.x -= self->velocity.x;
454
455
if (self->velocity.x <= 0)
456
mode = 2;
457
break;
458
}
459
460
if (mode > 1)
461
break;
462
}
463
464
RSDK.DrawSprite(&self->chainAnimator, &drawPos, false);
465
RSDK.DrawSprite(&self->backAnimator, &drawPos, false);
466
RSDK.DrawSprite(&self->frontAnimator, &drawPos, false);
467
468
DrawHelpers_DrawArrow(self->position.x, self->position.y, drawPos.x, drawPos.y, 0x00FF00, INK_NONE, 0xFF);
469
470
self->inkEffect = INK_NONE;
471
}
472
}
473
474
void Crane_EditorLoad(void)
475
{
476
Crane->aniFrames = RSDK.LoadSpriteAnimation("FBZ/Crane.bin", SCOPE_STAGE);
477
478
RSDK_ACTIVE_VAR(Crane, direction);
479
RSDK_ENUM_VAR("Right", FLIP_NONE);
480
RSDK_ENUM_VAR("Left", FLIP_X);
481
482
RSDK_ACTIVE_VAR(Crane, startType);
483
RSDK_ENUM_VAR("Up", CRANE_START_UP);
484
RSDK_ENUM_VAR("Down", CRANE_START_DOWN);
485
486
RSDK_ACTIVE_VAR(Crane, playerType);
487
RSDK_ENUM_VAR("Player Only", CRANE_PLAYER1_ONLY);
488
RSDK_ENUM_VAR("Sidekick Only", CRANE_PLAYER2_ONLY);
489
RSDK_ENUM_VAR("Any Player", CRANE_PLAYER_ALL);
490
}
491
#endif
492
493
void Crane_Serialize(void)
494
{
495
RSDK_EDITABLE_VAR(Crane, VAR_UINT8, direction);
496
RSDK_EDITABLE_VAR(Crane, VAR_UINT16, distance);
497
RSDK_EDITABLE_VAR(Crane, VAR_UINT8, startType);
498
RSDK_EDITABLE_VAR(Crane, VAR_UINT8, playerType);
499
}
500
501