Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/MMZ/Scarab.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Scarab Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectScarab *Scarab;
11
12
void Scarab_Update(void)
13
{
14
RSDK_THIS(Scarab);
15
16
RSDK.ProcessAnimation(&self->bodyAnimator);
17
RSDK.ProcessAnimation(&self->backLegAnimator);
18
RSDK.ProcessAnimation(&self->frontLegAnimator);
19
20
self->moveOffset.x = -self->position.x;
21
self->moveOffset.y = -self->position.y;
22
23
StateMachine_Run(self->state);
24
25
self->moveOffset.x += self->position.x;
26
self->moveOffset.y += self->position.y;
27
28
Scarab_CheckPlayerCollisions();
29
Scarab_HandleChildMove();
30
Scarab_HandlePlayerGrab();
31
32
if (self->state != Scarab_State_Init) {
33
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
34
int32 x = -self->position.x;
35
int32 y = -self->position.y;
36
37
self->direction = self->startDir;
38
self->position = self->startPos;
39
self->moveOffset.x = self->position.x + x;
40
self->moveOffset.y = self->position.y + y;
41
42
Scarab_HandleChildMove();
43
Scarab_Create(NULL);
44
}
45
}
46
}
47
48
void Scarab_LateUpdate(void) {}
49
50
void Scarab_StaticUpdate(void)
51
{
52
foreach_active(Scarab, scarab) { RSDK.AddDrawListRef(scarab->drawGroupHigh, RSDK.GetEntitySlot(scarab)); }
53
}
54
55
void Scarab_Draw(void)
56
{
57
RSDK_THIS(Scarab);
58
59
if (SceneInfo->currentDrawGroup == self->drawGroupHigh) {
60
RSDK.DrawSprite(&self->frontLegAnimator, NULL, false);
61
}
62
else {
63
RSDK.DrawSprite(&self->backLegAnimator, NULL, false);
64
RSDK.DrawSprite(&self->bodyAnimator, NULL, false);
65
}
66
}
67
68
void Scarab_Create(void *data)
69
{
70
RSDK_THIS(Scarab);
71
72
self->visible = true;
73
self->drawGroup = Zone->objectDrawGroup[0];
74
75
if (self->planeFilter == PLANEFILTER_NONE) {
76
self->drawGroupLow = Zone->objectDrawGroup[0];
77
self->drawGroupHigh = Zone->playerDrawGroup[1];
78
}
79
else if ((uint8)(self->planeFilter - 1) & 2) {
80
self->drawGroupLow = Zone->objectDrawGroup[1];
81
self->drawGroupHigh = Zone->playerDrawGroup[1];
82
}
83
else {
84
self->drawGroupLow = Zone->objectDrawGroup[0];
85
self->drawGroupHigh = Zone->playerDrawGroup[0];
86
}
87
88
self->drawFX = FX_FLIP;
89
self->active = ACTIVE_BOUNDS;
90
self->updateRange.x = 0x800000;
91
self->updateRange.y = 0x800000;
92
93
if (!self->amplitude)
94
self->amplitude = 100;
95
96
self->startPos = self->position;
97
self->startDir = self->direction;
98
self->state = Scarab_State_Init;
99
}
100
101
void Scarab_StageLoad(void)
102
{
103
if (RSDK.CheckSceneFolder("MMZ"))
104
Scarab->aniFrames = RSDK.LoadSpriteAnimation("MMZ/Scarab.bin", SCOPE_STAGE);
105
106
Scarab->hitboxBadnik.left = -16;
107
Scarab->hitboxBadnik.top = -14;
108
Scarab->hitboxBadnik.right = 14;
109
Scarab->hitboxBadnik.bottom = 6;
110
111
Scarab->hitboxGrab.left = -48;
112
Scarab->hitboxGrab.top = -14;
113
Scarab->hitboxGrab.right = -17;
114
Scarab->hitboxGrab.bottom = 6;
115
116
Scarab->active = ACTIVE_ALWAYS;
117
118
DEBUGMODE_ADD_OBJ(Scarab);
119
}
120
121
void Scarab_DebugSpawn(void)
122
{
123
RSDK_THIS(Scarab);
124
125
EntityScarab *scarab = CREATE_ENTITY(Scarab, NULL, self->position.x, self->position.y);
126
scarab->direction = self->direction;
127
scarab->startDir = self->direction;
128
}
129
130
void Scarab_DebugDraw(void)
131
{
132
RSDK.SetSpriteAnimation(Scarab->aniFrames, 4, &DebugMode->animator, true, 0);
133
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
134
135
RSDK.SetSpriteAnimation(Scarab->aniFrames, 0, &DebugMode->animator, true, 0);
136
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
137
138
RSDK.SetSpriteAnimation(Scarab->aniFrames, 2, &DebugMode->animator, true, 0);
139
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
140
}
141
142
void Scarab_CheckPlayerCollisions(void)
143
{
144
RSDK_THIS(Scarab);
145
146
foreach_active(Player, player)
147
{
148
if (self->planeFilter <= 0 || player->collisionPlane == ((uint8)(self->planeFilter - 1) & 1)) {
149
int32 playerID = RSDK.GetEntitySlot(player);
150
if (Player_CheckBadnikTouch(player, self, &Scarab->hitboxBadnik)) {
151
Scarab_HandlePlayerRelease();
152
Player_CheckBadnikBreak(player, self, true);
153
}
154
155
if (!self->childCount) {
156
if (Player_CheckCollisionTouch(player, self, &Scarab->hitboxGrab)) {
157
if (!((1 << playerID) & self->grabbedPlayers) && !self->playerTimers[playerID]) {
158
self->grabbedPlayers |= 1 << playerID;
159
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
160
player->groundVel = 0;
161
player->onGround = false;
162
player->tileCollisions = TILECOLLISION_NONE;
163
player->state = Player_State_Static;
164
player->nextAirState = StateMachine_None;
165
player->nextGroundState = StateMachine_None;
166
self->isPermanent = true;
167
}
168
}
169
}
170
}
171
}
172
}
173
174
void Scarab_HandleChildMove(void)
175
{
176
RSDK_THIS(Scarab);
177
178
int32 slot = SceneInfo->entitySlot + 1;
179
for (int32 c = 0; c < self->childCount; ++c) {
180
EntityItemBox *child = RSDK_GET_ENTITY(slot + c, ItemBox);
181
child->position.x += self->moveOffset.x;
182
child->position.y += self->moveOffset.y;
183
184
if (child->classID == ItemBox->classID)
185
child->moveOffset = self->moveOffset;
186
}
187
}
188
189
void Scarab_HandlePlayerGrab(void)
190
{
191
RSDK_THIS(Scarab);
192
193
foreach_active(Player, player)
194
{
195
int32 playerID = RSDK.GetEntitySlot(player);
196
if ((1 << playerID) & self->grabbedPlayers) {
197
if (self->playerTimers[playerID] < 60 && player->interaction && player->state == Player_State_Static) {
198
player->position.x = self->position.x + ((2 * (self->direction != FLIP_NONE) - 1) << 21);
199
player->position.y = self->position.y - 0xA0000;
200
player->velocity.x = self->state == Scarab_State_Move ? (0x6000 * self->moveDir) : 0;
201
player->velocity.y = 0;
202
++self->playerTimers[playerID];
203
}
204
else {
205
self->grabbedPlayers &= ~(1 << playerID);
206
self->playerTimers[playerID] = -10;
207
208
if (player->state != Player_State_FlyToPlayer && player->state != Player_State_ReturnToPlayer) {
209
player->tileCollisions = TILECOLLISION_DOWN;
210
player->state = Player_State_Air;
211
player->velocity.x = 0xA0000 * (2 * (self->direction != FLIP_NONE) - 1);
212
player->velocity.y = 0;
213
}
214
215
self->isPermanent = false;
216
}
217
}
218
else {
219
if (self->playerTimers[playerID] < 0)
220
self->playerTimers[playerID]++;
221
}
222
}
223
}
224
225
void Scarab_HandlePlayerRelease(void)
226
{
227
RSDK_THIS(Scarab);
228
229
foreach_active(Player, player)
230
{
231
int32 playerID = RSDK.GetEntitySlot(player);
232
233
if ((1 << playerID) & self->grabbedPlayers) {
234
self->grabbedPlayers &= ~(1 << playerID);
235
self->playerTimers[playerID] = -10;
236
237
if (player->state != Player_State_FlyToPlayer && player->state != Player_State_ReturnToPlayer) {
238
player->tileCollisions = TILECOLLISION_DOWN;
239
player->state = Player_State_Air;
240
player->velocity.x = 0xA0000 * (2 * (self->direction != FLIP_NONE) - 1);
241
player->velocity.y = 0;
242
}
243
244
self->isPermanent = false;
245
}
246
}
247
}
248
249
void Scarab_State_Init(void)
250
{
251
RSDK_THIS(Scarab);
252
253
self->active = ACTIVE_NORMAL;
254
self->state = Scarab_State_Move;
255
self->pullCount = 0;
256
self->timer = 0;
257
self->moveDir = 2 * (self->direction != FLIP_NONE) - 1;
258
259
RSDK.SetSpriteAnimation(Scarab->aniFrames, 1, &self->bodyAnimator, true, 0);
260
RSDK.SetSpriteAnimation(Scarab->aniFrames, 5, &self->backLegAnimator, true, 0);
261
RSDK.SetSpriteAnimation(Scarab->aniFrames, 3, &self->frontLegAnimator, true, 0);
262
263
Scarab_State_Move();
264
}
265
266
void Scarab_State_Move(void)
267
{
268
RSDK_THIS(Scarab);
269
270
if (self->frontLegAnimator.frameID == self->frontLegAnimator.frameCount - 1)
271
++self->pullCount;
272
273
if (self->pullCount == 9) {
274
RSDK.SetSpriteAnimation(Scarab->aniFrames, 0, &self->bodyAnimator, true, 0);
275
RSDK.SetSpriteAnimation(Scarab->aniFrames, 4, &self->backLegAnimator, true, 0);
276
RSDK.SetSpriteAnimation(Scarab->aniFrames, 2, &self->frontLegAnimator, true, 0);
277
self->timer = 45;
278
self->state = Scarab_State_Wait;
279
}
280
281
int32 x = self->position.x + 0x6000 * self->moveDir;
282
int32 y = self->position.y;
283
284
self->position.x = x;
285
if (abs(x - self->startPos.x) < (self->amplitude << 16) && RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x60000, 2)) {
286
self->position.x = x;
287
}
288
else {
289
self->position.y = y;
290
self->position.x = self->startPos.x + (self->amplitude << 16) * self->moveDir;
291
self->moveDir = -self->moveDir;
292
}
293
294
RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x60000, 4);
295
}
296
297
void Scarab_State_Wait(void)
298
{
299
RSDK_THIS(Scarab);
300
301
if (self->timer <= 0) {
302
RSDK.SetSpriteAnimation(Scarab->aniFrames, 1, &self->bodyAnimator, true, 0);
303
RSDK.SetSpriteAnimation(Scarab->aniFrames, 5, &self->backLegAnimator, true, 0);
304
RSDK.SetSpriteAnimation(Scarab->aniFrames, 3, &self->frontLegAnimator, true, 0);
305
306
self->pullCount = 0;
307
self->state = Scarab_State_Move;
308
}
309
else {
310
self->timer--;
311
}
312
}
313
314
#if GAME_INCLUDE_EDITOR
315
void Scarab_EditorDraw(void)
316
{
317
RSDK_THIS(Scarab);
318
319
RSDK.SetSpriteAnimation(Scarab->aniFrames, 0, &self->bodyAnimator, true, 0);
320
RSDK.DrawSprite(&self->bodyAnimator, NULL, false);
321
322
RSDK.SetSpriteAnimation(Scarab->aniFrames, 4, &self->backLegAnimator, true, 0);
323
RSDK.DrawSprite(&self->backLegAnimator, NULL, false);
324
325
RSDK.SetSpriteAnimation(Scarab->aniFrames, 2, &self->frontLegAnimator, true, 0);
326
RSDK.DrawSprite(&self->frontLegAnimator, NULL, false);
327
328
if (showGizmos()) {
329
RSDK_DRAWING_OVERLAY(true);
330
331
for (int32 s = SceneInfo->entitySlot + 1, i = 0; i < self->childCount; ++i) {
332
Entity *child = RSDK_GET_ENTITY_GEN(s + i);
333
if (!child)
334
continue;
335
336
DrawHelpers_DrawArrow(self->position.x, self->position.y, child->position.x, child->position.y, 0xE0E0E0, INK_NONE, 0xFF);
337
}
338
339
RSDK_DRAWING_OVERLAY(false);
340
}
341
}
342
343
void Scarab_EditorLoad(void)
344
{
345
Scarab->aniFrames = RSDK.LoadSpriteAnimation("MMZ/Scarab.bin", SCOPE_STAGE);
346
347
RSDK_ACTIVE_VAR(Scarab, planeFilter);
348
RSDK_ENUM_VAR("None", PLANEFILTER_NONE);
349
RSDK_ENUM_VAR("AL", PLANEFILTER_AL);
350
RSDK_ENUM_VAR("BL", PLANEFILTER_BL);
351
RSDK_ENUM_VAR("AH", PLANEFILTER_AH);
352
RSDK_ENUM_VAR("BH", PLANEFILTER_BH);
353
354
RSDK_ACTIVE_VAR(Scarab, direction);
355
RSDK_ENUM_VAR("Left", FLIP_NONE);
356
RSDK_ENUM_VAR("Right", FLIP_X);
357
}
358
#endif
359
360
void Scarab_Serialize(void)
361
{
362
RSDK_EDITABLE_VAR(Scarab, VAR_UINT8, direction);
363
RSDK_EDITABLE_VAR(Scarab, VAR_INT32, amplitude);
364
RSDK_EDITABLE_VAR(Scarab, VAR_UINT8, childCount);
365
RSDK_EDITABLE_VAR(Scarab, VAR_ENUM, planeFilter);
366
}
367
368