Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/MMZ/MechaBu.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: MechaBu Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectMechaBu *MechaBu;
11
12
void MechaBu_Update(void)
13
{
14
RSDK_THIS(MechaBu);
15
16
StateMachine_Run(self->state);
17
18
Vector2 offset = MechaBu_GetSawOffset();
19
self->sawPos.x = self->position.x + offset.x;
20
self->sawPos.y = self->position.y + offset.y;
21
}
22
23
void MechaBu_LateUpdate(void) {}
24
25
void MechaBu_StaticUpdate(void) {}
26
27
void MechaBu_Draw(void)
28
{
29
RSDK_THIS(MechaBu);
30
31
RSDK.DrawSprite(&self->badnikAnimator, NULL, false);
32
RSDK.DrawSprite(&self->sawAnimator, &self->sawPos, false);
33
RSDK.DrawSprite(&self->hornAnimator, NULL, false);
34
}
35
36
void MechaBu_Create(void *data)
37
{
38
RSDK_THIS(MechaBu);
39
40
self->visible = true;
41
if (self->planeFilter > 0 && (((uint8)self->planeFilter - 1) & 2))
42
self->drawGroup = Zone->objectDrawGroup[1];
43
else
44
self->drawGroup = Zone->objectDrawGroup[0];
45
46
self->drawFX |= FX_FLIP;
47
self->startPos = self->position;
48
self->startDir = self->direction;
49
self->active = ACTIVE_BOUNDS;
50
self->updateRange.x = 0x800000;
51
self->updateRange.y = 0x800000;
52
53
RSDK.SetSpriteAnimation(MechaBu->aniFrames, 1, &self->badnikAnimator, true, 0);
54
RSDK.SetSpriteAnimation(MechaBu->aniFrames, 3, &self->hornAnimator, true, 0);
55
RSDK.SetSpriteAnimation(MechaBu->aniFrames, 7, &self->sawAnimator, true, 0);
56
57
self->state = MechaBu_State_Init;
58
}
59
60
void MechaBu_StageLoad(void)
61
{
62
if (RSDK.CheckSceneFolder("MMZ"))
63
MechaBu->aniFrames = RSDK.LoadSpriteAnimation("MMZ/MechaBu.bin", SCOPE_STAGE);
64
65
MechaBu->hitboxSaw.left = -14;
66
MechaBu->hitboxSaw.top = -14;
67
MechaBu->hitboxSaw.right = 14;
68
MechaBu->hitboxSaw.bottom = 14;
69
70
MechaBu->hitboxUnused.left = -8;
71
MechaBu->hitboxUnused.top = -12;
72
MechaBu->hitboxUnused.right = 8;
73
MechaBu->hitboxUnused.bottom = 12;
74
75
DEBUGMODE_ADD_OBJ(MechaBu);
76
77
MechaBu->sfxSawUp = RSDK.GetSfx("MMZ/SawUp.wav");
78
MechaBu->sfxSawDown = RSDK.GetSfx("MMZ/SawDown.wav");
79
}
80
81
void MechaBu_DebugSpawn(void)
82
{
83
RSDK_THIS(DebugMode);
84
85
CREATE_ENTITY(MechaBu, NULL, self->position.x, self->position.y);
86
}
87
88
void MechaBu_DebugDraw(void)
89
{
90
RSDK.SetSpriteAnimation(MechaBu->aniFrames, 0, &DebugMode->animator, true, 0);
91
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
92
}
93
94
void MechaBu_CheckPlayerCollisions(void)
95
{
96
RSDK_THIS(MechaBu);
97
98
foreach_active(Player, player)
99
{
100
if (self->planeFilter <= 0 || player->collisionPlane == (((uint8)self->planeFilter - 1) & 1)) {
101
Vector2 posStore = self->position;
102
self->position = self->sawPos;
103
if (Player_CheckCollisionTouch(player, self, &MechaBu->hitboxSaw)) {
104
self->position = posStore;
105
#if MANIA_USE_PLUS
106
if (!Player_CheckMightyUnspin(player, 0x200, 2, &player->uncurlTimer))
107
#endif
108
Player_Hurt(player, self);
109
}
110
else {
111
self->position = posStore;
112
if (Player_CheckBadnikTouch(player, self, &MechaBu->hitboxSaw) && Player_CheckBadnikBreak(player, self, false)) {
113
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, self->sawPos.x, self->sawPos.y);
114
RSDK.SetSpriteAnimation(MechaBu->aniFrames, 7, &debris->animator, false, 0);
115
debris->velocity.x = RSDK.Rand(-2, 3) << 16;
116
debris->velocity.y = RSDK.Rand(-4, -1) << 16;
117
debris->gravityStrength = 0x3800;
118
debris->drawGroup = self->drawGroup;
119
debris->updateRange.x = 0x200000;
120
debris->updateRange.y = 0x200000;
121
destroyEntity(self);
122
}
123
}
124
}
125
}
126
}
127
128
void MechaBu_CheckOffScreen(void)
129
{
130
RSDK_THIS(MechaBu);
131
132
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
133
self->position = self->startPos;
134
self->direction = self->startDir;
135
MechaBu_Create(NULL);
136
}
137
}
138
139
Vector2 MechaBu_GetSawOffset(void)
140
{
141
RSDK_THIS(MechaBu);
142
143
Vector2 offset;
144
switch (self->hornAnimator.animationID) {
145
case 4:
146
offset.x = MechaBu->sawOffsets[8];
147
offset.y = MechaBu->sawOffsets[9];
148
break;
149
150
case 5:
151
offset.x = MechaBu->sawOffsets[2 * (4 - self->hornAnimator.frameID) + 0];
152
offset.y = MechaBu->sawOffsets[2 * (4 - self->hornAnimator.frameID) + 1];
153
break;
154
155
case 6:
156
offset.x = MechaBu->sawOffsets[(2 * self->hornAnimator.frameID) + 0];
157
offset.y = MechaBu->sawOffsets[(2 * self->hornAnimator.frameID) + 1];
158
break;
159
160
default:
161
offset.x = MechaBu->sawOffsets[0];
162
offset.y = MechaBu->sawOffsets[1];
163
break;
164
}
165
166
return offset;
167
}
168
169
void MechaBu_State_Init(void)
170
{
171
RSDK_THIS(MechaBu);
172
173
self->active = ACTIVE_NORMAL;
174
self->sawTimer = 0;
175
self->velocity.x = -0x10000;
176
self->velocity.y = 0;
177
178
self->state = MechaBu_State_Moving;
179
MechaBu_State_Moving();
180
}
181
182
void MechaBu_State_Moving(void)
183
{
184
RSDK_THIS(MechaBu);
185
186
RSDK.ProcessAnimation(&self->badnikAnimator);
187
RSDK.ProcessAnimation(&self->hornAnimator);
188
RSDK.ProcessAnimation(&self->sawAnimator);
189
190
self->sawTimer++;
191
if (self->sawTimer == 60) {
192
if (self->onScreen == 1)
193
RSDK.PlaySfx(MechaBu->sfxSawUp, false, 255);
194
195
RSDK.SetSpriteAnimation(MechaBu->aniFrames, 6, &self->hornAnimator, true, 0);
196
}
197
else if (self->sawTimer == 120) {
198
if (self->onScreen == 1)
199
RSDK.PlaySfx(MechaBu->sfxSawDown, false, 255);
200
201
self->sawTimer = 0;
202
RSDK.SetSpriteAnimation(MechaBu->aniFrames, 5, &self->hornAnimator, true, 0);
203
}
204
205
self->position.x += self->velocity.x;
206
207
if (RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xF0000, 8)) {
208
bool32 collidedWall = false;
209
bool32 collidedFloor = false;
210
if (self->velocity.x <= 0) {
211
collidedWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x120000, 0, true);
212
collidedFloor = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, -0x20000, 0x100000, false);
213
}
214
else {
215
collidedWall = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x120000, 0, true);
216
collidedFloor = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0x20000, 0x100000, false);
217
}
218
219
if (!collidedFloor || collidedWall) {
220
self->timer = 0;
221
self->state = MechaBu_State_Stopped;
222
}
223
}
224
else {
225
RSDK.SetSpriteAnimation(MechaBu->aniFrames, 1, &self->badnikAnimator, true, 0);
226
self->timer = 0;
227
228
bool32 collided = false;
229
if (self->velocity.x >= 0)
230
collided = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, -0x10000, 0xF0000, 8);
231
else
232
collided = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0x10000, 0xF0000, 8);
233
234
self->state = collided ? MechaBu_State_Stopped : MechaBu_State_Falling;
235
}
236
237
MechaBu_CheckPlayerCollisions();
238
MechaBu_CheckOffScreen();
239
}
240
241
void MechaBu_State_Stopped(void)
242
{
243
RSDK_THIS(MechaBu);
244
245
RSDK.ProcessAnimation(&self->badnikAnimator);
246
RSDK.ProcessAnimation(&self->hornAnimator);
247
RSDK.ProcessAnimation(&self->sawAnimator);
248
249
if (++self->timer == 48) {
250
self->velocity.x = -self->velocity.x;
251
252
self->state = MechaBu_State_Moving;
253
MechaBu_State_Moving();
254
}
255
256
MechaBu_CheckPlayerCollisions();
257
MechaBu_CheckOffScreen();
258
}
259
260
void MechaBu_State_Falling(void)
261
{
262
RSDK_THIS(MechaBu);
263
264
RSDK.ProcessAnimation(&self->badnikAnimator);
265
RSDK.ProcessAnimation(&self->hornAnimator);
266
RSDK.ProcessAnimation(&self->sawAnimator);
267
268
self->position.x += self->velocity.x;
269
self->position.y += self->velocity.y;
270
self->velocity.y += 0x3800;
271
272
if (RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0xF0000, 8)) {
273
self->velocity.y = 0;
274
RSDK.SetSpriteAnimation(MechaBu->aniFrames, 0, &self->badnikAnimator, true, 0);
275
276
self->state = MechaBu_State_Moving;
277
MechaBu_State_Moving();
278
}
279
else {
280
bool32 collided = false;
281
if (self->velocity.x <= 0)
282
collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_RWALL, 0, -0x120000, 0, true);
283
else
284
collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_LWALL, 0, 0x120000, 0, true);
285
286
if (collided)
287
self->velocity.x = 0;
288
289
MechaBu_CheckPlayerCollisions();
290
MechaBu_CheckOffScreen();
291
}
292
}
293
294
#if GAME_INCLUDE_EDITOR
295
void MechaBu_EditorDraw(void)
296
{
297
RSDK_THIS(MechaBu);
298
299
self->sawPos.x = self->position.x + -0x150000;
300
self->sawPos.y = self->position.y + -0xF0000;
301
302
MechaBu_Draw();
303
}
304
305
void MechaBu_EditorLoad(void)
306
{
307
MechaBu->aniFrames = RSDK.LoadSpriteAnimation("MMZ/MechaBu.bin", SCOPE_STAGE);
308
309
RSDK_ACTIVE_VAR(MechaBu, planeFilter);
310
RSDK_ENUM_VAR("None", PLANEFILTER_NONE);
311
RSDK_ENUM_VAR("AL", PLANEFILTER_AL);
312
RSDK_ENUM_VAR("BL", PLANEFILTER_BL);
313
RSDK_ENUM_VAR("AH", PLANEFILTER_AH);
314
RSDK_ENUM_VAR("BH", PLANEFILTER_BH);
315
}
316
#endif
317
318
void MechaBu_Serialize(void) { RSDK_EDITABLE_VAR(MechaBu, VAR_ENUM, planeFilter); }
319
320