Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/FBZ/HangPoint.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: HangPoint Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectHangPoint *HangPoint;
11
12
void HangPoint_Update(void)
13
{
14
RSDK_THIS(HangPoint);
15
16
if (self->length > 0) {
17
bool32 isActive = true;
18
if (self->activePlayers == 2) {
19
EntityPlayer *player2 = RSDK_GET_ENTITY(SLOT_PLAYER2, Player);
20
if (player2->sidekick)
21
isActive = false;
22
}
23
24
for (int32 i = 0; i < PLAYER_COUNT; ++i) {
25
if (self->moveDistance[i])
26
isActive = false;
27
}
28
29
if (self->pullPos > self->length) {
30
if (self->pullPos <= 0) {
31
self->activePlayers &= 0xF;
32
}
33
else {
34
self->velocity.y -= 0x1800;
35
if (self->velocity.y < -self->maxVel)
36
self->velocity.y = -self->maxVel;
37
38
self->activePlayers |= 16 * self->activePlayers;
39
self->pullPos += self->velocity.y;
40
}
41
}
42
else {
43
if (!self->activePlayers || !isActive) {
44
self->active = ACTIVE_BOUNDS;
45
if (self->direction == FLIP_NONE) {
46
if (self->pullPos > 0) {
47
self->velocity.y -= 0x1000;
48
if (self->velocity.y < -self->maxVel)
49
self->velocity.y = -self->maxVel;
50
51
self->pullPos += self->velocity.y;
52
}
53
}
54
else if (self->pullPos < self->length) {
55
self->velocity.y += 0x1000;
56
if (self->velocity.y > self->maxVel)
57
self->velocity.y = self->maxVel;
58
59
self->pullPos += self->velocity.y;
60
if (self->pullPos > self->length) {
61
self->pullPos = self->length;
62
self->velocity.y = 0;
63
}
64
}
65
}
66
else {
67
if (self->direction) {
68
if (self->pullPos <= 0) {
69
self->activePlayers &= 0xF;
70
}
71
else {
72
self->velocity.y -= 0x1800;
73
if (self->velocity.y < -self->maxVel)
74
self->velocity.y = -self->maxVel;
75
76
self->activePlayers |= 16 * self->activePlayers;
77
self->pullPos += self->velocity.y;
78
}
79
}
80
else {
81
if (self->pullPos >= self->length) {
82
self->activePlayers &= 0xF;
83
}
84
else {
85
self->velocity.y += 0x1800;
86
if (self->velocity.y > self->maxVel)
87
self->velocity.y = self->maxVel;
88
89
self->pullPos += self->velocity.y;
90
if (self->pullPos > self->length) {
91
self->pullPos = self->length;
92
self->velocity.y = 0;
93
}
94
95
self->activePlayers |= (self->activePlayers << 4);
96
}
97
}
98
}
99
}
100
101
if (self->pullPos < 0) {
102
self->pullPos = 0;
103
self->velocity.y = 0;
104
}
105
}
106
107
int32 storeX = self->position.x;
108
int32 storeY = self->position.y;
109
self->position.y += self->pullPos;
110
111
foreach_active(Player, player)
112
{
113
int32 playerID = RSDK.GetEntitySlot(player);
114
115
if (self->playerTimer[playerID] > 0)
116
self->playerTimer[playerID]--;
117
118
if (!((1 << playerID) & self->activePlayers)) {
119
if (player->state != Player_State_Static && !self->playerTimer[playerID]) {
120
Hitbox *playerHitbox = Player_GetHitbox(player);
121
122
Hitbox hitboxPlayer;
123
hitboxPlayer.left = playerHitbox->left;
124
hitboxPlayer.top = playerHitbox->top;
125
hitboxPlayer.right = playerHitbox->right;
126
hitboxPlayer.bottom = hitboxPlayer.top + 4;
127
if (RSDK.CheckObjectCollisionTouchBox(self, &HangPoint->hitboxGrab, player, &hitboxPlayer)) {
128
player->velocity.x = 0;
129
player->velocity.y = 0;
130
player->groundVel = 0;
131
player->onGround = false;
132
player->angle = 0;
133
player->rotation = 0;
134
player->position.x = self->position.x;
135
player->position.y = self->position.y;
136
player->position.y += ((HangPoint->hitboxGrab.top - playerHitbox->top) << 16)
137
+ (((HangPoint->hitboxGrab.bottom - HangPoint->hitboxGrab.top) << 15) & 0xFFFF0000);
138
player->tileCollisions = TILECOLLISION_NONE;
139
self->moveDistance[playerID] = 0;
140
141
if (!self->activePlayers) {
142
if (self->direction == FLIP_X) {
143
if (self->pullPos <= self->length)
144
self->velocity.y = 0x20000;
145
}
146
else {
147
self->velocity.y = 0;
148
}
149
}
150
self->activePlayers |= 1 << playerID;
151
152
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG, &player->animator, false, 0);
153
player->nextAirState = StateMachine_None;
154
player->nextGroundState = StateMachine_None;
155
player->state = Player_State_Static;
156
player->abilityValues[0] = RSDK.Rand(0, 2);
157
RSDK.PlaySfx(Player->sfxGrab, false, 255);
158
self->active = ACTIVE_NORMAL;
159
}
160
}
161
}
162
else {
163
if (player->state == Player_State_Hurt) {
164
player->tileCollisions = TILECOLLISION_DOWN;
165
self->activePlayers &= ~(1 << playerID) & ~(1 << (playerID + PLAYER_COUNT));
166
self->moveDistance[playerID] = 0;
167
if (player->left || player->right || player->down || player->state == Player_State_Hurt)
168
self->playerTimer[playerID] = 64;
169
else
170
self->playerTimer[playerID] = 16;
171
}
172
else {
173
if (player->state != Player_State_Static || self->playerTimer[playerID]) {
174
self->activePlayers &= ~(1 << playerID);
175
176
if (player->classID == Player->classID && Player_CheckValidState(player))
177
player->tileCollisions = TILECOLLISION_DOWN;
178
}
179
else {
180
Hitbox *playerHitbox = Player_GetHitbox(player);
181
player->velocity.x = 0;
182
player->velocity.y = 0;
183
player->groundVel = 0;
184
player->angle = 0;
185
player->rotation = 0;
186
player->position.x = self->position.x;
187
player->position.y = self->position.y;
188
player->position.y += (((HangPoint->hitboxGrab.bottom - HangPoint->hitboxGrab.top) << 15) & 0xFFFF0000)
189
+ ((HangPoint->hitboxGrab.top - playerHitbox->top) << 16);
190
191
if (!self->moveDistance[playerID]) {
192
if (player->left)
193
player->direction = FLIP_X;
194
195
if (player->right)
196
player->direction = FLIP_NONE;
197
198
if (player->jumpPress) {
199
player->velocity.y = -0x40000;
200
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
201
player->animator.speed = 48;
202
player->applyJumpCap = false;
203
player->jumpAbilityState = 1;
204
player->state = Player_State_Air;
205
player->tileCollisions = TILECOLLISION_DOWN;
206
self->activePlayers &= ~(1 << playerID) & ~(1 << (playerID + PLAYER_COUNT));
207
208
if (player->left || player->right || player->down || player->state == Player_State_Hurt) {
209
self->playerTimer[playerID] = 64;
210
HangPoint_HandlePlayerMovement(self, player, playerID);
211
}
212
else {
213
self->playerTimer[playerID] = 16;
214
HangPoint_HandlePlayerMovement(self, player, playerID);
215
}
216
}
217
else if ((!((1 << (playerID + 4)) & self->activePlayers) && (self->direction != FLIP_NONE || self->pullPos >= self->length)
218
&& (self->direction != FLIP_X || self->pullPos <= 0))
219
|| player->sidekick) {
220
221
bool32 changedHangPoint = false;
222
if (player->left) {
223
foreach_active(HangPoint, point)
224
{
225
if (self != point) {
226
int32 distance = self->position.x - point->position.x;
227
if (distance < 0x220000 && distance > 0) {
228
if (abs(self->position.y - point->position.y - point->pullPos) < 0x40000) {
229
self->activePlayers &= ~(1 << playerID);
230
self->playerTimer[playerID] = 16;
231
point->activePlayers |= 1 << playerID;
232
point->moveDistance[playerID] = 0x200000;
233
point->playerTimer[playerID] = 0;
234
#if MANIA_USE_PLUS
235
if (player->characterID == ID_RAY) {
236
if (player->abilityValues[0])
237
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG_MOVE, &player->animator, false, 6);
238
else
239
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG_MOVE, &player->animator, false, 1);
240
}
241
else {
242
#endif
243
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG_MOVE, &player->animator, false, 3);
244
#if MANIA_USE_PLUS
245
}
246
#endif
247
248
player->position.x = point->position.x;
249
250
if (RSDK.GetEntitySlot(point) < SceneInfo->entitySlot)
251
HangPoint_HandlePlayerMovement(point, player, playerID);
252
HangPoint_HandlePlayerMovement(self, player, playerID);
253
254
changedHangPoint = true;
255
foreach_break;
256
}
257
}
258
}
259
}
260
}
261
else if (player->right) {
262
foreach_active(HangPoint, point)
263
{
264
if (self != point) {
265
int32 distance = point->position.x - self->position.x;
266
if (distance < 0x220000 && distance > 0) {
267
if (abs(self->position.y - point->position.y - point->pullPos) < 0x40000) {
268
self->activePlayers &= ~(1 << playerID);
269
self->playerTimer[playerID] = 16;
270
point->activePlayers |= 1 << playerID;
271
point->moveDistance[playerID] = -0x200000;
272
point->playerTimer[playerID] = 0;
273
274
#if MANIA_USE_PLUS
275
if (player->characterID == ID_RAY) {
276
if (!player->abilityValues[0]) {
277
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG_MOVE, &player->animator, false, 0);
278
}
279
else {
280
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG_MOVE, &player->animator, false, 6);
281
}
282
}
283
else {
284
#endif
285
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG_MOVE, &player->animator, false, 3);
286
#if MANIA_USE_PLUS
287
}
288
#endif
289
290
player->position.x = point->position.x;
291
292
if (RSDK.GetEntitySlot(point) < SceneInfo->entitySlot)
293
HangPoint_HandlePlayerMovement(point, player, playerID);
294
HangPoint_HandlePlayerMovement(self, player, playerID);
295
296
changedHangPoint = true;
297
foreach_break;
298
}
299
}
300
}
301
}
302
}
303
304
if (!changedHangPoint) {
305
#if MANIA_USE_PLUS
306
if (player->characterID == ID_RAY && player->abilityValues[0] == 1)
307
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG2, &player->animator, false, 0);
308
else
309
#endif
310
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG, &player->animator, false, 0);
311
312
HangPoint_HandlePlayerMovement(self, player, playerID);
313
}
314
}
315
else {
316
#if MANIA_USE_PLUS
317
if (player->characterID == ID_RAY && player->abilityValues[0] == 1)
318
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG2, &player->animator, false, 0);
319
else
320
#endif
321
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG, &player->animator, false, 0);
322
323
HangPoint_HandlePlayerMovement(self, player, playerID);
324
}
325
}
326
else {
327
HangPoint_HandlePlayerMovement(self, player, playerID);
328
}
329
}
330
}
331
}
332
}
333
334
self->position.x = storeX;
335
self->position.y = storeY;
336
}
337
338
void HangPoint_LateUpdate(void) {}
339
340
void HangPoint_StaticUpdate(void) {}
341
342
void HangPoint_Draw(void)
343
{
344
RSDK_THIS(HangPoint);
345
346
Vector2 drawPos;
347
348
drawPos.x = self->position.x;
349
drawPos.y = self->position.y + self->pullPos;
350
RSDK.DrawSprite(&HangPoint->animator, &drawPos, false);
351
352
if (self->length) {
353
HangPoint->animator.frameID = 1;
354
int32 length = (self->pullPos >> 16) & 0xFF00;
355
356
SpriteFrame *frame = RSDK.GetFrame(HangPoint->aniFrames, 0, HangPoint->animator.frameID);
357
358
int32 extraLength = (self->pullPos >> 16) & 0x00FF;
359
frame->pivotY = -(self->pullPos >> 16);
360
frame->height = extraLength;
361
frame->sprY = 257 - extraLength;
362
RSDK.DrawSprite(&HangPoint->animator, &drawPos, false);
363
364
frame->height = 256;
365
frame->sprY = 1;
366
while (length >= 256) {
367
frame->pivotY = -length;
368
RSDK.DrawSprite(&HangPoint->animator, &drawPos, false);
369
length -= 256;
370
}
371
HangPoint->animator.frameID = 0;
372
}
373
}
374
375
void HangPoint_Create(void *data)
376
{
377
RSDK_THIS(HangPoint);
378
379
if (!self->speed)
380
self->speed = 2;
381
382
self->active = ACTIVE_BOUNDS;
383
self->updateRange.x = 0x400000;
384
self->visible = true;
385
self->updateRange.y = (self->length + 64) << 16;
386
self->drawGroup = Zone->objectDrawGroup[0];
387
if (!SceneInfo->inEditor) {
388
self->length = self->length << 16;
389
self->maxVel = self->speed << 15;
390
if (self->direction == FLIP_X)
391
self->pullPos = self->length;
392
}
393
}
394
395
void HangPoint_StageLoad(void)
396
{
397
if (RSDK.CheckSceneFolder("FBZ"))
398
HangPoint->aniFrames = RSDK.LoadSpriteAnimation("FBZ/HangPoint.bin", SCOPE_STAGE);
399
400
RSDK.SetSpriteAnimation(HangPoint->aniFrames, 0, &HangPoint->animator, true, 0);
401
402
Hitbox *hitbox = RSDK.GetHitbox(&HangPoint->animator, 0);
403
HangPoint->hitboxGrab.top = hitbox->top;
404
HangPoint->hitboxGrab.left = hitbox->left;
405
HangPoint->hitboxGrab.bottom = hitbox->bottom;
406
HangPoint->hitboxGrab.right = hitbox->right;
407
}
408
409
void HangPoint_HandlePlayerMovement(EntityHangPoint *self, EntityPlayer *player, int32 playerID)
410
{
411
if (self->moveDistance[playerID]) {
412
if (self->moveDistance[playerID] < 0) {
413
self->moveDistance[playerID] += 0x15556;
414
if (self->moveDistance[playerID] >= 0) {
415
self->moveDistance[playerID] = 0;
416
RSDK.PlaySfx(Player->sfxGrab, false, 255);
417
player->abilityValues[0] ^= 1;
418
}
419
}
420
else {
421
self->moveDistance[playerID] -= 0x15556;
422
if (self->moveDistance[playerID] <= 0) {
423
self->moveDistance[playerID] = 0;
424
RSDK.PlaySfx(Player->sfxGrab, false, 255);
425
player->abilityValues[0] ^= 1;
426
}
427
}
428
429
player->position.x += self->moveDistance[playerID] & 0xFFFF0000;
430
if (player->jumpPress) {
431
player->velocity.y = -0x40000;
432
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
433
434
player->applyJumpCap = false;
435
player->animator.speed = 48;
436
player->jumpAbilityState = 1;
437
player->state = Player_State_Air;
438
player->tileCollisions = TILECOLLISION_DOWN;
439
self->activePlayers &= ~(1 << playerID) & ~(1 << (playerID + 4));
440
self->moveDistance[playerID] = 0;
441
442
if (player->left || player->right || player->down || player->state == Player_State_Hurt)
443
self->playerTimer[playerID] = 64;
444
else
445
self->playerTimer[playerID] = 16;
446
}
447
}
448
}
449
450
#if GAME_INCLUDE_EDITOR
451
void HangPoint_EditorDraw(void)
452
{
453
RSDK_THIS(HangPoint);
454
455
int32 len = self->length;
456
self->length <<= 16;
457
458
self->pullPos = self->direction == FLIP_X ? self->length : 0;
459
HangPoint_Draw();
460
461
if (self->length && showGizmos()) {
462
RSDK_DRAWING_OVERLAY(true);
463
self->inkEffect = INK_BLEND;
464
465
int32 prevPullPos = self->pullPos;
466
self->pullPos = self->direction == FLIP_X ? 0 : self->length;
467
HangPoint_Draw();
468
469
DrawHelpers_DrawArrow(self->position.x, self->position.y + prevPullPos, self->position.x, self->position.y + self->pullPos, 0x00FF00,
470
INK_NONE, 0xFF);
471
472
RSDK_DRAWING_OVERLAY(false);
473
self->inkEffect = INK_NONE;
474
}
475
476
self->length = len;
477
}
478
479
void HangPoint_EditorLoad(void)
480
{
481
HangPoint->aniFrames = RSDK.LoadSpriteAnimation("FBZ/HangPoint.bin", SCOPE_STAGE);
482
RSDK.SetSpriteAnimation(HangPoint->aniFrames, 0, &HangPoint->animator, true, 0);
483
484
RSDK_ACTIVE_VAR(HangPoint, direction);
485
RSDK_ENUM_VAR("Drop Down", FLIP_NONE);
486
RSDK_ENUM_VAR("Pull Up", FLIP_X);
487
}
488
#endif
489
490
void HangPoint_Serialize(void)
491
{
492
RSDK_EDITABLE_VAR(HangPoint, VAR_ENUM, length);
493
RSDK_EDITABLE_VAR(HangPoint, VAR_UINT8, speed);
494
RSDK_EDITABLE_VAR(HangPoint, VAR_UINT8, direction);
495
}
496
497