Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/FBZ/Blaster.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Blaster Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectBlaster *Blaster;
11
12
void Blaster_Update(void)
13
{
14
RSDK_THIS(Blaster);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Blaster_LateUpdate(void) {}
20
21
void Blaster_StaticUpdate(void) {}
22
23
void Blaster_Draw(void)
24
{
25
RSDK_THIS(Blaster);
26
27
RSDK.DrawSprite(&self->animator, NULL, false);
28
}
29
30
void Blaster_Create(void *data)
31
{
32
RSDK_THIS(Blaster);
33
34
self->visible = true;
35
self->drawGroup = Zone->objectDrawGroup[0];
36
self->drawFX |= FX_FLIP;
37
self->active = ACTIVE_BOUNDS;
38
self->updateRange.x = 0x800000;
39
self->updateRange.y = 0x800000;
40
41
if (data) {
42
if (data == INT_TO_VOID(BLASTER_SHOT)) {
43
self->active = ACTIVE_NORMAL;
44
RSDK.SetSpriteAnimation(Blaster->aniFrames, 4, &self->animator, true, 0);
45
self->state = Blaster_State_BeginShot;
46
}
47
else if (data == INT_TO_VOID(BLASTER_SHELL)) {
48
self->active = ACTIVE_NORMAL;
49
RSDK.SetSpriteAnimation(Blaster->aniFrames, 5, &self->animator, true, 0);
50
self->state = Blaster_State_Shell;
51
}
52
}
53
else {
54
self->startPos = self->position;
55
self->startDir = self->direction;
56
RSDK.SetSpriteAnimation(Blaster->aniFrames, 1, &self->animator, true, 0);
57
self->state = Blaster_State_Init;
58
}
59
}
60
61
void Blaster_StageLoad(void)
62
{
63
if (RSDK.CheckSceneFolder("FBZ"))
64
Blaster->aniFrames = RSDK.LoadSpriteAnimation("FBZ/Blaster.bin", SCOPE_STAGE);
65
66
Blaster->hitboxBadnik.left = -16;
67
Blaster->hitboxBadnik.top = -8;
68
Blaster->hitboxBadnik.right = 24;
69
Blaster->hitboxBadnik.bottom = 16;
70
71
Blaster->hitboxRange.left = -128;
72
Blaster->hitboxRange.top = -128;
73
Blaster->hitboxRange.right = 0;
74
Blaster->hitboxRange.bottom = 0;
75
76
Blaster->hitboxProjectile.left = -4;
77
Blaster->hitboxProjectile.top = -4;
78
Blaster->hitboxProjectile.right = 4;
79
Blaster->hitboxProjectile.bottom = 4;
80
81
DEBUGMODE_ADD_OBJ(Blaster);
82
}
83
84
void Blaster_DebugSpawn(void)
85
{
86
RSDK_THIS(Blaster);
87
88
CREATE_ENTITY(Blaster, NULL, self->position.x, self->position.y);
89
}
90
91
void Blaster_DebugDraw(void)
92
{
93
RSDK.SetSpriteAnimation(Blaster->aniFrames, 0, &DebugMode->animator, true, 0);
94
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
95
}
96
97
void Blaster_HandlePlayerInteractions(void)
98
{
99
RSDK_THIS(Blaster);
100
101
foreach_active(Player, player)
102
{
103
if (Player_CheckBadnikTouch(player, self, &Blaster->hitboxBadnik))
104
Player_CheckBadnikBreak(player, self, true);
105
106
if (self->state != Blaster_State_AttackPlayer && self->state != Blaster_State_Fall && self->animator.animationID != 3) {
107
if (Player_CheckCollisionTouch(player, self, &Blaster->hitboxRange)) {
108
self->attackTimer = 0;
109
RSDK.SetSpriteAnimation(Blaster->aniFrames, 0, &self->animator, true, 0);
110
self->state = Blaster_State_AttackPlayer;
111
}
112
}
113
}
114
}
115
116
void Blaster_CheckOffScreen(void)
117
{
118
RSDK_THIS(Blaster);
119
120
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
121
self->position = self->startPos;
122
self->direction = self->startDir;
123
Blaster_Create(NULL);
124
}
125
}
126
127
void Blaster_State_Init(void)
128
{
129
RSDK_THIS(Blaster);
130
self->active = ACTIVE_NORMAL;
131
self->velocity.x = self->direction == FLIP_NONE ? -0x8000 : 0x8000;
132
self->velocity.y = 0;
133
self->timer = 256;
134
135
self->state = Blaster_State_Move;
136
Blaster_State_Move();
137
}
138
139
void Blaster_State_Move(void)
140
{
141
RSDK_THIS(Blaster);
142
143
self->position.x += self->velocity.x;
144
RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, 8);
145
146
if (!--self->timer) {
147
self->state = Blaster_State_HandleTurn;
148
self->timer = 30;
149
RSDK.SetSpriteAnimation(Blaster->aniFrames, 0, &self->animator, true, 0);
150
}
151
else if (self->velocity.x < 0 && !RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, -0xE0000, 0x140000, false)) {
152
self->state = Blaster_State_HandleTurn;
153
self->timer = 30;
154
RSDK.SetSpriteAnimation(Blaster->aniFrames, 0, &self->animator, true, 0);
155
}
156
else if (self->velocity.x > 0 && !RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0xE0000, 0x140000, false)) {
157
self->state = Blaster_State_HandleTurn;
158
self->timer = 30;
159
RSDK.SetSpriteAnimation(Blaster->aniFrames, 0, &self->animator, true, 0);
160
}
161
162
RSDK.ProcessAnimation(&self->animator);
163
164
Blaster_HandlePlayerInteractions();
165
Blaster_CheckOffScreen();
166
}
167
168
void Blaster_State_HandleTurn(void)
169
{
170
RSDK_THIS(Blaster);
171
172
RSDK.ProcessAnimation(&self->animator);
173
Blaster_HandlePlayerInteractions();
174
Blaster_CheckOffScreen();
175
176
switch (--self->timer) {
177
case 15: RSDK.SetSpriteAnimation(Blaster->aniFrames, 3, &self->animator, true, 0); break;
178
179
case 7:
180
self->direction ^= FLIP_X;
181
self->velocity.x = -self->velocity.x;
182
break;
183
184
case 0:
185
self->state = Blaster_State_Move;
186
self->timer = 512;
187
Blaster_State_Move();
188
RSDK.SetSpriteAnimation(Blaster->aniFrames, 1, &self->animator, true, 0);
189
break;
190
}
191
}
192
193
void Blaster_State_AttackPlayer(void)
194
{
195
RSDK_THIS(Blaster);
196
197
switch (++self->attackTimer) {
198
case 18: {
199
EntityBlaster *shot = NULL;
200
if (self->direction) {
201
shot = CREATE_ENTITY(Blaster, INT_TO_VOID(BLASTER_SHOT), self->position.x + 0x170000, self->position.y - 0x150000);
202
shot->velocity.x = 0x20000;
203
}
204
else {
205
shot = CREATE_ENTITY(Blaster, INT_TO_VOID(BLASTER_SHOT), self->position.x - 0x170000, self->position.y - 0x150000);
206
shot->velocity.x = -0x20000;
207
}
208
shot->velocity.y = -0x48000;
209
break;
210
}
211
212
case 20: RSDK.SetSpriteAnimation(Blaster->aniFrames, 2, &self->animator, true, 0); break;
213
214
case 24: {
215
EntityBlaster *shell = NULL;
216
if (self->direction) {
217
shell = CREATE_ENTITY(Blaster, INT_TO_VOID(BLASTER_SHELL), self->position.x + 0x60000, self->position.y - 0x30000);
218
shell->velocity.x = -0x10000;
219
}
220
else {
221
shell = CREATE_ENTITY(Blaster, INT_TO_VOID(BLASTER_SHELL), self->position.x - 0x60000, self->position.y - 0x30000);
222
shell->velocity.x = 0x10000;
223
}
224
shell->velocity.y = -0x20000;
225
break;
226
}
227
228
case 60:
229
RSDK.SetSpriteAnimation(Blaster->aniFrames, 1, &self->animator, true, 0);
230
self->state = Blaster_State_Move;
231
self->timer = 512;
232
break;
233
234
default: break;
235
}
236
237
RSDK.ProcessAnimation(&self->animator);
238
239
Blaster_HandlePlayerInteractions();
240
Blaster_CheckOffScreen();
241
}
242
243
void Blaster_State_MagnetAttract(void)
244
{
245
RSDK_THIS(Blaster);
246
247
self->position.y += self->velocity.y;
248
self->velocity.y -= 0x3800;
249
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_ROOF, 0, 0, -0xC0000, 8))
250
self->velocity.y = 0;
251
252
Blaster_HandlePlayerInteractions();
253
254
if (!RSDK.CheckOnScreen(self, NULL)) {
255
Blaster_CheckOffScreen();
256
}
257
258
// Always set us to released state, the electro magnet should reset the state before the next frame
259
self->state = Blaster_State_MagnetReleased;
260
}
261
262
void Blaster_State_MagnetReleased(void)
263
{
264
RSDK_THIS(Blaster);
265
266
self->position.y += self->velocity.y;
267
self->velocity.y += 0x3800;
268
269
Blaster_HandlePlayerInteractions();
270
Blaster_CheckOffScreen();
271
272
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, 8)) {
273
self->velocity.y = 0;
274
self->state = Blaster_State_Move;
275
}
276
else {
277
self->state = Blaster_State_MagnetReleased;
278
}
279
}
280
281
void Blaster_State_BeginShot(void)
282
{
283
RSDK_THIS(Blaster);
284
285
RSDK.ProcessAnimation(&self->animator);
286
287
if (self->animator.frameID == 2)
288
self->state = Blaster_State_Shot;
289
}
290
291
void Blaster_State_Shot(void)
292
{
293
RSDK_THIS(Blaster);
294
295
self->position.x += self->velocity.x;
296
self->position.y += self->velocity.y;
297
self->velocity.y += 0x3800;
298
299
if (RSDK.CheckOnScreen(self, &self->updateRange)) {
300
RSDK.ProcessAnimation(&self->animator);
301
foreach_active(Player, player)
302
{
303
if (Player_CheckCollisionTouch(player, self, &Blaster->hitboxProjectile)) {
304
Player_ProjectileHurt(player, self);
305
}
306
}
307
}
308
else {
309
destroyEntity(self);
310
}
311
}
312
313
void Blaster_State_Fall(void)
314
{
315
RSDK_THIS(Blaster);
316
317
self->position.x += self->velocity.x;
318
self->position.y += self->velocity.y;
319
self->velocity.y += 0x3800;
320
321
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x100000, 8)) {
322
self->startPos.x = self->position.x;
323
self->startPos.y = self->position.y;
324
self->direction = self->direction;
325
self->velocity.y = 0;
326
self->state = Blaster_State_Init;
327
}
328
329
Blaster_HandlePlayerInteractions();
330
}
331
332
void Blaster_State_Shell(void)
333
{
334
RSDK_THIS(Blaster);
335
336
self->position.x += self->velocity.x;
337
self->position.y += self->velocity.y;
338
self->velocity.y += 0x3800;
339
340
RSDK.ProcessAnimation(&self->animator);
341
342
if (!RSDK.CheckOnScreen(self, &self->updateRange))
343
destroyEntity(self);
344
}
345
346
#if GAME_INCLUDE_EDITOR
347
void Blaster_EditorDraw(void)
348
{
349
RSDK_THIS(Blaster);
350
351
RSDK.SetSpriteAnimation(Blaster->aniFrames, 1, &self->animator, true, 0);
352
353
Blaster_Draw();
354
}
355
356
void Blaster_EditorLoad(void)
357
{
358
Blaster->aniFrames = RSDK.LoadSpriteAnimation("FBZ/Blaster.bin", SCOPE_STAGE);
359
360
RSDK_ACTIVE_VAR(Blaster, direction);
361
RSDK_ENUM_VAR("Left", FLIP_NONE);
362
RSDK_ENUM_VAR("Right", FLIP_X);
363
}
364
#endif
365
366
void Blaster_Serialize(void) { RSDK_EDITABLE_VAR(Blaster, VAR_UINT8, direction); }
367
368