Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/PGZ/Crate.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Crate Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectCrate *Crate;
11
12
void Crate_Update(void)
13
{
14
RSDK_THIS(Crate);
15
16
if (self->collision != PLATFORM_C_SOLID || !Crate_Collide()) {
17
if (self->animator.animationID) {
18
StateMachine_Run(self->state);
19
}
20
else {
21
Platform_Update();
22
}
23
}
24
}
25
26
void Crate_LateUpdate(void) {}
27
28
void Crate_StaticUpdate(void) {}
29
30
void Crate_Draw(void)
31
{
32
RSDK_THIS(Crate);
33
RSDK.DrawSprite(&self->animator, &self->drawPos, false);
34
}
35
36
void Crate_Create(void *data)
37
{
38
RSDK_THIS(Crate);
39
40
int32 frameID = self->frameID;
41
if (frameID == 3)
42
self->collision = PLATFORM_C_NONE;
43
else
44
self->collision = PLATFORM_C_SOLID;
45
46
Platform_Create(NULL);
47
self->frameID = frameID;
48
49
if (!SceneInfo->inEditor) {
50
self->hitbox.left = -24;
51
self->hitbox.top = -24;
52
self->hitbox.right = 24;
53
self->hitbox.bottom = 24;
54
55
self->active = ACTIVE_XBOUNDS;
56
self->drawFX = FX_SCALE | FX_FLIP;
57
self->scale.x = 0x200;
58
self->scale.y = 0x200;
59
self->drawGroup = frameID == 3 ? Zone->objectDrawGroup[0] : Zone->objectDrawGroup[1];
60
RSDK.SetSpriteAnimation(Crate->aniFrames, 0, &self->animator, true, frameID);
61
self->state = Crate_State_None;
62
}
63
}
64
65
void Crate_StageLoad(void)
66
{
67
if (RSDK.CheckSceneFolder("PSZ1"))
68
Crate->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Crate.bin", SCOPE_STAGE);
69
70
Crate->sfxExplosion2 = RSDK.GetSfx("Stage/Explosion2.wav");
71
}
72
73
void Crate_Break(EntityCrate *create)
74
{
75
for (int32 s = 0; s < 64; ++s) {
76
// ice is used to create a shattering effect
77
int32 x = create->position.x + (RSDK.Rand(-24, 25) << 16);
78
int32 y = create->position.y + (RSDK.Rand(-24, 25) << 16);
79
EntityIce *ice = CREATE_ENTITY(Ice, INT_TO_VOID(ICE_CHILD_SHARD), x, y);
80
81
ice->velocity.x = RSDK.Rand(-6, 8) << 15;
82
ice->velocity.y = RSDK.Rand(-10, 2) << 15;
83
ice->direction = RSDK.Rand(0, 4);
84
ice->blockAnimator.speed = RSDK.Rand(1, 4);
85
ice->drawGroup = Zone->objectDrawGroup[0] + 1;
86
87
switch (create->animator.frameID) {
88
case 0:
89
case 3: RSDK.SetSpriteAnimation(Crate->aniFrames, 1, &ice->blockAnimator, true, 0); break;
90
91
case 1:
92
case 2:
93
if (RSDK.Rand(0, 6) >= 2)
94
RSDK.SetSpriteAnimation(Crate->aniFrames, 2, &ice->blockAnimator, true, 0);
95
else
96
RSDK.SetSpriteAnimation(Crate->aniFrames, 3, &ice->blockAnimator, true, 0);
97
break;
98
99
default: break;
100
}
101
}
102
103
RSDK.PlaySfx(Crate->sfxExplosion2, false, 255);
104
create->position.y -= 0x10000;
105
106
foreach_active(Crate, crate)
107
{
108
if (crate != create && crate->state == Crate_State_None
109
&& RSDK.CheckObjectCollisionTouchBox(create, &create->hitbox, crate, &crate->hitbox)) {
110
crate->state = Crate_State_ApplyGravity;
111
}
112
}
113
114
destroyEntity(create);
115
}
116
void Crate_MoveY(EntityCrate *self, int32 offset)
117
{
118
self->drawPos.y += offset;
119
self->centerPos.x = self->drawPos.x;
120
self->centerPos.y = self->drawPos.y;
121
self->position.x = self->drawPos.x;
122
self->position.y = self->drawPos.y;
123
124
int32 start = (self->drawPos.y - 0x300000) & 0xFFFF0000;
125
foreach_active(Crate, crate)
126
{
127
if (crate != self && RSDK.CheckObjectCollisionBox(self, &self->hitbox, crate, &crate->hitbox, true) == C_TOP)
128
Crate_MoveY(crate, start - crate->drawPos.y);
129
}
130
}
131
bool32 Crate_Collide(void)
132
{
133
RSDK_THIS(Crate);
134
135
foreach_active(Player, player)
136
{
137
int32 storeX = player->position.x;
138
int32 storeY = player->position.y;
139
int32 storeXVel = player->velocity.x;
140
int32 storeYVel = player->velocity.y;
141
int32 storeVel = player->groundVel;
142
int32 storeGrounded = player->onGround;
143
Hitbox *playerHitbox = Player_GetHitbox(player);
144
145
int32 shieldAnim = RSDK_GET_ENTITY(Player->playerCount + RSDK.GetEntitySlot(player), Shield)->shieldAnimator.animationID;
146
147
switch (MathHelpers_CheckBoxCollision(self, &self->hitbox, player, playerHitbox)) {
148
default:
149
case C_NONE:
150
player->velocity.x = storeXVel;
151
player->velocity.y = storeYVel;
152
player->position.x = storeX;
153
player->position.y = storeY;
154
Player_CheckCollisionBox(player, self, &self->hitbox);
155
break;
156
157
case C_TOP:
158
if (self->frameID != 1) {
159
player->velocity.x = storeXVel;
160
player->velocity.y = storeYVel;
161
player->position.x = storeX;
162
player->position.y = storeY;
163
Player_CheckCollisionBox(player, self, &self->hitbox);
164
break;
165
}
166
#if MANIA_USE_PLUS
167
else if (player->state == Player_State_MightyHammerDrop) {
168
player->velocity.y -= 0x10000;
169
Crate_Break(self);
170
player->velocity.x = storeXVel;
171
player->velocity.y = storeYVel;
172
player->position.x = storeX;
173
player->position.y = storeY;
174
player->groundVel = storeVel;
175
player->onGround = storeGrounded;
176
foreach_return true;
177
}
178
#endif
179
else if (player->shield == SHIELD_BUBBLE && player->invincibleTimer <= 0) {
180
if (shieldAnim == 8 && player->velocity.y >= 0x80000) {
181
Crate_Break(self);
182
player->velocity.x = storeXVel;
183
player->velocity.y = storeYVel;
184
player->position.x = storeX;
185
player->position.y = storeY;
186
player->groundVel = storeVel;
187
player->onGround = storeGrounded;
188
foreach_return true;
189
}
190
}
191
192
player->velocity.x = storeXVel;
193
player->velocity.y = storeYVel;
194
player->position.x = storeX;
195
player->position.y = storeY;
196
Player_CheckCollisionBox(player, self, &self->hitbox);
197
break;
198
199
case C_LEFT:
200
case C_RIGHT:
201
if (self->frameID != 1 || player->shield != SHIELD_FIRE || player->invincibleTimer > 0 || shieldAnim != 2) {
202
player->velocity.x = storeXVel;
203
player->velocity.y = storeYVel;
204
player->position.x = storeX;
205
player->position.y = storeY;
206
Player_CheckCollisionBox(player, self, &self->hitbox);
207
}
208
else if (player->position.x < self->position.x) {
209
player->velocity.x = storeXVel;
210
player->velocity.y = storeYVel;
211
player->position.x = storeX;
212
player->position.y = storeY;
213
214
if (player->velocity.x >= 0x78000) {
215
Crate_Break(self);
216
player->groundVel = storeVel;
217
player->onGround = storeGrounded;
218
foreach_return true;
219
}
220
else {
221
Player_CheckCollisionBox(player, self, &self->hitbox);
222
}
223
}
224
else {
225
player->velocity.x = storeXVel;
226
player->velocity.y = storeYVel;
227
player->position.x = storeX;
228
player->position.y = storeY;
229
230
if (player->velocity.x <= -0x78000) {
231
Crate_Break(self);
232
233
player->groundVel = storeVel;
234
player->onGround = storeGrounded;
235
foreach_return true;
236
}
237
else {
238
Player_CheckCollisionBox(player, self, &self->hitbox);
239
}
240
}
241
break;
242
243
case C_BOTTOM:
244
if (self->collisionOffset.y >= 0)
245
player->collisionFlagV |= 2;
246
247
player->velocity.x = storeXVel;
248
player->velocity.y = storeYVel;
249
player->position.x = storeX;
250
player->position.y = storeY;
251
Player_CheckCollisionBox(player, self, &self->hitbox);
252
break;
253
}
254
}
255
256
return false;
257
}
258
void Crate_State_None(void)
259
{
260
// hehe
261
}
262
void Crate_State_ApplyGravity(void)
263
{
264
RSDK_THIS(Crate);
265
266
self->position.y -= 0x10000;
267
268
foreach_active(Crate, crate)
269
{
270
if (crate != self && crate->state == Crate_State_None && RSDK.CheckObjectCollisionTouchBox(self, &self->hitbox, crate, &crate->hitbox)) {
271
crate->state = Crate_State_ApplyGravity;
272
}
273
}
274
275
self->position.y += 0x10000;
276
self->timer = 15;
277
self->state = Crate_State_WaitToFall;
278
}
279
void Crate_State_WaitToFall(void)
280
{
281
RSDK_THIS(Crate);
282
283
if (--self->timer <= 0)
284
self->state = Crate_State_Fall;
285
}
286
void Crate_State_Fall(void)
287
{
288
RSDK_THIS(Crate);
289
290
self->drawPos.y += self->velocity.y;
291
292
int32 x = self->position.x;
293
int32 y = self->position.y;
294
295
self->velocity.y += 0x3800;
296
self->position.x = self->drawPos.x;
297
self->position.y = self->drawPos.y;
298
299
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, 0, CMODE_FLOOR, 0, 0x180000, true)) {
300
self->velocity.y = 0;
301
self->state = Crate_State_None;
302
}
303
else {
304
foreach_active(Crate, crate)
305
{
306
if (crate != self && !crate->velocity.y && RSDK.CheckObjectCollisionBox(crate, &crate->hitbox, self, &self->hitbox, true) == C_TOP) {
307
self->velocity.y = 0;
308
self->state = Crate_State_None;
309
}
310
}
311
}
312
313
self->drawPos.x = self->position.x;
314
self->drawPos.y = self->position.y;
315
self->centerPos.x = self->position.x;
316
self->centerPos.y = self->position.y;
317
318
self->position.x = x;
319
self->position.y = y;
320
}
321
322
#if GAME_INCLUDE_EDITOR
323
void Crate_EditorDraw(void)
324
{
325
RSDK_THIS(Crate);
326
327
RSDK.SetSpriteAnimation(Crate->aniFrames, 0, &self->animator, true, self->frameID);
328
self->drawPos = self->position;
329
330
Crate_Draw();
331
332
if (showGizmos()) {
333
RSDK_DRAWING_OVERLAY(true);
334
335
for (int32 s = SceneInfo->entitySlot + 1, i = 0; i < self->childCount; ++i) {
336
Entity *child = RSDK_GET_ENTITY_GEN(s + i);
337
if (!child)
338
continue;
339
340
DrawHelpers_DrawArrow(self->position.x, self->position.y, child->position.x, child->position.y, 0xE0E0E0, INK_NONE, 0xFF);
341
}
342
343
RSDK_DRAWING_OVERLAY(false);
344
}
345
}
346
347
void Crate_EditorLoad(void)
348
{
349
Crate->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Crate.bin", SCOPE_STAGE);
350
351
RSDK_ACTIVE_VAR(Crate, frameID);
352
RSDK_ENUM_VAR("Blue", CRATE_FRAME_BLUE);
353
RSDK_ENUM_VAR("Orange (Broken)", CRATE_FRAME_ORANGE_BROKEN);
354
RSDK_ENUM_VAR("Orange", CRATE_FRAME_ORANGE);
355
RSDK_ENUM_VAR("Blue (BG)", CRATE_FRAME_BLUE_BG);
356
}
357
#endif
358
359
void Crate_Serialize(void)
360
{
361
RSDK_EDITABLE_VAR(Crate, VAR_UINT8, frameID);
362
RSDK_EDITABLE_VAR(Crate, VAR_ENUM, childCount);
363
RSDK_EDITABLE_VAR(Crate, VAR_BOOL, ignoreItemBox);
364
}
365
366