Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/LRZ/Fireworm.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Fireworm Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectFireworm *Fireworm;
11
12
void Fireworm_Update(void)
13
{
14
RSDK_THIS(Fireworm);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Fireworm_LateUpdate(void) {}
20
21
void Fireworm_StaticUpdate(void) {}
22
23
void Fireworm_Draw(void)
24
{
25
RSDK_THIS(Fireworm);
26
27
self->drawFX &= ~FX_FLIP;
28
Fireworm->holeAnimator.frameID = 0;
29
RSDK.DrawSprite(&Fireworm->holeAnimator, &self->startPos, false);
30
31
self->drawFX |= FX_FLIP;
32
if (self->state) {
33
// Draw Body
34
for (int32 i = FIREWORM_SEGMENT_COUNT - 1; i > 0; --i) {
35
self->direction = self->bodyDirections[i];
36
RSDK.DrawSprite(&self->bodyAnimators[i], &self->bodyPositions[i], false);
37
RSDK.DrawSprite(&self->flameAnimators[i], &self->bodyPositions[i], false);
38
}
39
40
// Draw Head
41
self->direction = self->bodyDirections[0];
42
RSDK.DrawSprite(&self->bodyAnimators[0], NULL, false);
43
}
44
}
45
46
void Fireworm_Create(void *data)
47
{
48
RSDK_THIS(Fireworm);
49
50
self->drawFX |= FX_FLIP;
51
52
// Head
53
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 0, &self->bodyAnimators[0], true, 0);
54
55
if (!SceneInfo->inEditor) {
56
for (int32 i = 0; i < FIREWORM_SEGMENT_COUNT; ++i) {
57
self->bodyPositions[i].x = self->position.x;
58
self->bodyPositions[i].y = self->position.y;
59
self->bodyOriginY[i] = self->position.y;
60
}
61
62
self->startPos = self->position;
63
self->startDir = self->direction;
64
self->visible = true;
65
self->active = ACTIVE_BOUNDS;
66
self->updateRange.x = 0x800000;
67
self->updateRange.y = 0x800000;
68
self->drawGroup = Zone->objectDrawGroup[0];
69
self->state = Fireworm_State_Init;
70
}
71
}
72
73
void Fireworm_StageLoad(void)
74
{
75
if (RSDK.CheckSceneFolder("LRZ1"))
76
Fireworm->aniFrames = RSDK.LoadSpriteAnimation("LRZ1/Fireworm.bin", SCOPE_STAGE);
77
else if (RSDK.CheckSceneFolder("LRZ2") || RSDK.CheckSceneFolder("LRZ3"))
78
Fireworm->aniFrames = RSDK.LoadSpriteAnimation("LRZ2/Fireworm.bin", SCOPE_STAGE);
79
80
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 6, &Fireworm->holeAnimator, true, 0);
81
82
Fireworm->hitboxBadnik.left = -8;
83
Fireworm->hitboxBadnik.top = -8;
84
Fireworm->hitboxBadnik.right = 8;
85
Fireworm->hitboxBadnik.bottom = 8;
86
87
Fireworm->hitboxRange.left = -128;
88
Fireworm->hitboxRange.top = -128;
89
Fireworm->hitboxRange.right = 128;
90
Fireworm->hitboxRange.bottom = 128;
91
92
DEBUGMODE_ADD_OBJ(Fireworm);
93
}
94
95
void Fireworm_DebugSpawn(void)
96
{
97
RSDK_THIS(DebugMode);
98
99
CREATE_ENTITY(Fireworm, NULL, self->position.x, self->position.y);
100
}
101
102
void Fireworm_DebugDraw(void)
103
{
104
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 0, &DebugMode->animator, true, 0);
105
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
106
}
107
108
void Fireworm_CheckPlayerCollisions(void)
109
{
110
RSDK_THIS(Fireworm);
111
112
foreach_active(Player, player)
113
{
114
// Collide with the head
115
self->position.x = self->bodyPositions[0].x;
116
self->position.y = self->bodyPositions[0].y;
117
118
if (Player_CheckBadnikTouch(player, self, &Fireworm->hitboxBadnik) && Player_CheckBadnikBreak(player, self, false)) {
119
for (int32 i = 1; i < FIREWORM_SEGMENT_COUNT; ++i) {
120
EntityDebris *debris = CREATE_ENTITY(Debris, Debris_State_FallAndFlicker, self->bodyPositions[i].x, self->bodyPositions[i].y);
121
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 3, &debris->animator, true, 0);
122
debris->velocity.x = RSDK.Rand(-0x40000, 0x40000);
123
debris->velocity.y = RSDK.Rand(-0x40000, 0x40000);
124
debris->gravityStrength = 0x3800;
125
debris->drawGroup = Zone->objectDrawGroup[0];
126
debris->updateRange.x = 0x400000;
127
debris->updateRange.y = 0x400000;
128
}
129
130
self->state = StateMachine_None;
131
foreach_break;
132
}
133
else {
134
// Collide with the rest of the body
135
for (int32 i = 1; i < FIREWORM_SEGMENT_COUNT; ++i) {
136
self->position.x = self->bodyPositions[i].x;
137
self->position.y = self->bodyPositions[i].y;
138
139
if (Player_CheckCollisionTouch(player, self, &Fireworm->hitboxBadnik)) {
140
#if MANIA_USE_PLUS
141
if (!Player_CheckMightyUnspin(player, 0x300, 2, &player->uncurlTimer))
142
#endif
143
Player_Hurt(player, self);
144
}
145
}
146
}
147
}
148
149
if (self->state) {
150
self->position.x = self->bodyPositions[0].x;
151
self->position.y = self->bodyPositions[0].y;
152
}
153
}
154
155
void Fireworm_CheckOffScreen(void)
156
{
157
RSDK_THIS(Fireworm);
158
159
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
160
self->timer = 0;
161
self->position = self->startPos;
162
self->direction = self->startDir;
163
164
for (int32 i = 0; i < FIREWORM_SEGMENT_COUNT; ++i) {
165
self->bodyVelocities[i].x = 0;
166
self->bodyAngles[i] = 0;
167
self->bodyTimers[i] = 0;
168
169
if (i > 0) {
170
RSDK.SetSpriteAnimation(-1, 0, &self->bodyAnimators[i], true, 0);
171
RSDK.SetSpriteAnimation(-1, 0, &self->flameAnimators[i], true, 0);
172
}
173
}
174
175
Fireworm_Create(NULL);
176
}
177
}
178
179
void Fireworm_State_Init(void)
180
{
181
RSDK_THIS(Fireworm);
182
183
self->active = ACTIVE_NORMAL;
184
185
self->state = Fireworm_State_AwaitPlayer;
186
Fireworm_State_AwaitPlayer();
187
}
188
189
void Fireworm_State_AwaitPlayer(void)
190
{
191
RSDK_THIS(Fireworm);
192
193
foreach_active(Player, player)
194
{
195
if (Player_CheckCollisionTouch(player, self, &Fireworm->hitboxRange)) {
196
for (int32 i = 0; i < FIREWORM_SEGMENT_COUNT; ++i) {
197
self->bodyDirections[i] = player->position.x >= self->position.x;
198
}
199
200
self->startDir = self->bodyDirections[0];
201
202
if (self->startDir) {
203
self->bodyVelocities[0].x = 0x10000;
204
self->boundsL = self->position.x - 0x3C0000;
205
self->boundsR = self->position.x + 0xBC0000;
206
}
207
else {
208
self->bodyVelocities[0].x = -0x10000;
209
self->boundsL = self->position.x - 0xBC0000;
210
self->boundsR = self->position.x + 0x3C0000;
211
}
212
213
self->state = Fireworm_State_HeadAppear;
214
foreach_break;
215
}
216
}
217
218
if (self->state == Fireworm_State_BodyAppear)
219
Fireworm_CheckOffScreen();
220
}
221
222
void Fireworm_State_HeadAppear(void)
223
{
224
RSDK_THIS(Fireworm);
225
226
RSDK.ProcessAnimation(&self->bodyAnimators[0]);
227
228
if (self->bodyAnimators[0].frameID == 3) {
229
for (int32 i = 1; i < FIREWORM_SEGMENT_COUNT; ++i) {
230
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 3, &self->bodyAnimators[i], true, 0);
231
self->flameExhaustDelays[i] = RSDK.Rand(0, 60);
232
}
233
234
self->state = Fireworm_State_BodyAppear;
235
}
236
}
237
238
void Fireworm_State_BodyAppear(void)
239
{
240
RSDK_THIS(Fireworm);
241
242
++self->timer;
243
244
for (int32 i = 0; i < FIREWORM_SEGMENT_COUNT; ++i) {
245
if (self->timer == (i * 10) + 4) {
246
self->bodyVelocities[i].x = self->bodyDirections[i] ? 0x10000 : -0x10000;
247
248
if (i == FIREWORM_SEGMENT_COUNT - 1) {
249
self->timer = 0;
250
self->state = Fireworm_State_FlyAround;
251
}
252
}
253
}
254
255
Fireworm_State_FlyAround();
256
}
257
258
void Fireworm_State_FlyAround(void)
259
{
260
RSDK_THIS(Fireworm);
261
262
for (int32 i = 0; i < FIREWORM_SEGMENT_COUNT; ++i) {
263
if (!self->bodyVelocities[i].x)
264
continue;
265
266
RSDK.ProcessAnimation(&self->bodyAnimators[i]);
267
RSDK.ProcessAnimation(&self->flameAnimators[i]);
268
269
self->bodyPositions[i].x += self->bodyVelocities[i].x;
270
271
if (self->bodyVelocities[i].x <= 0) {
272
if (self->bodyPositions[i].x > self->boundsL) {
273
self->bodyVelocities[i].x -= 0xC00;
274
275
if (self->bodyVelocities[i].x < -0x10000)
276
self->bodyVelocities[i].x = -0x10000;
277
}
278
else {
279
self->bodyVelocities[i].x += 0xC00;
280
281
if (self->bodyVelocities[i].x > 0x10000)
282
self->bodyVelocities[i].x = 0x10000;
283
284
if (!self->bodyTimers[i]) {
285
if (i)
286
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 4, &self->bodyAnimators[i], true, 0);
287
else
288
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 2, &self->bodyAnimators[i], true, 0);
289
290
self->bodyDirections[i] = FLIP_X;
291
self->bodyVelocities[i].y = self->startDir ? 0x10000 : -0x10000;
292
self->bodyTimers[i] = 32;
293
}
294
}
295
}
296
else {
297
if (self->bodyPositions[i].x < self->boundsR) {
298
self->bodyVelocities[i].x += 0xC00;
299
300
if (self->bodyVelocities[i].x > 0x10000)
301
self->bodyVelocities[i].x = 0x10000;
302
}
303
else {
304
self->bodyVelocities[i].x -= 0xC00;
305
306
if (self->bodyVelocities[i].x < -0x10000)
307
self->bodyVelocities[i].x = -0x10000;
308
309
if (!self->bodyTimers[i]) {
310
if (i)
311
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 4, &self->bodyAnimators[i], true, 0);
312
else
313
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 2, &self->bodyAnimators[i], true, 0);
314
315
self->bodyDirections[i] = FLIP_NONE;
316
self->bodyVelocities[i].y = self->startDir ? -0x10000 : 0x10000;
317
self->bodyTimers[i] = 32;
318
}
319
}
320
}
321
322
if (self->bodyTimers[i]) {
323
self->bodyTimers[i]--;
324
self->bodyOriginY[i] += self->bodyVelocities[i].y;
325
}
326
327
if (!--self->flameExhaustDelays[i]) {
328
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 5, &self->flameAnimators[i], true, 0);
329
self->flameExhaustDelays[i] = RSDK.Rand(0, 60) + 32;
330
}
331
332
self->bodyAngles[i] += 16;
333
self->bodyPositions[i].y = (RSDK.Sin1024(self->bodyAngles[i]) << 8) + self->bodyOriginY[i];
334
self->bodyAngles[i] %= 0xC00;
335
}
336
337
Fireworm_CheckPlayerCollisions();
338
Fireworm_CheckOffScreen();
339
}
340
341
#if GAME_INCLUDE_EDITOR
342
void Fireworm_EditorDraw(void)
343
{
344
RSDK_THIS(Fireworm);
345
346
for (int32 i = 0; i < FIREWORM_SEGMENT_COUNT; ++i) {
347
self->bodyPositions[i].x = self->position.x + (self->direction ? 0x100000 : -0x100000) * i;
348
self->bodyPositions[i].y = self->position.y;
349
self->bodyOriginY[i] = self->position.y;
350
}
351
352
self->startPos.x = self->position.x;
353
self->startPos.y = self->position.y;
354
self->startDir = self->direction;
355
356
for (int32 i = 1; i < FIREWORM_SEGMENT_COUNT; ++i) {
357
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 3, &self->bodyAnimators[i], true, 0);
358
}
359
360
Fireworm_Draw();
361
}
362
363
void Fireworm_EditorLoad(void)
364
{
365
if (RSDK.CheckSceneFolder("LRZ1"))
366
Fireworm->aniFrames = RSDK.LoadSpriteAnimation("LRZ1/Fireworm.bin", SCOPE_STAGE);
367
else if (RSDK.CheckSceneFolder("LRZ2") || RSDK.CheckSceneFolder("LRZ3"))
368
Fireworm->aniFrames = RSDK.LoadSpriteAnimation("LRZ2/Fireworm.bin", SCOPE_STAGE);
369
370
RSDK.SetSpriteAnimation(Fireworm->aniFrames, 6, &Fireworm->holeAnimator, true, 0);
371
372
RSDK_ACTIVE_VAR(Fireworm, direction);
373
RSDK_ENUM_VAR("Left", FLIP_NONE);
374
RSDK_ENUM_VAR("Right", FLIP_X);
375
}
376
#endif
377
378
void Fireworm_Serialize(void) { RSDK_EDITABLE_VAR(Fireworm, VAR_UINT8, direction); }
379
380