Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/GHZ/BuzzBomber.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: BuzzBomber Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectBuzzBomber *BuzzBomber;
11
12
void BuzzBomber_Update(void)
13
{
14
RSDK_THIS(BuzzBomber);
15
StateMachine_Run(self->state);
16
}
17
18
void BuzzBomber_LateUpdate(void) {}
19
20
void BuzzBomber_StaticUpdate(void) {}
21
22
void BuzzBomber_Draw(void)
23
{
24
RSDK_THIS(BuzzBomber);
25
26
if (self->inkEffect == INK_ADD) {
27
RSDK.DrawSprite(&self->animator, NULL, false);
28
}
29
else {
30
RSDK.DrawSprite(&self->animator, NULL, false);
31
32
self->inkEffect = INK_ALPHA;
33
RSDK.DrawSprite(&self->wingAnimator, NULL, false);
34
35
self->inkEffect = INK_NONE;
36
RSDK.DrawSprite(&self->thrustAnimator, NULL, false);
37
}
38
}
39
40
void BuzzBomber_Create(void *data)
41
{
42
RSDK_THIS(BuzzBomber);
43
self->visible = true;
44
self->drawFX |= FX_FLIP;
45
self->drawGroup = Zone->objectDrawGroup[0];
46
self->startPos.x = self->position.x;
47
self->startPos.y = self->position.y;
48
self->startDir = self->direction;
49
self->timer = 128;
50
self->detectedPlayer = false;
51
self->projectile = NULL;
52
53
if (!self->shotRange)
54
self->shotRange = 96;
55
56
self->hitboxRange.right = self->shotRange;
57
self->hitboxRange.left = -self->shotRange;
58
self->hitboxRange.top = -256;
59
self->hitboxRange.bottom = 256;
60
61
if (data) {
62
self->inkEffect = INK_ADD;
63
self->alpha = 0xC0;
64
self->active = ACTIVE_NORMAL;
65
self->updateRange.x = 0x200000;
66
self->updateRange.y = 0x200000;
67
RSDK.SetSpriteAnimation(BuzzBomber->aniFrames, 4, &self->animator, true, 0);
68
RSDK.SetSpriteAnimation(-1, 0, &self->wingAnimator, true, 0);
69
RSDK.SetSpriteAnimation(-1, 0, &self->thrustAnimator, true, 0);
70
self->state = BuzzBomber_State_ProjectileCharge;
71
}
72
else {
73
self->active = ACTIVE_BOUNDS;
74
self->updateRange.x = 0x800000;
75
self->updateRange.y = 0x800000;
76
RSDK.SetSpriteAnimation(BuzzBomber->aniFrames, 0, &self->animator, true, 0);
77
RSDK.SetSpriteAnimation(BuzzBomber->aniFrames, 2, &self->wingAnimator, true, 0);
78
RSDK.SetSpriteAnimation(BuzzBomber->aniFrames, 3, &self->thrustAnimator, true, 0);
79
self->state = BuzzBomber_State_Init;
80
self->alpha = 0xC0;
81
}
82
}
83
84
void BuzzBomber_StageLoad(void)
85
{
86
if (RSDK.CheckSceneFolder("GHZ"))
87
BuzzBomber->aniFrames = RSDK.LoadSpriteAnimation("GHZ/BuzzBomber.bin", SCOPE_STAGE);
88
else if (RSDK.CheckSceneFolder("Blueprint"))
89
BuzzBomber->aniFrames = RSDK.LoadSpriteAnimation("Blueprint/BuzzBomber.bin", SCOPE_STAGE);
90
91
BuzzBomber->hitboxBadnik.left = -24;
92
BuzzBomber->hitboxBadnik.top = -12;
93
BuzzBomber->hitboxBadnik.right = 24;
94
BuzzBomber->hitboxBadnik.bottom = 12;
95
96
BuzzBomber->hitboxProjectile.left = -6;
97
BuzzBomber->hitboxProjectile.top = -6;
98
BuzzBomber->hitboxProjectile.right = 6;
99
BuzzBomber->hitboxProjectile.bottom = 6;
100
101
DEBUGMODE_ADD_OBJ(BuzzBomber);
102
}
103
104
void BuzzBomber_DebugDraw(void)
105
{
106
RSDK.SetSpriteAnimation(BuzzBomber->aniFrames, 0, &DebugMode->animator, true, 0);
107
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
108
}
109
110
void BuzzBomber_DebugSpawn(void)
111
{
112
RSDK_THIS(DebugMode);
113
114
EntityBuzzBomber *buzzBomber = CREATE_ENTITY(BuzzBomber, NULL, self->position.x, self->position.y);
115
116
buzzBomber->direction = self->direction;
117
buzzBomber->startDir = self->direction;
118
}
119
120
void BuzzBomber_CheckOffScreen(void)
121
{
122
RSDK_THIS(BuzzBomber);
123
124
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
125
self->position.x = self->startPos.x;
126
self->position.y = self->startPos.y;
127
self->direction = self->startDir;
128
BuzzBomber_Create(NULL);
129
}
130
}
131
132
void BuzzBomber_CheckPlayerCollisions(void)
133
{
134
RSDK_THIS(BuzzBomber);
135
136
foreach_active(Player, player)
137
{
138
if (Player_CheckBadnikTouch(player, self, &BuzzBomber->hitboxBadnik)) {
139
if (Player_CheckBadnikBreak(player, self, true)) {
140
if (self->projectile)
141
destroyEntity(self->projectile);
142
}
143
}
144
else if (self->state == BuzzBomber_State_Flying && !self->detectedPlayer) {
145
if (Player_CheckCollisionTouch(player, self, &self->hitboxRange)) {
146
self->detectedPlayer = true;
147
self->timer = 90;
148
RSDK.SetSpriteAnimation(-1, 0, &self->thrustAnimator, true, 0);
149
self->state = BuzzBomber_State_DetectedPlayer;
150
}
151
}
152
}
153
}
154
155
void BuzzBomber_State_Init(void)
156
{
157
RSDK_THIS(BuzzBomber);
158
159
self->active = ACTIVE_NORMAL;
160
if (!(self->direction & FLIP_X))
161
self->velocity.x = -0x40000;
162
else
163
self->velocity.x = 0x40000;
164
165
self->state = BuzzBomber_State_Flying;
166
BuzzBomber_State_Flying();
167
}
168
169
void BuzzBomber_State_Flying(void)
170
{
171
RSDK_THIS(BuzzBomber);
172
173
self->position.x += self->velocity.x;
174
self->position.y += self->velocity.y;
175
176
if (!--self->timer) {
177
self->direction ^= FLIP_X;
178
self->timer = 60;
179
self->velocity.x = -self->velocity.x;
180
self->detectedPlayer = false;
181
RSDK.SetSpriteAnimation(-1, 0, &self->thrustAnimator, true, 0);
182
self->state = BuzzBomber_State_Idle;
183
}
184
185
RSDK.ProcessAnimation(&self->animator);
186
RSDK.ProcessAnimation(&self->wingAnimator);
187
RSDK.ProcessAnimation(&self->thrustAnimator);
188
BuzzBomber_CheckPlayerCollisions();
189
BuzzBomber_CheckOffScreen();
190
}
191
192
void BuzzBomber_State_Idle(void)
193
{
194
RSDK_THIS(BuzzBomber);
195
196
if (!--self->timer) {
197
self->timer = 128;
198
RSDK.SetSpriteAnimation(BuzzBomber->aniFrames, 3, &self->thrustAnimator, true, 0);
199
self->state = BuzzBomber_State_Flying;
200
}
201
202
RSDK.ProcessAnimation(&self->animator);
203
RSDK.ProcessAnimation(&self->wingAnimator);
204
205
BuzzBomber_CheckPlayerCollisions();
206
BuzzBomber_CheckOffScreen();
207
}
208
209
void BuzzBomber_State_DetectedPlayer(void)
210
{
211
RSDK_THIS(BuzzBomber);
212
213
RSDK.ProcessAnimation(&self->animator);
214
RSDK.ProcessAnimation(&self->wingAnimator);
215
BuzzBomber_CheckPlayerCollisions();
216
BuzzBomber_CheckOffScreen();
217
218
self->timer--;
219
if (self->timer == 82) {
220
RSDK.SetSpriteAnimation(BuzzBomber->aniFrames, 1, &self->animator, true, 0);
221
}
222
else if (self->timer == 45) {
223
EntityBuzzBomber *projectile = CREATE_ENTITY(BuzzBomber, INT_TO_VOID(true), self->position.x, self->position.y);
224
if (self->direction) {
225
projectile->position.x += 0x180000;
226
projectile->velocity.x = 0x20000;
227
}
228
else {
229
projectile->position.x -= 0x180000;
230
projectile->velocity.x = -0x20000;
231
}
232
projectile->position.y += 0x1C0000;
233
projectile->velocity.y = 0x20000;
234
projectile->groundVel = 0;
235
projectile->projectile = (Entity *)self;
236
projectile->direction = self->direction;
237
projectile->active = ACTIVE_NORMAL;
238
239
self->projectile = (Entity *)projectile;
240
}
241
else if (!self->timer) {
242
RSDK.SetSpriteAnimation(BuzzBomber->aniFrames, 0, &self->animator, true, 0);
243
self->timer = 128;
244
RSDK.SetSpriteAnimation(BuzzBomber->aniFrames, 3, &self->thrustAnimator, true, 0);
245
self->state = BuzzBomber_State_Flying;
246
}
247
}
248
249
void BuzzBomber_State_ProjectileCharge(void)
250
{
251
RSDK_THIS(BuzzBomber);
252
RSDK.ProcessAnimation(&self->animator);
253
254
if (self->animator.frameID == 6) {
255
self->state = BuzzBomber_State_ProjectileShot;
256
EntityBuzzBomber *shot = (EntityBuzzBomber *)self->projectile;
257
shot->projectile = NULL;
258
}
259
}
260
261
void BuzzBomber_State_ProjectileShot(void)
262
{
263
RSDK_THIS(BuzzBomber);
264
265
self->position.x += self->velocity.x;
266
self->position.y += self->velocity.y;
267
268
if (RSDK.CheckOnScreen(self, NULL)) {
269
RSDK.ProcessAnimation(&self->animator);
270
271
foreach_active(Player, player)
272
{
273
if (Player_CheckCollisionTouch(player, self, &BuzzBomber->hitboxProjectile))
274
Player_ProjectileHurt(player, self);
275
}
276
}
277
else {
278
destroyEntity(self);
279
}
280
}
281
282
#if GAME_INCLUDE_EDITOR
283
void BuzzBomber_EditorDraw(void)
284
{
285
RSDK_THIS(BuzzBomber);
286
287
BuzzBomber_Draw();
288
289
if (showGizmos()) {
290
RSDK_DRAWING_OVERLAY(true);
291
292
self->hitboxRange.right = self->shotRange;
293
self->hitboxRange.left = -self->shotRange;
294
self->hitboxRange.top = -256;
295
self->hitboxRange.bottom = 256;
296
297
DrawHelpers_DrawHitboxOutline(self->position.x, self->position.y, &self->hitboxRange, FLIP_NONE, 0xFF0000);
298
299
RSDK_DRAWING_OVERLAY(false);
300
}
301
}
302
303
void BuzzBomber_EditorLoad(void)
304
{
305
if (RSDK.CheckSceneFolder("GHZ"))
306
BuzzBomber->aniFrames = RSDK.LoadSpriteAnimation("GHZ/BuzzBomber.bin", SCOPE_STAGE);
307
else if (RSDK.CheckSceneFolder("Blueprint"))
308
BuzzBomber->aniFrames = RSDK.LoadSpriteAnimation("Blueprint/BuzzBomber.bin", SCOPE_STAGE);
309
310
RSDK_ACTIVE_VAR(BuzzBomber, direction);
311
RSDK_ENUM_VAR("Left", FLIP_NONE);
312
RSDK_ENUM_VAR("Right", FLIP_X);
313
}
314
#endif
315
316
void BuzzBomber_Serialize(void)
317
{
318
RSDK_EDITABLE_VAR(BuzzBomber, VAR_UINT8, direction);
319
RSDK_EDITABLE_VAR(BuzzBomber, VAR_UINT8, shotRange);
320
}
321
322