Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/MSZ/CollapsingSand.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: CollapsingSand Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectCollapsingSand *CollapsingSand;
11
12
void CollapsingSand_Update(void)
13
{
14
RSDK_THIS(CollapsingSand);
15
16
self->visible = DebugMode->debugActive;
17
18
StateMachine_Run(self->state);
19
}
20
21
void CollapsingSand_LateUpdate(void) {}
22
23
void CollapsingSand_StaticUpdate(void) {}
24
25
void CollapsingSand_Draw(void)
26
{
27
RSDK_THIS(CollapsingSand);
28
Vector2 drawPos;
29
30
// Draw Outline
31
drawPos.x = self->position.x - (self->size.x >> 1);
32
drawPos.y = self->position.y - (self->size.y >> 1);
33
RSDK.DrawLine(drawPos.x - 0x10000, drawPos.y - 0x10000, drawPos.x + self->size.x, drawPos.y - 0x10000, 0xE0E0E0, 0, INK_NONE, false);
34
RSDK.DrawLine(drawPos.x - 0x10000, self->size.y + drawPos.y, drawPos.x + self->size.x, self->size.y + drawPos.y, 0xE0E0E0, 0, INK_NONE, false);
35
RSDK.DrawLine(drawPos.x - 0x10000, drawPos.y - 0x10000, drawPos.x - 0x10000, drawPos.y + self->size.y, 0xE0E0E0, 0, INK_NONE, false);
36
RSDK.DrawLine(drawPos.x + self->size.x, drawPos.y - 0x10000, drawPos.x + self->size.x, drawPos.y + self->size.y, 0xE0E0E0, 0, INK_NONE, false);
37
38
// Draw Corners
39
self->direction = FLIP_NONE;
40
RSDK.DrawSprite(&CollapsingSand->animator, &drawPos, false);
41
42
drawPos.x += self->size.x;
43
self->direction = FLIP_X;
44
RSDK.DrawSprite(&CollapsingSand->animator, &drawPos, false);
45
46
drawPos.y += self->size.y;
47
self->direction = FLIP_XY;
48
RSDK.DrawSprite(&CollapsingSand->animator, &drawPos, false);
49
50
drawPos.x -= self->size.x;
51
self->direction = FLIP_Y;
52
RSDK.DrawSprite(&CollapsingSand->animator, &drawPos, false);
53
}
54
55
void CollapsingSand_Create(void *data)
56
{
57
RSDK_THIS(CollapsingSand);
58
59
self->visible = true;
60
self->drawGroup = Zone->objectDrawGroup[0];
61
self->drawFX |= FX_FLIP;
62
self->position.x &= 0xFFF80000;
63
self->position.y &= 0xFFF80000;
64
65
if (!SceneInfo->inEditor) {
66
self->active = ACTIVE_BOUNDS;
67
self->updateRange.x = 0x800000;
68
self->updateRange.y = 0x800000;
69
self->hitbox.left = -(self->size.x >> 17);
70
self->hitbox.top = -48 - (self->size.y >> 17);
71
self->hitbox.right = self->size.x >> 17;
72
self->hitbox.bottom = self->size.y >> 17;
73
self->state = CollapsingSand_State_CheckPlayerCollisions;
74
}
75
}
76
77
void CollapsingSand_StageLoad(void)
78
{
79
CollapsingSand->aniFrames = RSDK.LoadSpriteAnimation("MSZ/SandCollapse.bin", SCOPE_STAGE);
80
RSDK.SetSpriteAnimation(CollapsingSand->aniFrames, 0, &CollapsingSand->animator, true, 0);
81
82
CollapsingSand->sfxSandFall = RSDK.GetSfx("MSZ/SandFall.wav");
83
}
84
85
void CollapsingSand_State_CheckPlayerCollisions(void)
86
{
87
RSDK_THIS(CollapsingSand);
88
89
foreach_active(Player, player)
90
{
91
if (Player_CheckCollisionTouch(player, self, &self->hitbox) && player->onGround && player->collisionMode) {
92
self->state = CollapsingSand_State_CollapseDelay;
93
self->collapseLeft = player->position.x <= self->position.x;
94
foreach_break;
95
}
96
}
97
}
98
99
void CollapsingSand_State_CollapseDelay(void)
100
{
101
RSDK_THIS(CollapsingSand);
102
103
if (self->collapseTimer >= self->delay) {
104
self->collapseDuration.x = self->size.x >> 20;
105
self->collapseDuration.y = self->size.y >> 20;
106
self->collapseTimer = 0;
107
108
if (!self->collapseLeft) {
109
self->state = CollapsingSand_State_CollapseRight;
110
self->tilePos.x = ((self->size.x >> 1) + self->position.x - 0x80000) >> 20;
111
}
112
else {
113
self->state = CollapsingSand_State_CollapseLeft;
114
self->tilePos.x = (self->position.x - (self->size.x >> 1) + 0x80000) >> 20;
115
}
116
RSDK.PlaySfx(CollapsingSand->sfxSandFall, false, 255);
117
118
self->tilePos.y = ((self->size.y >> 1) + self->position.y - 0x80000) >> 20;
119
self->tileEndPos.x = self->tilePos.x;
120
self->tileEndPos.y = (self->position.y - (self->size.y >> 1) + 0x80000) >> 20;
121
}
122
else {
123
self->collapseTimer++;
124
}
125
}
126
127
void CollapsingSand_State_CollapseLeft(void)
128
{
129
RSDK_THIS(CollapsingSand);
130
131
if (self->collapseTimer) {
132
self->collapseTimer = (self->collapseTimer + 1) & 3;
133
}
134
else {
135
if (self->collapseDuration.x > 0 || self->collapseDuration.y > 0) {
136
int32 tx = self->tilePos.x;
137
int32 ty = self->tilePos.y;
138
139
for (int32 x = (tx << 20) + 0x80000, y = (ty << 20) + 0x80000; tx >= self->tileEndPos.x && ty >= self->tileEndPos.y; --tx, --ty) {
140
bool32 spawnSand = false;
141
142
uint16 tile = RSDK.GetTile(Zone->fgLayer[0], tx, ty);
143
if ((tile & 0x3FF) >= 446 && (tile & 0x3FF) <= 554) {
144
RSDK.SetTile(Zone->fgLayer[0], tx, ty, -1);
145
spawnSand = true;
146
}
147
148
tile = RSDK.GetTile(Zone->fgLayer[1], tx, ty);
149
if ((tile & 0x3FF) >= 446 && (tile & 0x3FF) <= 554) {
150
RSDK.SetTile(Zone->fgLayer[1], tx, ty, -1);
151
spawnSand = true;
152
}
153
154
if (spawnSand) {
155
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, x, y);
156
RSDK.SetSpriteAnimation(CollapsingSand->aniFrames, 0, &debris->animator, true, 0);
157
debris->drawGroup = Zone->objectDrawGroup[1];
158
debris->timer = 44;
159
if (self->collapseDuration.x > 0) {
160
// Replace ground tile with a flat one
161
if (ty == self->tilePos.y)
162
RSDK.SetTile(Zone->fgLayer[0], tx, ty, (168 + (self->collapseDuration.x & 1)) | 0b1111000000000000);
163
}
164
}
165
166
x -= 0x100000;
167
y -= 0x100000;
168
}
169
170
if (self->collapseDuration.x > 0) {
171
++self->tilePos.x;
172
--self->collapseDuration.x;
173
}
174
else {
175
--self->tilePos.y;
176
--self->collapseDuration.y;
177
}
178
self->collapseTimer = (self->collapseTimer + 1) & 3;
179
}
180
else {
181
foreach_all(ItemBox, itembox)
182
{
183
if (abs(itembox->position.x - self->position.x) < self->size.x >> 1) {
184
if (abs(itembox->position.y - self->position.y >= 0) < self->size.y >> 1 && itembox->state == ItemBox_State_Idle)
185
itembox->state = ItemBox_State_Falling;
186
}
187
}
188
189
destroyEntity(self);
190
}
191
}
192
}
193
194
void CollapsingSand_State_CollapseRight(void)
195
{
196
RSDK_THIS(CollapsingSand);
197
198
if (self->collapseTimer) {
199
self->collapseTimer = (self->collapseTimer + 1) & 3;
200
}
201
else {
202
if (self->collapseDuration.x > 0 || self->collapseDuration.y > 0) {
203
int32 tx = self->tilePos.x;
204
int32 ty = self->tilePos.y;
205
206
for (int32 x = (tx << 20) + 0x80000, y = (ty << 20) + 0x80000; tx <= self->tileEndPos.x && ty >= self->tileEndPos.y; ++tx, --ty) {
207
bool32 spawnSand = false;
208
209
uint16 tile = RSDK.GetTile(Zone->fgLayer[0], tx, ty);
210
if ((tile & 0x3FF) >= 446 && (tile & 0x3FF) <= 554) {
211
RSDK.SetTile(Zone->fgLayer[0], tx, ty, -1);
212
spawnSand = true;
213
}
214
215
tile = RSDK.GetTile(Zone->fgLayer[1], tx, ty);
216
if ((tile & 0x3FF) >= 446 && (tile & 0x3FF) <= 554) {
217
RSDK.SetTile(Zone->fgLayer[1], tx, ty, -1);
218
spawnSand = true;
219
}
220
221
if (spawnSand) {
222
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_Move, x, y);
223
RSDK.SetSpriteAnimation(CollapsingSand->aniFrames, 0, &debris->animator, true, 0);
224
debris->drawGroup = Zone->objectDrawGroup[1];
225
debris->timer = 44;
226
if (self->collapseDuration.x > 0) {
227
// Replace ground tile with a flat one
228
if (ty == self->tilePos.y)
229
RSDK.SetTile(Zone->fgLayer[0], tx, ty, (169 - (self->collapseDuration.x & 1)) | 0b1111000000000000);
230
}
231
}
232
233
x += 0x100000;
234
y -= 0x100000;
235
}
236
237
if (self->collapseDuration.x > 0) {
238
--self->tilePos.x;
239
--self->collapseDuration.x;
240
}
241
else {
242
--self->tilePos.y;
243
--self->collapseDuration.y;
244
}
245
246
self->collapseTimer = (self->collapseTimer + 1) & 3;
247
}
248
else {
249
foreach_all(ItemBox, itembox)
250
{
251
if (abs(itembox->position.x - self->position.x) < self->size.x >> 1) {
252
if (abs(itembox->position.y - self->position.y >= 0) < self->size.y >> 1 && itembox->state == ItemBox_State_Idle)
253
itembox->state = ItemBox_State_Falling;
254
}
255
}
256
destroyEntity(self);
257
}
258
}
259
}
260
261
#if GAME_INCLUDE_EDITOR
262
void CollapsingSand_EditorDraw(void) { CollapsingSand_Draw(); }
263
264
void CollapsingSand_EditorLoad(void)
265
{
266
CollapsingSand->aniFrames = RSDK.LoadSpriteAnimation("MSZ/SandCollapse.bin", SCOPE_STAGE);
267
RSDK.SetSpriteAnimation(CollapsingSand->aniFrames, 0, &CollapsingSand->animator, true, 0);
268
}
269
#endif
270
271
void CollapsingSand_Serialize(void)
272
{
273
RSDK_EDITABLE_VAR(CollapsingSand, VAR_VECTOR2, size);
274
RSDK_EDITABLE_VAR(CollapsingSand, VAR_ENUM, delay);
275
}
276
277