Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/PGZ/PaperRoller.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PaperRoller Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPaperRoller *PaperRoller;
11
12
void PaperRoller_Update(void)
13
{
14
RSDK_THIS(PaperRoller);
15
16
RSDK.ProcessAnimation(&self->rollerAnimator);
17
18
int32 startX = self->position.x - (RSDK.Cos256(self->angle) << 7) * self->length;
19
int32 startY = self->position.y - (RSDK.Sin256(self->angle) << 7) * self->length;
20
int32 endX = self->position.x + (RSDK.Cos256(self->angle) << 7) * self->length;
21
int32 endY = self->position.y + (RSDK.Sin256(self->angle) << 7) * self->length;
22
int32 centerX = self->position.x;
23
int32 centerY = self->position.y;
24
25
// left roller
26
self->position.x = startX;
27
self->position.y = startY;
28
PaperRoller_HandleRollerCollisions();
29
30
// right roller
31
self->position.x = endX;
32
self->position.y = endY;
33
PaperRoller_HandleRollerCollisions();
34
35
// print
36
self->position.x = centerX;
37
self->position.y = centerY;
38
PaperRoller_HandlePrintCollisions();
39
40
if (self->direction == FLIP_NONE)
41
self->divotAngle += 6;
42
else
43
self->divotAngle -= 6;
44
45
if (self->divotAngle < 0)
46
self->divotAngle += 0x100;
47
48
self->divotAngle &= 0xFF;
49
}
50
51
void PaperRoller_LateUpdate(void) {}
52
53
void PaperRoller_StaticUpdate(void) {}
54
55
void PaperRoller_Draw(void)
56
{
57
PaperRoller_DrawPaperLines();
58
PaperRoller_DrawRollers();
59
}
60
61
void PaperRoller_Create(void *data)
62
{
63
RSDK_THIS(PaperRoller);
64
65
self->active = ACTIVE_BOUNDS;
66
self->drawGroup = Zone->objectDrawGroup[0];
67
self->startPos.x = self->position.x;
68
self->startPos.y = self->position.y;
69
self->visible = true;
70
self->drawFX = FX_NONE;
71
self->updateRange.x = 0x800000;
72
self->updateRange.y = 0x800000;
73
74
self->updateRange.x += abs((RSDK.Cos256(self->angle) << 8) * self->length);
75
self->updateRange.y += abs((RSDK.Sin256(self->angle) << 8) * self->length);
76
77
if (self->length > 256)
78
self->length = 256;
79
80
self->lastJumpTimer[0] = 0x7FFF;
81
self->lastJumpTimer[1] = 0x7FFF;
82
self->lastJumpTimer[2] = 0x7FFF;
83
self->lastJumpTimer[3] = 0x7FFF;
84
85
self->hitbox.left = -24;
86
self->hitbox.top = -24;
87
self->hitbox.right = 24;
88
self->hitbox.bottom = 24;
89
90
RSDK.SetSpriteAnimation(PaperRoller->aniFrames, 0, &self->rollerAnimator, true, 0);
91
RSDK.SetSpriteAnimation(PaperRoller->aniFrames, 1, &self->divotAnimator, true, 0);
92
}
93
94
void PaperRoller_StageLoad(void)
95
{
96
97
PaperRoller->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/PaperRoller.bin", SCOPE_STAGE);
98
99
color colors[] = { 0x0F0F0E8, 0x0D0B898, 0x987870, 0x586868 };
100
for (int32 i = 0; i < 0x40; ++i) PaperRoller->colors[i] = colors[i & 3];
101
102
PaperRoller->sfxPaper = RSDK.GetSfx("PSZ/Paper.wav");
103
}
104
105
void PaperRoller_DrawDeformedLine(int32 startX, int32 startY, int32 endX, int32 endY, int32 offsetX, int32 offsetY, int32 deformX, int32 deformY,
106
int32 len, uint32 *color)
107
{
108
RSDK_THIS(PaperRoller);
109
110
int32 count = (self->length / 4) + ((self->length % 4) > 0);
111
if (count) {
112
int32 negAngle = -self->angle & 0xFF;
113
114
int32 currentX = startX;
115
int32 currentY = startY;
116
int32 moveX = (endX - startX) / count;
117
int32 moveY = (endY - startY) / count;
118
119
for (int32 i = 0; i < count; ++i) {
120
int32 colorID = self->direction ? (len % count) : (count - len % count - 1);
121
122
uint32 lineColor = color ? *color : PaperRoller->colors[(Zone->timer + colorID) % count];
123
124
if (!deformY) {
125
RSDK.DrawLine(offsetX + currentX, offsetY + currentY, offsetX + (currentX + moveX), offsetY + (currentY + moveY), lineColor, 0x7F,
126
INK_NONE, false);
127
}
128
else {
129
int32 distX = (currentX - self->position.x) >> 8;
130
int32 distY = (currentY - self->position.y) >> 8;
131
132
int32 angValX = distY * RSDK.Sin256(self->angle) + distX * RSDK.Cos256(self->angle);
133
int32 angValY = self->position.y - distX * RSDK.Sin256(self->angle) + distY * RSDK.Cos256(self->angle) - self->position.y;
134
135
int32 lenY = 0;
136
137
if (angValX >= deformX) {
138
int32 length = abs((self->length << 15) - deformX);
139
140
if (length >> 16 > 0)
141
lenY = (deformY >> 8) * ((length + deformX - angValX) >> 8) / (length >> 16);
142
}
143
else {
144
int32 length = length = abs(deformX + (self->length << 15));
145
146
if (length >> 16 > 0)
147
lenY = (deformY >> 8) * (((self->length << 15) + angValX) >> 8) / (length >> 16);
148
}
149
150
distX = angValX >> 8;
151
distY = (lenY + angValY) >> 8;
152
153
Vector2 offset1;
154
offset1.x = self->position.x + distY * RSDK.Sin256(negAngle) + distX * RSDK.Cos256(negAngle);
155
offset1.y = self->position.y - distX * RSDK.Sin256(negAngle) + distY * RSDK.Cos256(negAngle);
156
157
distX = ((currentX + moveX) - self->position.x) >> 8;
158
distY = ((currentY + moveY) - self->position.y) >> 8;
159
160
angValX = distY * RSDK.Sin256(self->angle) + distX * RSDK.Cos256(self->angle);
161
angValY = self->position.y - distX * RSDK.Sin256(self->angle) + distY * RSDK.Cos256(self->angle) - self->position.y;
162
163
lenY = 0;
164
if (angValX >= deformX) {
165
int32 length = abs((self->length << 15) - deformX);
166
167
if (length >> 16 > 0)
168
lenY = (deformY >> 8) * ((length + deformX - angValX) >> 8) / (length >> 16);
169
}
170
else {
171
int32 length = abs((self->length << 15) + deformX);
172
173
if (length >> 16 > 0)
174
lenY = (deformY >> 8) * (((self->length << 15) + angValX) >> 8) / (length >> 16);
175
}
176
177
distX = angValX >> 8;
178
distY = (lenY + angValY) >> 8;
179
180
Vector2 offset2;
181
offset2.x = self->position.x + distY * RSDK.Sin256(negAngle) + distX * RSDK.Cos256(negAngle);
182
offset2.y = self->position.y - distX * RSDK.Sin256(negAngle) + distY * RSDK.Cos256(negAngle);
183
184
RSDK.DrawLine(offsetX + offset1.x, offsetY + offset1.y, offsetX + offset2.x, offsetY + offset2.y, lineColor, 0x7F, INK_NONE, false);
185
}
186
187
++len;
188
189
currentX += moveX;
190
currentY += moveY;
191
}
192
}
193
}
194
195
void PaperRoller_DrawPaperLines(void)
196
{
197
RSDK_THIS(PaperRoller);
198
199
int32 x1 = self->position.x - (RSDK.Cos256(self->angle) << 7) * self->length;
200
int32 y1 = self->position.y - (RSDK.Sin256(self->angle) << 7) * self->length;
201
int32 x2 = self->position.x + (RSDK.Cos256(self->angle) << 7) * self->length;
202
int32 y2 = self->position.y + (RSDK.Sin256(self->angle) << 7) * self->length;
203
204
int32 len = self->length / 4 + (self->length % 4 > 0);
205
int32 startX1 = x1 + 0x1800 * RSDK.Cos256(self->angle - 64);
206
int32 startY1 = y1 + 0x1800 * RSDK.Sin256(self->angle - 64);
207
int32 endX1 = x2 + 0x1800 * RSDK.Cos256(self->angle - 64);
208
int32 endY1 = y2 + 0x1800 * RSDK.Sin256(self->angle - 64);
209
210
int32 startX2 = x2 + 0x1800 * RSDK.Cos256(self->angle + 64);
211
int32 startY2 = y2 + 0x1800 * RSDK.Sin256(self->angle + 64);
212
int32 endX2 = x1 + 0x1800 * RSDK.Cos256(self->angle + 64);
213
int32 endY2 = y1 + 0x1800 * RSDK.Sin256(self->angle + 64);
214
215
PaperRoller_DrawDeformedLine(startX1, startY1, endX1, endY1, 0, 0, self->deformPosTop.x, self->deformPosTop.y, 0, NULL);
216
PaperRoller_DrawDeformedLine(startX2, startY2, endX2, endY2, 0, 0, self->deformPosBottom.x, self->deformPosBottom.y, len, NULL);
217
218
int32 angle = self->angle + 32;
219
if (angle < 0)
220
angle = ((-1 - (self->angle + 32)) & 0xFFFFFF00) + self->angle + 288;
221
222
int32 offsetY1 = 0, offsetY2 = 0, offsetX2 = 0, offsetX1 = 0;
223
switch (angle >> 6) {
224
case 0:
225
offsetY1 = 0x10000;
226
offsetY2 = -0x10000;
227
break;
228
229
case 1:
230
offsetX1 = -0x10000;
231
offsetX2 = 0x10000;
232
break;
233
234
case 2:
235
offsetY1 = -0x10000;
236
offsetY2 = 0x10000;
237
break;
238
239
case 3:
240
offsetX1 = 0x10000;
241
offsetX2 = -0x10000;
242
break;
243
}
244
PaperRoller_DrawDeformedLine(startX1, startY1, endX1, endY1, offsetX1, offsetY1, self->deformPosTop.x, self->deformPosTop.y, 0, NULL);
245
PaperRoller_DrawDeformedLine(startX2, startY2, endX2, endY2, offsetX2, offsetY2, self->deformPosBottom.x, self->deformPosBottom.y, len, NULL);
246
247
color color = 0xD0B898;
248
offsetX1 <<= 1;
249
offsetY1 <<= 1;
250
offsetX2 <<= 1;
251
offsetY2 <<= 1;
252
PaperRoller_DrawDeformedLine(startX1, startY1, endX1, endY1, offsetX1, offsetY1, self->deformPosTop.x, self->deformPosTop.y, 0, &color);
253
PaperRoller_DrawDeformedLine(startX2, startY2, endX2, endY2, offsetX2, offsetY2, self->deformPosBottom.x, self->deformPosBottom.y, len, &color);
254
}
255
256
void PaperRoller_DrawRollers(void)
257
{
258
RSDK_THIS(PaperRoller);
259
260
Vector2 rollerPos;
261
Vector2 divotPos;
262
263
rollerPos = self->position;
264
rollerPos.x -= (RSDK.Cos256(self->angle) << 7) * self->length;
265
rollerPos.y -= (RSDK.Sin256(self->angle) << 7) * self->length;
266
RSDK.DrawSprite(&self->rollerAnimator, &rollerPos, false);
267
268
divotPos = rollerPos;
269
divotPos.x += -0x900 * RSDK.Cos256(self->divotAngle);
270
divotPos.y += -0x900 * RSDK.Sin256(self->divotAngle);
271
RSDK.DrawSprite(&self->divotAnimator, &divotPos, false);
272
273
divotPos = rollerPos;
274
divotPos.x += 0x900 * RSDK.Cos256(self->divotAngle);
275
divotPos.y += 0x900 * RSDK.Sin256(self->divotAngle);
276
RSDK.DrawSprite(&self->divotAnimator, &divotPos, false);
277
278
rollerPos = self->position;
279
rollerPos.x += (RSDK.Cos256(self->angle) << 7) * self->length;
280
rollerPos.y += (RSDK.Sin256(self->angle) << 7) * self->length;
281
RSDK.DrawSprite(&self->rollerAnimator, &rollerPos, false);
282
283
divotPos = rollerPos;
284
divotPos.x += -0x900 * RSDK.Cos256(self->divotAngle);
285
divotPos.y += -0x900 * RSDK.Sin256(self->divotAngle);
286
RSDK.DrawSprite(&self->divotAnimator, &divotPos, false);
287
288
divotPos = rollerPos;
289
divotPos.x += 0x900 * RSDK.Cos256(self->divotAngle);
290
divotPos.y += 0x900 * RSDK.Sin256(self->divotAngle);
291
RSDK.DrawSprite(&self->divotAnimator, &divotPos, false);
292
}
293
294
void PaperRoller_HandleRollerCollisions(void)
295
{
296
RSDK_THIS(PaperRoller);
297
298
foreach_active(Player, player)
299
{
300
int32 playerID = RSDK.GetEntitySlot(player);
301
if (self->playerTimer[playerID] <= 0) {
302
int32 distX = abs(self->position.x - player->position.x) >> 16;
303
int32 distY = abs(self->position.y - player->position.y) >> 16;
304
if (MathHelpers_SquareRoot(distX * distX + distY * distY) <= 40 && !self->playerTimer[playerID]) {
305
RSDK.PlaySfx(Player->sfxRelease, false, 255);
306
int32 angle = RSDK.ATan2(player->position.x - self->position.x, player->position.y - self->position.y);
307
308
int32 ang = angle + (self->direction == FLIP_NONE ? 64 : -64);
309
310
player->position.x = self->position.x + 0x2800 * RSDK.Cos256(angle);
311
player->position.y = self->position.y + 0x2800 * RSDK.Sin256(angle);
312
player->velocity.x = RSDK.Cos256(ang) << 11;
313
player->velocity.y = RSDK.Sin256(ang) << 11;
314
player->state = Player_State_Air;
315
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
316
317
player->nextAirState = StateMachine_None;
318
player->nextGroundState = StateMachine_None;
319
player->onGround = false;
320
player->groundVel = 0;
321
// bug details: fixes a bug where knux can touch this without tile collisions enabled lol
322
#if GAME_VERSION != VER_100
323
player->tileCollisions = TILECOLLISION_DOWN;
324
#endif
325
player->applyJumpCap = false;
326
player->jumpAbilityState = 0;
327
328
self->playerTimer[playerID] = 10;
329
}
330
}
331
else {
332
self->playerTimer[playerID]--;
333
}
334
}
335
}
336
337
void PaperRoller_HandlePrintCollisions(void)
338
{
339
RSDK_THIS(PaperRoller);
340
341
bool32 hasDeformedTop = false;
342
bool32 hasDeformedBottom = false;
343
344
int32 negAngle = -self->angle;
345
self->deformPosTop.x = 0;
346
self->deformPosTop.y = 0;
347
self->deformPosBottom.x = 0;
348
self->deformPosBottom.y = 0;
349
350
foreach_active(Player, player)
351
{
352
int32 playerID = RSDK.GetEntitySlot(player);
353
354
if (player->jumpPress)
355
self->lastJumpTimer[playerID] = 0;
356
else
357
++self->lastJumpTimer[playerID];
358
359
Vector2 pivotPos = player->position;
360
Zone_RotateOnPivot(&pivotPos, &self->position, self->angle);
361
362
int32 pivotX = pivotPos.x - self->position.x;
363
int32 pivotY = pivotPos.y - self->position.y;
364
365
if (abs(pivotX) <= self->length << 15 && abs(pivotY) <= 0x280000) {
366
int32 deformY = 0;
367
if (pivotY < 0) {
368
if (abs(pivotY) > 0x180000) {
369
deformY = pivotY + 0x280000;
370
}
371
else {
372
Vector2 playerPos;
373
playerPos.x = self->position.x + pivotX;
374
playerPos.y = self->position.y - 0x180000;
375
Zone_RotateOnPivot(&playerPos, &self->position, negAngle);
376
377
Vector2 pivotPos = { 0, 0 };
378
player->position = playerPos;
379
380
Vector2 playerVel = player->velocity;
381
Zone_RotateOnPivot(&playerVel, &pivotPos, self->angle);
382
int32 angle = RSDK.ATan2(playerVel.x, -playerVel.y);
383
384
int32 force = player->jumpHold ? 12 : 6;
385
386
playerVel.x = force * (RSDK.Cos256(angle) << 8);
387
playerVel.y = force * (RSDK.Sin256(angle) << 8);
388
if (abs(playerVel.x) < 0x10000)
389
playerVel.x += ((2 * (self->direction == FLIP_NONE) - 1) << 16);
390
391
Zone_RotateOnPivot(&playerVel, &pivotPos, negAngle);
392
player->velocity = playerVel;
393
394
player->state = Player_State_Air;
395
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
396
397
player->nextAirState = StateMachine_None;
398
player->nextGroundState = StateMachine_None;
399
player->onGround = false;
400
player->groundVel = 0;
401
// bug details: fixes a bug where knux can touch this without tile collisions enabled lol
402
#if GAME_VERSION != VER_100
403
player->tileCollisions = TILECOLLISION_DOWN;
404
#endif
405
player->applyJumpCap = false;
406
player->jumpAbilityState = 0;
407
RSDK.PlaySfx(PaperRoller->sfxPaper, false, 0xFF);
408
409
deformY = 0x100000;
410
}
411
412
if (player->sidekick) {
413
if (!hasDeformedTop) {
414
self->deformPosTop.x = pivotX;
415
self->deformPosTop.y = deformY;
416
}
417
}
418
else {
419
self->deformPosTop.x = pivotX;
420
self->deformPosTop.y = deformY;
421
hasDeformedTop = true;
422
}
423
}
424
else {
425
if (abs(pivotY) > 0x180000) {
426
deformY = pivotY - 0x280000;
427
}
428
else {
429
Vector2 playerPos;
430
playerPos.x = self->position.x + pivotX;
431
playerPos.y = self->position.y + 0x180000;
432
Zone_RotateOnPivot(&playerPos, &self->position, negAngle);
433
434
Vector2 pivotPos = { 0, 0 };
435
player->position = playerPos;
436
437
Vector2 playerVel = player->velocity;
438
Zone_RotateOnPivot(&playerVel, &pivotPos, self->angle);
439
440
int32 angle = RSDK.ATan2(playerVel.x, -playerVel.y);
441
int32 force = player->jumpHold ? 12 : 6;
442
443
playerVel.x = force * (RSDK.Cos256(angle) << 8);
444
playerVel.y = force * (RSDK.Sin256(angle) << 8);
445
if ((self->direction == FLIP_NONE && playerVel.x > -0x10000) || (self->direction == FLIP_X && playerVel.x < 0x10000))
446
playerVel.x += ((2 * (self->direction != FLIP_NONE) - 1) << 18);
447
448
Zone_RotateOnPivot(&playerVel, &pivotPos, negAngle);
449
player->velocity = playerVel;
450
451
player->state = Player_State_Air;
452
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
453
454
player->nextAirState = StateMachine_None;
455
player->nextGroundState = StateMachine_None;
456
player->onGround = false;
457
player->groundVel = 0;
458
// bug details: fixes a bug where knux can touch this without tile collisions enabled lol
459
#if GAME_VERSION != VER_100
460
player->tileCollisions = TILECOLLISION_DOWN;
461
#endif
462
player->applyJumpCap = false;
463
player->jumpAbilityState = 0;
464
RSDK.PlaySfx(PaperRoller->sfxPaper, false, 0xFF);
465
466
deformY = -0x100000;
467
}
468
469
if (!player->sidekick) {
470
self->deformPosBottom.x = pivotX;
471
self->deformPosBottom.y = deformY;
472
hasDeformedBottom = true;
473
}
474
else if (!hasDeformedBottom) {
475
self->deformPosBottom.x = pivotX;
476
self->deformPosBottom.y = deformY;
477
}
478
}
479
}
480
}
481
}
482
483
#if GAME_INCLUDE_EDITOR
484
void PaperRoller_EditorDraw(void)
485
{
486
RSDK_THIS(PaperRoller);
487
488
self->drawGroup = Zone->objectDrawGroup[0];
489
self->startPos = self->position;
490
self->visible = true;
491
self->drawFX = FX_NONE;
492
self->updateRange.x = 0x800000;
493
self->updateRange.y = 0x800000;
494
495
int32 len = self->length;
496
497
self->updateRange.x += abs((RSDK.Cos256(self->angle) << 8) * self->length);
498
self->updateRange.y += abs((RSDK.Sin256(self->angle) << 8) * self->length);
499
500
if (self->length > 256)
501
self->length = 256;
502
503
RSDK.SetSpriteAnimation(PaperRoller->aniFrames, 0, &self->rollerAnimator, true, 0);
504
RSDK.SetSpriteAnimation(PaperRoller->aniFrames, 1, &self->divotAnimator, true, 0);
505
506
PaperRoller_DrawPaperLines();
507
PaperRoller_DrawRollers();
508
509
self->length = len;
510
}
511
512
void PaperRoller_EditorLoad(void)
513
{
514
PaperRoller_StageLoad();
515
516
RSDK_ACTIVE_VAR(PaperRoller, direction);
517
RSDK_ENUM_VAR("Right", FLIP_NONE);
518
RSDK_ENUM_VAR("Left", FLIP_X);
519
}
520
#endif
521
522
void PaperRoller_Serialize(void)
523
{
524
RSDK_EDITABLE_VAR(PaperRoller, VAR_UINT8, direction);
525
RSDK_EDITABLE_VAR(PaperRoller, VAR_ENUM, length);
526
RSDK_EDITABLE_VAR(PaperRoller, VAR_ENUM, angle);
527
}
528
529