Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/HCZ/Buggernaut.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Buggernaut Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
// NOTE:
9
// This object was prolly based on Unused/Wisp
10
// it looks like it has the same structure, and even has "buzzCount", even though its set to -1
11
12
#include "Game.h"
13
14
ObjectBuggernaut *Buggernaut;
15
16
void Buggernaut_Update(void)
17
{
18
RSDK_THIS(Buggernaut);
19
20
StateMachine_Run(self->state);
21
}
22
23
void Buggernaut_LateUpdate(void) {}
24
25
void Buggernaut_StaticUpdate(void) {}
26
27
void Buggernaut_Draw(void)
28
{
29
RSDK_THIS(Buggernaut);
30
31
RSDK.DrawSprite(&self->bodyAnimator, NULL, false);
32
33
self->inkEffect = INK_ALPHA;
34
RSDK.DrawSprite(&self->wingAnimator, NULL, false);
35
36
self->inkEffect = INK_NONE;
37
}
38
39
void Buggernaut_Create(void *data)
40
{
41
RSDK_THIS(Buggernaut);
42
43
self->visible = true;
44
self->drawGroup = Zone->objectDrawGroup[0] + 1;
45
46
if (!SceneInfo->inEditor) {
47
self->drawFX |= FX_FLIP;
48
self->startPos = self->position;
49
self->active = ACTIVE_BOUNDS;
50
self->updateRange.x = 0x800000;
51
self->updateRange.y = 0x800000;
52
self->direction = FLIP_NONE;
53
self->alpha = 128;
54
self->timer = 16;
55
self->buzzCount = -1;
56
57
RSDK.SetSpriteAnimation(Buggernaut->aniFrames, 0, &self->bodyAnimator, true, 0);
58
RSDK.SetSpriteAnimation(Buggernaut->aniFrames, 2, &self->wingAnimator, true, 0);
59
60
self->state = Buggernaut_State_Init;
61
}
62
}
63
64
void Buggernaut_StageLoad(void)
65
{
66
Buggernaut->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Buggernaut.bin", SCOPE_STAGE);
67
68
Buggernaut->hitboxBadnik.left = -8;
69
Buggernaut->hitboxBadnik.top = -8;
70
Buggernaut->hitboxBadnik.right = 8;
71
Buggernaut->hitboxBadnik.bottom = 8;
72
73
Buggernaut->hitboxParentRange.left = -64;
74
Buggernaut->hitboxParentRange.top = -64;
75
Buggernaut->hitboxParentRange.right = 64;
76
Buggernaut->hitboxParentRange.bottom = 64;
77
78
DEBUGMODE_ADD_OBJ(Buggernaut);
79
}
80
81
void Buggernaut_DebugSpawn(void)
82
{
83
RSDK_THIS(DebugMode);
84
85
CREATE_ENTITY(Buggernaut, NULL, self->position.x, self->position.y);
86
}
87
88
void Buggernaut_DebugDraw(void)
89
{
90
RSDK.SetSpriteAnimation(Buggernaut->aniFrames, 0, &DebugMode->animator, true, 0);
91
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
92
}
93
94
void Buggernaut_CheckPlayerCollisions(void)
95
{
96
RSDK_THIS(Buggernaut);
97
98
foreach_active(Player, player)
99
{
100
if (Player_CheckBadnikTouch(player, self, &Buggernaut->hitboxBadnik))
101
Player_CheckBadnikBreak(player, self, true);
102
}
103
}
104
105
void Buggernaut_CheckOffScreen(void)
106
{
107
RSDK_THIS(Buggernaut);
108
109
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
110
if (self->bodyAnimator.animationID) {
111
destroyEntity(self);
112
}
113
else {
114
self->position = self->startPos;
115
Buggernaut_Create(NULL);
116
}
117
}
118
}
119
120
bool32 Buggernaut_HandleTileCollisionsX(void)
121
{
122
RSDK_THIS(Buggernaut);
123
124
bool32 collided = false;
125
if (self->velocity.x <= 0) {
126
collided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, -0x90000, -0x80000, false);
127
collided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, -0x90000, 0x80000, false);
128
}
129
else {
130
collided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0x90000, -0x80000, false);
131
collided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0x90000, 0x80000, false);
132
}
133
134
if (collided)
135
self->velocity.x = -self->velocity.x;
136
137
return collided;
138
}
139
140
bool32 Buggernaut_HandleTileCollisionsY(void)
141
{
142
RSDK_THIS(Buggernaut);
143
144
bool32 collided = false;
145
if (self->velocity.y <= 0) {
146
collided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, -0x80000, -0x90000, false);
147
collided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0x80000, 0x90000, false);
148
}
149
else {
150
collided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, -0x80000, 0x90000, false);
151
collided |= RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0x80000, 0x90000, false);
152
}
153
154
if (collided)
155
self->velocity.y = -self->velocity.y;
156
157
return collided;
158
}
159
160
void Buggernaut_State_Init(void)
161
{
162
RSDK_THIS(Buggernaut);
163
164
self->active = ACTIVE_NORMAL;
165
int32 x = self->position.x;
166
int32 y = self->position.y;
167
self->velocity.x = 0;
168
self->velocity.y = 0;
169
170
EntityBuggernaut *child = CREATE_ENTITY(Buggernaut, INT_TO_VOID(true), x, y);
171
RSDK.SetSpriteAnimation(Buggernaut->aniFrames, 1, &child->bodyAnimator, true, 0);
172
RSDK.SetSpriteAnimation(Buggernaut->aniFrames, 3, &child->wingAnimator, true, 0);
173
child->active = ACTIVE_NORMAL;
174
child->drawGroup = self->drawGroup - 1;
175
child->parent = self;
176
child->passThrough = self->passThrough;
177
child->isPermanent = true;
178
child->state = Buggernaut_State_Child;
179
180
self->state = Buggernaut_State_Idle;
181
Buggernaut_State_Idle();
182
}
183
184
void Buggernaut_State_Idle(void)
185
{
186
RSDK_THIS(Buggernaut);
187
188
if (--self->timer <= 0) {
189
if (--self->buzzCount) {
190
self->velocity.y = -0x10000;
191
self->timer = 96;
192
self->state = Buggernaut_State_FlyTowardTarget;
193
}
194
else {
195
self->velocity.x = RSDK.Rand(-2, 3) << 16;
196
self->velocity.y = RSDK.Rand(-2, 3) << 16;
197
198
if (!self->velocity.x || !self->velocity.y)
199
self->velocity.x = -0x20000;
200
201
self->velocity.y = -0x20000;
202
self->state = Buggernaut_State_FlyAway;
203
}
204
}
205
206
RSDK.ProcessAnimation(&self->wingAnimator);
207
208
Buggernaut_CheckPlayerCollisions();
209
Buggernaut_CheckOffScreen();
210
}
211
212
void Buggernaut_State_FlyTowardTarget(void)
213
{
214
RSDK_THIS(Buggernaut);
215
216
self->position.x += self->velocity.x;
217
self->position.y += self->velocity.y;
218
219
EntityPlayer *player = Player_GetNearestPlayer();
220
if (player) {
221
if (player->position.x >= self->position.x) {
222
self->velocity.x += 0x1000;
223
224
if (self->velocity.x > 0x20000)
225
self->velocity.x = 0x20000;
226
227
self->direction = FLIP_X;
228
}
229
else {
230
self->velocity.x -= 0x1000;
231
232
if (self->velocity.x < -0x20000)
233
self->velocity.x = -0x20000;
234
235
self->direction = FLIP_NONE;
236
}
237
238
if (player->position.y >= self->position.y) {
239
self->velocity.y += 0x1000;
240
241
if (self->velocity.y > 0x20000)
242
self->velocity.y = 0x20000;
243
}
244
else {
245
self->velocity.y -= 0x1000;
246
247
if (self->velocity.y < -0x20000)
248
self->velocity.y = -0x20000;
249
}
250
}
251
252
if (self->velocity.y > 0 && self->position.y > Water->waterLevel - 0x80000)
253
self->velocity.y = -self->velocity.y;
254
255
if (!self->passThrough) {
256
if (abs(self->velocity.x) <= abs(self->velocity.y)) {
257
if (!Buggernaut_HandleTileCollisionsY())
258
Buggernaut_HandleTileCollisionsX();
259
}
260
else if (!Buggernaut_HandleTileCollisionsX()) {
261
Buggernaut_HandleTileCollisionsY();
262
}
263
}
264
265
if (!--self->timer) {
266
self->timer = RSDK.Rand(0, 32);
267
self->state = Buggernaut_State_Idle;
268
self->velocity.x = 0;
269
self->velocity.y = 0;
270
self->direction = FLIP_NONE;
271
}
272
273
RSDK.ProcessAnimation(&self->wingAnimator);
274
275
Buggernaut_CheckPlayerCollisions();
276
Buggernaut_CheckOffScreen();
277
}
278
279
void Buggernaut_State_FlyAway(void)
280
{
281
RSDK_THIS(Buggernaut);
282
283
self->position.x += self->velocity.x;
284
self->position.y += self->velocity.y;
285
286
RSDK.ProcessAnimation(&self->wingAnimator);
287
288
if (!self->bodyAnimator.animationID)
289
Buggernaut_CheckPlayerCollisions();
290
291
Buggernaut_CheckOffScreen();
292
}
293
294
void Buggernaut_State_Child(void)
295
{
296
RSDK_THIS(Buggernaut);
297
298
self->position.x += self->velocity.x;
299
self->position.y += self->velocity.y;
300
301
if (!self->parent || self->parent->classID != Buggernaut->classID) {
302
foreach_active(Buggernaut, buggernaut)
303
{
304
if (buggernaut->bodyAnimator.animationID == 0
305
&& RSDK.CheckObjectCollisionTouchBox(buggernaut, &Buggernaut->hitboxBadnik, self, &Buggernaut->hitboxParentRange)) {
306
self->parent = buggernaut;
307
foreach_break;
308
}
309
}
310
311
if (!self->parent) {
312
self->velocity.x = RSDK.Rand(-2, 3) << 16;
313
self->velocity.y = RSDK.Rand(-2, 3) << 16;
314
315
if (!self->velocity.y || !self->velocity.x)
316
self->velocity.x = -0x20000;
317
self->velocity.y = -0x20000;
318
self->state = Buggernaut_State_FlyAway;
319
}
320
}
321
322
if (self->parent) {
323
if (self->parent->position.x >= self->position.x) {
324
self->velocity.x += 0x2000;
325
326
if (self->velocity.x > 0x20000)
327
self->velocity.x = 0x20000;
328
329
self->direction = FLIP_X;
330
}
331
else {
332
self->velocity.x -= 0x2000;
333
334
if (self->velocity.x < -0x20000)
335
self->velocity.x = -0x20000;
336
337
self->direction = FLIP_NONE;
338
}
339
340
if (self->parent->position.y >= self->position.y) {
341
self->velocity.y += 0x2000;
342
343
if (self->velocity.y > 0x20000)
344
self->velocity.y = 0x20000;
345
}
346
else {
347
self->velocity.y -= 0x2000;
348
349
if (self->velocity.y < -0x20000)
350
self->velocity.y = -0x20000;
351
}
352
353
if (self->velocity.y > 0 && self->position.y > Water->waterLevel - 0x80000)
354
self->velocity.y = -self->velocity.y;
355
356
if (!self->passThrough) {
357
if (abs(self->velocity.x) <= abs(self->velocity.y)) {
358
if (!Buggernaut_HandleTileCollisionsY())
359
Buggernaut_HandleTileCollisionsX();
360
}
361
else if (!Buggernaut_HandleTileCollisionsX()) {
362
Buggernaut_HandleTileCollisionsY();
363
}
364
}
365
}
366
367
RSDK.ProcessAnimation(&self->wingAnimator);
368
369
if (self->parent->state == Buggernaut_State_Init)
370
destroyEntity(self);
371
}
372
373
#if GAME_INCLUDE_EDITOR
374
void Buggernaut_EditorDraw(void)
375
{
376
RSDK_THIS(Buggernaut);
377
378
self->drawFX = FX_FLIP;
379
self->alpha = 0x80;
380
RSDK.SetSpriteAnimation(Buggernaut->aniFrames, 0, &self->bodyAnimator, true, 0);
381
RSDK.SetSpriteAnimation(Buggernaut->aniFrames, 2, &self->wingAnimator, true, 0);
382
383
Buggernaut_Draw();
384
}
385
386
void Buggernaut_EditorLoad(void)
387
{
388
Buggernaut->aniFrames = RSDK.LoadSpriteAnimation("HCZ/Buggernaut.bin", SCOPE_STAGE);
389
390
// despite being editable, this variable is set to FLIP_NONE on create, thereby making the editable var's value unused
391
RSDK_ACTIVE_VAR(Buggernaut, direction);
392
RSDK_ENUM_VAR("(Unused)", FLIP_NONE);
393
// RSDK_ENUM_VAR("No Flip", FLIP_NONE);
394
// RSDK_ENUM_VAR("Flip X", FLIP_X);
395
}
396
#endif
397
398
void Buggernaut_Serialize(void)
399
{
400
RSDK_EDITABLE_VAR(Buggernaut, VAR_UINT8, direction);
401
RSDK_EDITABLE_VAR(Buggernaut, VAR_BOOL, passThrough);
402
}
403
404