Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/PGZ/Press.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Press Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPress *Press;
11
12
void Press_Update(void)
13
{
14
RSDK_THIS(Press);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Press_LateUpdate(void) {}
20
21
void Press_StaticUpdate(void)
22
{
23
#if MANIA_USE_PLUS
24
Press->canSuper = true;
25
EntityPlayer *player = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
26
27
if (player->classID == Player->classID) {
28
foreach_active(Press, press)
29
{
30
Hitbox hitboxRange;
31
hitboxRange.top = -4 * press->size;
32
hitboxRange.bottom = 4 * press->size;
33
hitboxRange.left = -112;
34
hitboxRange.right = 112;
35
if (Player_CheckCollisionTouch(player, press, &hitboxRange)) {
36
Press->canSuper = false;
37
foreach_break;
38
}
39
}
40
}
41
else
42
Press->canSuper = false;
43
#endif
44
}
45
46
void Press_Draw(void)
47
{
48
RSDK_THIS(Press);
49
50
if (self->rotation <= 0x100)
51
Press_DrawHandle();
52
53
// threads
54
Vector2 drawPos = self->drawPos;
55
SpriteFrame *frame = RSDK.GetFrame(Press->aniFrames, 1, self->threadAnimator.frameID);
56
frame->height = 56;
57
frame->sprY = (self->threadSprY >> 8) + 182;
58
for (uint32 i = 0; i < self->threads; ++i) {
59
RSDK.DrawSprite(&self->threadAnimator, &drawPos, false);
60
drawPos.y += 0x380000;
61
}
62
frame->height = self->height;
63
RSDK.DrawSprite(&self->threadAnimator, &drawPos, false);
64
65
// crusher platforms
66
drawPos = self->position;
67
drawPos.y += self->offTop;
68
self->crusherAnimator.frameID = 3;
69
RSDK.DrawSprite(&self->crusherAnimator, &drawPos, false);
70
71
self->crusherAnimator.frameID = 4;
72
RSDK.DrawSprite(&self->crusherAnimator, &drawPos, false);
73
74
drawPos.y -= self->offTop;
75
drawPos.y += self->offBottom;
76
self->crusherAnimator.frameID = 3;
77
RSDK.DrawSprite(&self->crusherAnimator, &drawPos, false);
78
79
self->crusherAnimator.frameID = 5;
80
RSDK.DrawSprite(&self->crusherAnimator, &drawPos, false);
81
82
// bumper
83
drawPos.y = self->drawPos.y - 0x80000;
84
RSDK.DrawSprite(&self->bumperAnimator, &drawPos, false);
85
86
drawPos.y += (self->size + 16) << 16;
87
RSDK.DrawSprite(&self->bumperAnimator, &drawPos, false);
88
89
if (self->rotation > 0x100)
90
Press_DrawHandle();
91
}
92
93
void Press_Create(void *data)
94
{
95
RSDK_THIS(Press);
96
97
self->active = ACTIVE_BOUNDS;
98
self->visible = true;
99
self->drawGroup = Zone->objectDrawGroup[0];
100
101
if (!SceneInfo->inEditor) {
102
self->size *= 8;
103
int32 size = self->size;
104
self->speed <<= 15;
105
int32 step = size / 7;
106
int32 count = (size - step) / 2;
107
self->threads = (step + count) / 32;
108
self->scale.y = 0x200;
109
self->height = size - 0x38 * self->threads;
110
111
size <<= 15;
112
self->updateRange.x = 0x1000000;
113
self->updateRange.y = 0x380000 * self->threads + 0x1000000;
114
self->drawPos.x = self->position.x;
115
self->drawPos.y = self->position.y - size;
116
self->offTop = (self->offTop << 16) - size;
117
self->offBottom = (self->offBottom << 16) - size + 0xFFFF;
118
119
RSDK.SetSpriteAnimation(Press->aniFrames, 0, &self->crusherAnimator, true, 0);
120
RSDK.SetSpriteAnimation(Press->aniFrames, 1, &self->threadAnimator, true, 0);
121
RSDK.SetSpriteAnimation(Press->aniFrames, 2, &self->bumperAnimator, true, 0);
122
self->state = Press_State_Crush;
123
}
124
}
125
126
void Press_StageLoad(void)
127
{
128
if (RSDK.CheckSceneFolder("PSZ1"))
129
Press->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Press.bin", SCOPE_STAGE);
130
131
Press->hitbox.left = -112;
132
Press->hitbox.top = -16;
133
Press->hitbox.right = 112;
134
Press->hitbox.bottom = 16;
135
136
#if MANIA_USE_PLUS
137
Player->canSuperCB = Press_CheckCanSuper;
138
#endif
139
140
Press->sfxImpact = RSDK.GetSfx("Stage/Impact2.wav");
141
Press->sfxPress = RSDK.GetSfx("PSZ/Press.wav");
142
}
143
144
#if MANIA_USE_PLUS
145
bool32 Press_CheckCanSuper(bool32 isHUD) { return Press->canSuper; }
146
#endif
147
148
void Press_DrawHandle(void)
149
{
150
RSDK_THIS(Press);
151
152
Vector2 drawPos = self->drawPos;
153
154
self->scale.x = abs(RSDK.Cos512(self->rotation)) + 1;
155
int32 scaleX = abs(RSDK.Sin512(self->rotation)) + 1;
156
157
drawPos.x += 0x2500 * RSDK.Cos512(self->rotation);
158
drawPos.y -= 0x80000;
159
self->crusherAnimator.frameID = 0;
160
RSDK.DrawSprite(&self->crusherAnimator, &drawPos, false);
161
162
self->drawFX |= FX_SCALE;
163
drawPos.x = 0x1B80 * RSDK.Cos512(self->rotation) + self->drawPos.x;
164
165
switch (self->rotation >> 7) {
166
case 0:
167
case 2:
168
drawPos.x += (scaleX << 9);
169
self->crusherAnimator.frameID = 2;
170
RSDK.DrawSprite(&self->crusherAnimator, &drawPos, false);
171
172
drawPos.x += -0xC00 * self->scale.x - (scaleX << 9);
173
break;
174
175
case 1:
176
case 3:
177
drawPos.x -= (scaleX << 9);
178
self->crusherAnimator.frameID = 2;
179
RSDK.DrawSprite(&self->crusherAnimator, &drawPos, false);
180
181
drawPos.x += (scaleX + 2 * (3 * self->scale.x - 32)) << 9;
182
break;
183
184
default: break;
185
}
186
187
self->scale.x = scaleX;
188
self->crusherAnimator.frameID = 1;
189
RSDK.DrawSprite(&self->crusherAnimator, &drawPos, false);
190
191
self->drawFX &= ~FX_SCALE;
192
}
193
194
void Press_Move(void)
195
{
196
RSDK_THIS(Press);
197
198
self->stoodPlayersRoof = 0;
199
self->stoodPlayersFloor = 0;
200
201
int32 playerID = 0;
202
foreach_active(Player, player)
203
{
204
self->position.y += self->offBottom;
205
206
if (Player_CheckCollisionBox(player, self, &Press->hitbox) == C_TOP) {
207
if (self->state == Press_State_Crush && !player->sidekick) {
208
if (abs(self->position.x - player->position.x) <= 0x600000) {
209
RSDK.PlaySfx(Press->sfxPress, false, 255);
210
self->state = Press_HandleMovement;
211
self->active = ACTIVE_NORMAL;
212
}
213
}
214
215
self->stoodPlayersFloor |= 1 << playerID;
216
}
217
218
self->position.y += self->offTop - self->offBottom;
219
220
int32 collide = Player_CheckCollisionBox(player, self, &Press->hitbox);
221
if (collide == C_BOTTOM)
222
player->collisionFlagV |= 2;
223
else if (collide == C_TOP)
224
self->stoodPlayersRoof |= 1 << playerID;
225
226
++playerID;
227
self->position.y -= self->offTop;
228
}
229
}
230
231
void Press_State_Crush(void)
232
{
233
// fun press fact!
234
Press_Move();
235
}
236
void Press_State_FinalCrush(void)
237
{
238
// every second you don't move the press only gets closer
239
Press_Move();
240
}
241
void Press_HandleMovement(void)
242
{
243
RSDK_THIS(Press);
244
245
RSDK.ProcessAnimation(&self->threadAnimator);
246
RSDK.ProcessAnimation(&self->bumperAnimator);
247
248
Press_Move();
249
250
int32 oldBottom = self->offBottom;
251
int32 newBottom = oldBottom - self->speed;
252
self->offBottom = oldBottom - self->speed;
253
254
self->threadSprY += (self->speed >> 11);
255
self->threadSprY &= 0x7FF;
256
257
int32 oldTop = self->offTop;
258
int32 newTop = self->speed + self->offTop + self->topOffset;
259
260
self->rotation = (self->rotation - (self->speed >> 15)) & 0x1FF;
261
self->offTop = newTop;
262
self->topOffset = 0;
263
264
if (newTop + 0x100000 >= newBottom - 0x100000) {
265
int32 diff = newTop - newBottom + 0x200000;
266
if (diff > 0) {
267
diff >>= 1;
268
self->offTop = newTop - diff;
269
self->offBottom = newBottom + diff;
270
}
271
272
RSDK.PlaySfx(Press->sfxImpact, false, 255);
273
self->active = ACTIVE_BOUNDS;
274
Camera_ShakeScreen(0, 0, 5);
275
self->state = Press_State_FinalCrush;
276
}
277
278
uint32 waitTime = 0;
279
self->topOffset = self->offTop;
280
281
bool32 top = false, bottom = false;
282
int32 floorOffset = (oldBottom & 0xFFFF0000) - (self->offBottom & 0xFFFF0000);
283
int32 actualPos = self->position.y;
284
285
foreach_active(Crate, crate)
286
{
287
self->position.y += self->offBottom;
288
289
if (MathHelpers_CheckBoxCollision(self, &Press->hitbox, crate, &crate->hitbox) == C_TOP) {
290
bottom = true;
291
Crate_MoveY(crate, -floorOffset);
292
}
293
294
self->position.y += self->offTop - self->offBottom;
295
if (MathHelpers_CheckBoxCollision(crate, &crate->hitbox, self, &Press->hitbox) == C_TOP) {
296
top = true;
297
298
switch (crate->frameID) {
299
default: break;
300
case 0: waitTime += 60; break;
301
case 1: waitTime += 30; break;
302
case 2: waitTime += 90; break;
303
case 3: waitTime += 60; break;
304
}
305
}
306
307
self->offTop = self->position.y - actualPos;
308
self->position.y = actualPos;
309
}
310
311
self->topOffset -= self->offTop;
312
313
if (bottom && top) {
314
RSDK.PlaySfx(Press->sfxImpact, false, 255);
315
Camera_ShakeScreen(0, 0, 3);
316
317
self->state = Press_State_HandleCrates;
318
self->timerStart = waitTime;
319
self->timer = waitTime;
320
}
321
322
int32 playerID = 1;
323
int32 roofOffset = (oldTop & 0xFFFF0000) - (self->offTop & 0xFFFF0000);
324
foreach_active(Player, player)
325
{
326
if (playerID & self->stoodPlayersFloor)
327
player->position.y -= floorOffset;
328
if (playerID & self->stoodPlayersRoof)
329
player->position.y -= roofOffset;
330
331
playerID <<= 1;
332
}
333
}
334
335
void Press_State_HandleCrates(void)
336
{
337
RSDK_THIS(Press);
338
339
Press_Move();
340
341
if (self->timer <= 0) {
342
foreach_active(Crate, crate)
343
{
344
self->position.y += self->offTop + 0x80000;
345
346
if (RSDK.CheckObjectCollisionTouchBox(self, &Press->hitbox, crate, &crate->hitbox))
347
Crate_Break(crate);
348
349
self->position.y += -0x80000 - self->offTop;
350
}
351
352
self->state = Press_HandleMovement;
353
}
354
else {
355
int32 percentDone = ((self->timerStart - self->timer) << 16) / self->timerStart;
356
int32 crateOff = 0;
357
358
foreach_active(Crate, crate)
359
{
360
self->position.y += self->offTop + 0x80000;
361
if (RSDK.CheckObjectCollisionTouchBox(self, &Press->hitbox, crate, &crate->hitbox) && percentDone > 0x8000) {
362
int32 percent = percentDone >> 9;
363
int32 percent2 = percent * percent;
364
int32 angle = crateOff + ((percent * self->timerStart * (percent2 >> 8)) >> 8);
365
366
crateOff += 0x100;
367
crate->drawPos.x = (RSDK.Sin512(angle & 0x1FF) << 7) + crate->centerPos.x;
368
}
369
370
self->position.y += -0x80000 - self->offTop;
371
}
372
373
--self->timer;
374
}
375
}
376
377
#if GAME_INCLUDE_EDITOR
378
void Press_EditorDraw(void)
379
{
380
RSDK_THIS(Press);
381
382
int32 sizeStore = self->size;
383
int32 offT = self->offTop;
384
int32 offB = self->offBottom;
385
386
self->size *= 8;
387
int32 size = self->size;
388
389
int32 step = size / 7;
390
int32 count = (size - step) / 2;
391
self->threads = (step + count) / 32;
392
self->scale.y = 0x200;
393
self->height = size - 0x38 * self->threads;
394
395
size <<= 15;
396
self->updateRange.x = 0x1000000;
397
self->updateRange.y = 0x380000 * self->threads + 0x1000000;
398
self->drawPos.x = self->position.x;
399
self->drawPos.y = self->position.y - size;
400
self->offTop = (self->offTop << 16) - size;
401
self->offBottom = (self->offBottom << 16) - size + 0xFFFF;
402
403
RSDK.SetSpriteAnimation(Press->aniFrames, 0, &self->crusherAnimator, true, 0);
404
RSDK.SetSpriteAnimation(Press->aniFrames, 1, &self->threadAnimator, true, 0);
405
RSDK.SetSpriteAnimation(Press->aniFrames, 2, &self->bumperAnimator, true, 0);
406
407
Press_Draw();
408
409
self->size = sizeStore;
410
self->offTop = offT;
411
self->offBottom = offB;
412
}
413
414
void Press_EditorLoad(void) { Press->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Press.bin", SCOPE_STAGE); }
415
#endif
416
417
void Press_Serialize(void)
418
{
419
RSDK_EDITABLE_VAR(Press, VAR_UINT16, size);
420
RSDK_EDITABLE_VAR(Press, VAR_UINT32, speed);
421
RSDK_EDITABLE_VAR(Press, VAR_ENUM, offTop);
422
RSDK_EDITABLE_VAR(Press, VAR_ENUM, offBottom);
423
}
424
425