Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/ZipLine.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: ZipLine Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectZipLine *ZipLine;
11
12
void ZipLine_Update(void)
13
{
14
RSDK_THIS(ZipLine);
15
16
StateMachine_Run(self->state);
17
18
int32 storeX = self->position.x;
19
int32 storeY = self->position.y;
20
21
self->position = self->handlePos;
22
foreach_active(Player, player)
23
{
24
int32 playerID = RSDK.GetEntitySlot(player);
25
if (self->grabDelay[playerID])
26
self->grabDelay[playerID]--;
27
28
if ((1 << playerID) & self->activePlayers) {
29
if (Player_CheckValidState(player)) {
30
Hitbox *playerHitbox = Player_GetHitbox(player);
31
32
if (player->state != Player_State_Hurt) {
33
if (player->velocity.x) {
34
self->groundVel = player->groundVel;
35
if (self->angle >= 0x40 && self->angle <= 0xC0)
36
self->groundVel = -player->groundVel;
37
38
self->groundVel = CLAMP(self->groundVel, -0xA0000, 0xA0000);
39
40
self->velocity.x = self->groundVel * RSDK.Cos256(self->angle) >> 8;
41
self->velocity.y = self->groundVel * RSDK.Sin256(self->angle) >> 8;
42
player->velocity.x = 0;
43
player->velocity.y = 0;
44
player->groundVel = 0;
45
player->angle = 0;
46
player->rotation = 0;
47
}
48
49
int32 lastX = player->position.x;
50
player->position.x = self->position.x;
51
player->position.y = self->position.y + (((ZipLine->hitboxHandle.bottom - ZipLine->hitboxHandle.top) << 15) & 0xFFFF0000)
52
+ ((ZipLine->hitboxHandle.top - playerHitbox->top) << 16);
53
54
if (abs(lastX - self->position.x) <= 0x100000) {
55
if (!self->grabDelay[playerID] && player->jumpPress) {
56
player->velocity.y = -0x40000;
57
player->jumpAbilityState = 1;
58
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
59
player->animator.speed = 48;
60
player->state = Player_State_Air;
61
self->grabDelay[playerID] = 60;
62
self->activePlayers &= ~(1 << playerID);
63
player->onGround = false;
64
player->groundedStore = false;
65
player->tileCollisions = TILECOLLISION_DOWN;
66
}
67
}
68
else {
69
player->state = Player_State_Air;
70
self->grabDelay[playerID] = 60;
71
self->activePlayers &= ~(1 << playerID);
72
player->onGround = false;
73
player->groundedStore = false;
74
player->tileCollisions = TILECOLLISION_DOWN;
75
}
76
}
77
else {
78
self->grabDelay[playerID] = 60;
79
self->activePlayers &= ~(1 << playerID);
80
player->onGround = false;
81
player->groundedStore = false;
82
player->tileCollisions = TILECOLLISION_DOWN;
83
}
84
}
85
else {
86
self->activePlayers &= ~(1 << playerID);
87
if (player->state != Player_State_Death) {
88
player->tileCollisions = TILECOLLISION_DOWN;
89
}
90
}
91
}
92
else if (!self->grabDelay[playerID] && player->state != Player_State_Static && !player->down) {
93
Hitbox *playerHitbox = Player_GetHitbox(player);
94
Hitbox otherHitbox;
95
otherHitbox.top = playerHitbox->top - 4;
96
otherHitbox.left = playerHitbox->left;
97
otherHitbox.right = playerHitbox->right;
98
otherHitbox.bottom = otherHitbox.top + 8;
99
100
if (RSDK.CheckObjectCollisionTouchBox(self, &ZipLine->hitboxHandle, player, &otherHitbox)) {
101
if (player->sidekick || self->state == ZipLine_State_Moving) {
102
ZipLine_GrabHandle(player, playerID, playerHitbox);
103
}
104
else if (!self->state) {
105
self->groundVel = player->groundVel;
106
if (self->angle >= 0x40 && self->angle <= 0xC0)
107
self->groundVel = -player->groundVel;
108
109
self->groundVel = CLAMP(self->groundVel, -0xA0000, 0xA0000);
110
111
self->velocity.x = self->groundVel * RSDK.Cos256(self->angle) >> 8;
112
self->velocity.y = self->groundVel * RSDK.Sin256(self->angle) >> 8;
113
114
if (self->angle & 0x7F) {
115
if ((uint8)self->angle < 0x80) {
116
if (self->handlePos.x == self->startPos.x) {
117
if (self->velocity.y < 0) {
118
self->velocity.x = 0;
119
self->velocity.y = 0;
120
self->groundVel = 0;
121
}
122
self->state = ZipLine_State_Moving;
123
}
124
125
if (self->handlePos.x == self->endPos.x && self->velocity.y < 0)
126
ZipLine_GrabHandle(player, playerID, playerHitbox);
127
}
128
else {
129
if (self->handlePos.x == self->endPos.x) {
130
if (self->velocity.y < 0) {
131
self->velocity.x = 0;
132
self->velocity.y = 0;
133
self->groundVel = 0;
134
}
135
136
self->state = ZipLine_State_Moving;
137
}
138
139
if (self->handlePos.x == self->startPos.x && self->velocity.y < 0)
140
ZipLine_GrabHandle(player, playerID, playerHitbox);
141
}
142
}
143
else if (self->groundVel) {
144
if ((self->groundVel < 0 && self->handlePos.x != self->startPos.x)
145
|| (self->groundVel > 0 && self->handlePos.x != self->endPos.x)) {
146
ZipLine_GrabHandle(player, playerID, playerHitbox);
147
}
148
}
149
}
150
}
151
}
152
}
153
self->position.x = storeX;
154
self->position.y = storeY;
155
}
156
157
void ZipLine_LateUpdate(void) {}
158
159
void ZipLine_StaticUpdate(void) {}
160
161
void ZipLine_Draw(void)
162
{
163
RSDK_THIS(ZipLine);
164
165
RSDK.DrawLine(self->startPos.x, self->startPos.y, self->endPos.x, self->endPos.y, 0x6060A0, 0x00, INK_NONE, false);
166
RSDK.DrawLine(self->startPos.x, self->startPos.y + 0x10000, self->endPos.x, self->endPos.y + 0x10000, 0x303070, 0x00, INK_NONE, false);
167
168
self->animator.frameID = 0;
169
RSDK.DrawSprite(&self->animator, &self->handlePos, false);
170
self->animator.frameID = 1;
171
172
RSDK.DrawSprite(&self->animator, &self->startPos, false);
173
RSDK.DrawSprite(&self->animator, &self->endPos, false);
174
}
175
176
void ZipLine_Create(void *data)
177
{
178
RSDK_THIS(ZipLine);
179
self->active = ACTIVE_BOUNDS;
180
self->visible = true;
181
self->drawFX = FX_FLIP;
182
RSDK.SetSpriteAnimation(ZipLine->aniFrames, 0, &self->animator, true, 0);
183
self->drawGroup = Zone->playerDrawGroup[0];
184
185
self->handlePos = self->position;
186
self->startPos = self->position;
187
self->endPos.x = self->position.x + (self->length << 8) * RSDK.Cos256(self->angle);
188
self->endPos.y = self->position.y + (self->length << 8) * RSDK.Sin256(self->angle);
189
190
if (!SceneInfo->inEditor) {
191
self->position.x += (self->endPos.x - self->startPos.x) >> 1;
192
self->position.y += (self->endPos.y - self->startPos.y) >> 1;
193
self->updateRange.x = (abs(self->endPos.x - self->startPos.x) >> 1) + 0x400000;
194
self->updateRange.y = (abs(self->endPos.y - self->startPos.y) >> 1) + 0x400000;
195
self->joinPos = ZipLine_GetJoinPos();
196
}
197
}
198
199
void ZipLine_StageLoad(void)
200
{
201
if (RSDK.CheckSceneFolder("GHZ"))
202
ZipLine->aniFrames = RSDK.LoadSpriteAnimation("GHZ/ZipLine.bin", SCOPE_STAGE);
203
204
ZipLine->hitboxHandle.top = 0;
205
ZipLine->hitboxHandle.left = -8;
206
ZipLine->hitboxHandle.bottom = 24;
207
ZipLine->hitboxHandle.right = 8;
208
209
Zone_AddVSSwapCallback(ZipLine_VSSwap_CheckBusy);
210
}
211
212
void ZipLine_VSSwap_CheckBusy(void)
213
{
214
foreach_active(ZipLine, zipline)
215
{
216
#if MANIA_USE_PLUS
217
if ((1 << Zone->swapPlayerID) & zipline->activePlayers)
218
Zone->playerSwapEnabled[Zone->swapPlayerID] = false;
219
#else
220
if (zipline->activePlayers)
221
Zone->playerSwapEnabled = false;
222
#endif
223
}
224
}
225
226
void ZipLine_GrabHandle(EntityPlayer *player, int32 playerID, Hitbox *playerHitbox)
227
{
228
RSDK_THIS(ZipLine);
229
230
self->state = ZipLine_State_Moving;
231
self->activePlayers |= 1 << playerID;
232
player->onGround = false;
233
player->groundedStore = false;
234
player->velocity.x = 0;
235
player->velocity.y = 0;
236
player->groundVel = 0;
237
player->angle = 0;
238
player->rotation = 0;
239
player->position.x = self->position.x;
240
player->position.y = self->position.y;
241
player->position.y +=
242
((ZipLine->hitboxHandle.top - playerHitbox->top) << 16) + (((ZipLine->hitboxHandle.bottom - ZipLine->hitboxHandle.top) << 15) & 0xFFFF0000);
243
player->tileCollisions = TILECOLLISION_NONE;
244
RSDK.SetSpriteAnimation(player->aniFrames, ANI_HANG, &player->animator, true, 0);
245
player->state = Player_State_Static;
246
player->nextAirState = StateMachine_None;
247
player->nextGroundState = StateMachine_None;
248
RSDK.PlaySfx(Player->sfxGrab, false, 0xFF);
249
self->grabDelay[playerID] = 15;
250
self->active = ACTIVE_NORMAL;
251
}
252
253
void ZipLine_ForceReleasePlayers(void)
254
{
255
RSDK_THIS(ZipLine);
256
257
foreach_active(Player, player)
258
{
259
int32 playerID = RSDK.GetEntitySlot(player);
260
if ((1 << playerID) & self->activePlayers) {
261
self->grabDelay[playerID] = 60;
262
player->velocity.y = self->velocity.y;
263
player->velocity.x = self->velocity.x;
264
player->groundVel = player->velocity.x;
265
self->activePlayers &= ~(1 << playerID);
266
player->onGround = false;
267
player->groundedStore = false;
268
player->tileCollisions = TILECOLLISION_DOWN;
269
player->state = Player_State_Air;
270
}
271
}
272
}
273
274
// this func actually rules, you can join any number of ZipLines together using this
275
Vector2 ZipLine_GetJoinPos(void)
276
{
277
RSDK_THIS(ZipLine);
278
279
EntityZipLine *endMarker = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, ZipLine);
280
Vector2 result;
281
result.x = 0;
282
result.y = 0;
283
284
if (endMarker->classID == ZipLine->classID) {
285
Hitbox thisHitbox, otherHitbox;
286
287
if (self->startPos.y >= self->endPos.y) {
288
otherHitbox.top = (self->endPos.y - self->position.y) >> 16;
289
otherHitbox.bottom = (self->startPos.y - self->position.y) >> 16;
290
}
291
else {
292
otherHitbox.top = (self->startPos.y - self->position.y) >> 16;
293
otherHitbox.bottom = (self->endPos.y - self->position.y) >> 16;
294
}
295
296
if (self->startPos.x >= self->endPos.x) {
297
otherHitbox.left = (self->endPos.x - self->position.y) >> 16;
298
otherHitbox.right = (self->startPos.x - self->position.y) >> 16;
299
}
300
else {
301
otherHitbox.left = (self->startPos.x - self->position.x) >> 16;
302
otherHitbox.right = (self->endPos.x - self->position.x) >> 16;
303
}
304
305
if (endMarker->startPos.y >= endMarker->endPos.y) {
306
thisHitbox.top = (endMarker->endPos.y - endMarker->position.y) >> 16;
307
thisHitbox.bottom = (endMarker->startPos.y - endMarker->position.y) >> 16;
308
}
309
else {
310
thisHitbox.top = (endMarker->startPos.y - endMarker->position.y) >> 16;
311
thisHitbox.bottom = (endMarker->endPos.y - endMarker->position.y) >> 16;
312
}
313
314
if (endMarker->startPos.x >= endMarker->endPos.x) {
315
thisHitbox.left = (endMarker->endPos.x - endMarker->position.y) >> 16;
316
thisHitbox.right = (endMarker->startPos.x - endMarker->position.y) >> 16;
317
}
318
else {
319
thisHitbox.left = (endMarker->startPos.x - endMarker->position.x) >> 16;
320
thisHitbox.right = (endMarker->endPos.x - endMarker->position.x) >> 16;
321
}
322
323
otherHitbox.left -= 8;
324
otherHitbox.top -= 8;
325
otherHitbox.right += 8;
326
otherHitbox.bottom += 8;
327
thisHitbox.left -= 8;
328
thisHitbox.top -= 8;
329
thisHitbox.right += 8;
330
thisHitbox.bottom += 8;
331
if (RSDK.CheckObjectCollisionTouchBox(endMarker, &thisHitbox, self, &otherHitbox)) {
332
int32 distX1 = (self->startPos.x >> 17) - (self->endPos.x >> 17);
333
int32 distY1 = (self->endPos.y >> 17) - (self->startPos.y >> 17);
334
int32 distX2 = (endMarker->startPos.x >> 17) - (endMarker->endPos.x >> 17);
335
int32 distY2 = (endMarker->endPos.y >> 17) - (endMarker->startPos.y >> 17);
336
337
int32 val1 = distX1 * (self->startPos.y >> 17) + distY1 * (self->startPos.x >> 17);
338
int32 val2 = distX2 * (endMarker->startPos.y >> 17) + distY2 * (endMarker->startPos.x >> 17);
339
float divisor = (float)(distY1 * distX2 - distX1 * distY2);
340
if (divisor != 0.0f) {
341
endMarker->handlePos.x = -0x100000;
342
result.x = (int32)((float)(distX2 * val1 - distX1 * val2) / divisor) << 17;
343
result.y = (int32)((float)(distY1 * val2 - distY2 * val1) / divisor) << 17;
344
}
345
}
346
}
347
return result;
348
}
349
350
void ZipLine_State_Moving(void)
351
{
352
RSDK_THIS(ZipLine);
353
354
self->groundVel += (RSDK.Sin256(self->angle) << 14 >> 8);
355
if (self->groundVel >= 0xA0000)
356
self->groundVel = 0xA0000;
357
358
self->velocity.x = self->groundVel * RSDK.Cos256(self->angle) >> 8;
359
self->velocity.y = self->groundVel * RSDK.Sin256(self->angle) >> 8;
360
361
if (self->joinPos.x) {
362
int32 storeX = self->position.x;
363
int32 storeY = self->position.y;
364
self->position.x = self->handlePos.x;
365
self->position.y = self->handlePos.y;
366
367
Hitbox otherHitbox;
368
otherHitbox.top = ((self->joinPos.y - self->position.y - (self->velocity.y >> 1)) >> 16) + 8;
369
otherHitbox.bottom = (((self->velocity.y >> 1) + (self->joinPos.y - self->position.y)) >> 16) + 16;
370
371
if (self->velocity.x >= 0) {
372
otherHitbox.left = (self->joinPos.x - self->position.x) >> 16;
373
otherHitbox.right = ((self->joinPos.x + self->velocity.x - self->position.x) >> 16) + 5;
374
}
375
else {
376
otherHitbox.left = (((self->joinPos.x - self->position.x) - self->velocity.x) >> 16) - 5;
377
otherHitbox.right = (self->joinPos.x - self->position.x) >> 16;
378
}
379
380
if (RSDK.CheckObjectCollisionTouchBox(self, &ZipLine->hitboxHandle, self, &otherHitbox)) {
381
EntityZipLine *endMarker = RSDK_GET_ENTITY(SceneInfo->entitySlot - 1, ZipLine);
382
endMarker->handlePos.x = self->joinPos.x;
383
endMarker->handlePos.y = self->joinPos.y;
384
endMarker->onGround = true;
385
endMarker->activePlayers = self->activePlayers;
386
endMarker->groundVel = self->groundVel;
387
endMarker->state = ZipLine_State_Moving;
388
self->position.x = storeX;
389
self->position.y = storeY;
390
self->activePlayers = 0;
391
self->groundVel = 0;
392
self->handlePos.x = -0x100000;
393
self->state = StateMachine_None;
394
foreach_active(Player, player)
395
{
396
if ((1 << RSDK.GetEntitySlot(player)) & endMarker->activePlayers) {
397
Hitbox *playerHitbox = Player_GetHitbox(player);
398
player->velocity.x = 0;
399
player->velocity.y = 0;
400
player->groundVel = 0;
401
player->angle = 0;
402
player->rotation = 0;
403
player->position.x = endMarker->handlePos.x;
404
player->position.y = endMarker->handlePos.y + (((ZipLine->hitboxHandle.bottom - ZipLine->hitboxHandle.top) << 15) & 0xFFFF0000)
405
+ ((ZipLine->hitboxHandle.top - playerHitbox->top) << 16);
406
}
407
}
408
return;
409
}
410
self->position.x = storeX;
411
self->position.y = storeY;
412
}
413
414
self->handlePos.x += self->velocity.x;
415
self->handlePos.y += self->velocity.y;
416
if (self->groundVel < 0) {
417
if (self->velocity.x < 0) {
418
if (self->handlePos.x < self->startPos.x)
419
self->handlePos.x = self->startPos.x;
420
421
if (self->velocity.y < 0) {
422
if (self->handlePos.y < self->startPos.y)
423
self->handlePos.y = self->startPos.y;
424
}
425
if (self->velocity.y > 0) {
426
if (self->handlePos.y > self->startPos.y)
427
self->handlePos.y = self->startPos.y;
428
}
429
430
if (self->handlePos.x == self->startPos.x && self->handlePos.y == self->startPos.y) {
431
self->groundVel = 0;
432
if (self->startPos.y >= self->endPos.y || !self->onGround) {
433
self->onGround = false;
434
self->active = ACTIVE_BOUNDS;
435
self->state = StateMachine_None;
436
ZipLine_ForceReleasePlayers();
437
}
438
}
439
}
440
else if (self->velocity.x > 0) {
441
if (self->handlePos.x > self->startPos.x)
442
self->handlePos.x = self->startPos.x;
443
444
if (self->velocity.y < 0) {
445
if (self->handlePos.y < self->startPos.y)
446
self->handlePos.y = self->startPos.y;
447
}
448
if (self->velocity.y > 0) {
449
if (self->handlePos.y > self->startPos.y)
450
self->handlePos.y = self->startPos.y;
451
}
452
453
if (self->handlePos.x == self->startPos.x && self->handlePos.y == self->startPos.y) {
454
self->groundVel = 0;
455
if (self->startPos.y >= self->endPos.y || !self->onGround) {
456
self->onGround = false;
457
self->active = ACTIVE_BOUNDS;
458
self->state = StateMachine_None;
459
ZipLine_ForceReleasePlayers();
460
}
461
}
462
}
463
}
464
else if (self->groundVel > 0) {
465
if (self->velocity.x > 0) {
466
if (self->handlePos.x > self->endPos.x) {
467
self->handlePos.x = self->endPos.x;
468
}
469
}
470
else if (self->velocity.x < 0) {
471
self->endPos.x = self->endPos.x;
472
if (self->handlePos.x < self->endPos.x) {
473
self->handlePos.x = self->endPos.x;
474
}
475
}
476
477
if (self->velocity.y < 0) {
478
if (self->handlePos.y < self->endPos.y)
479
self->handlePos.y = self->endPos.y;
480
}
481
else if (self->velocity.y > 0) {
482
if (self->handlePos.y > self->endPos.y)
483
self->handlePos.y = self->endPos.y;
484
}
485
486
if (self->handlePos.x == self->endPos.x && self->handlePos.y == self->endPos.y) {
487
self->groundVel = 0;
488
if (self->endPos.y >= self->startPos.y || !self->onGround) {
489
self->onGround = false;
490
self->active = ACTIVE_BOUNDS;
491
self->state = StateMachine_None;
492
ZipLine_ForceReleasePlayers();
493
}
494
}
495
}
496
}
497
498
#if GAME_INCLUDE_EDITOR
499
void ZipLine_EditorDraw(void)
500
{
501
RSDK_THIS(ZipLine);
502
self->handlePos = self->position;
503
self->startPos = self->position;
504
self->endPos.x = self->position.x + (self->length << 8) * RSDK.Cos256(self->angle);
505
self->endPos.y = self->position.y + (self->length << 8) * RSDK.Sin256(self->angle);
506
507
ZipLine_Draw();
508
}
509
510
void ZipLine_EditorLoad(void) { ZipLine->aniFrames = RSDK.LoadSpriteAnimation("GHZ/ZipLine.bin", SCOPE_STAGE); }
511
#endif
512
513
void ZipLine_Serialize(void)
514
{
515
RSDK_EDITABLE_VAR(ZipLine, VAR_INT32, angle);
516
RSDK_EDITABLE_VAR(ZipLine, VAR_ENUM, length);
517
}
518
519