Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/OOZ/Sol.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Sol Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectSol *Sol;
11
12
void Sol_Update(void)
13
{
14
RSDK_THIS(Sol);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Sol_LateUpdate(void) {}
20
21
void Sol_StaticUpdate(void) {}
22
23
void Sol_Draw(void)
24
{
25
RSDK_THIS(Sol);
26
27
for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {
28
if ((1 << i) & self->activeOrbs)
29
RSDK.DrawSprite(&self->ballAnimator, &self->positions[i], false);
30
}
31
32
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
33
}
34
35
void Sol_Create(void *data)
36
{
37
RSDK_THIS(Sol);
38
39
self->visible = true;
40
self->drawGroup = Zone->objectDrawGroup[0];
41
self->drawFX = FX_FLIP;
42
43
if (data) {
44
RSDK.SetSpriteAnimation(Sol->aniFrames, 1, &self->mainAnimator, true, 0);
45
self->active = ACTIVE_NORMAL;
46
self->drawFX |= FX_ROTATE;
47
self->updateRange.x = 0x1000000;
48
self->updateRange.y = 0x1000000;
49
self->state = Sol_State_SmallFireball;
50
}
51
else {
52
self->startPos = self->position;
53
self->startDir = self->direction;
54
self->active = ACTIVE_BOUNDS;
55
self->updateRange.x = 0x800000;
56
self->updateRange.y = 0x800000;
57
self->activeOrbs = 2 | 8;
58
59
RSDK.SetSpriteAnimation(Sol->aniFrames, 0, &self->mainAnimator, true, 0);
60
RSDK.SetSpriteAnimation(Sol->aniFrames, 1, &self->ballAnimator, true, 0);
61
self->state = Sol_State_Init;
62
self->velocity.x = self->direction == FLIP_NONE ? -0x4000 : 0x4000;
63
}
64
}
65
66
void Sol_StageLoad(void)
67
{
68
if (RSDK.CheckSceneFolder("OOZ1") || RSDK.CheckSceneFolder("OOZ2"))
69
Sol->aniFrames = RSDK.LoadSpriteAnimation("OOZ/Sol.bin", SCOPE_STAGE);
70
71
Sol->hitboxBadnik.left = -8;
72
Sol->hitboxBadnik.top = -8;
73
Sol->hitboxBadnik.right = 8;
74
Sol->hitboxBadnik.bottom = 8;
75
76
Sol->hitboxOrb.left = -4;
77
Sol->hitboxOrb.top = -4;
78
Sol->hitboxOrb.right = 4;
79
Sol->hitboxOrb.bottom = 4;
80
81
DEBUGMODE_ADD_OBJ(Sol);
82
}
83
84
void Sol_DebugSpawn(void)
85
{
86
RSDK_THIS(Sol);
87
88
CREATE_ENTITY(Sol, NULL, self->position.x, self->position.y);
89
}
90
91
void Sol_DebugDraw(void)
92
{
93
RSDK.SetSpriteAnimation(Sol->aniFrames, 0, &DebugMode->animator, true, 0);
94
RSDK.DrawSprite(&DebugMode->animator, 0, false);
95
}
96
97
void Sol_HandlePlayerInteractions(void)
98
{
99
RSDK_THIS(Sol);
100
101
int32 storeX = self->position.x;
102
int32 storeY = self->position.y;
103
104
for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {
105
if ((1 << i) & self->activeOrbs) {
106
self->position.x = self->positions[i].x;
107
self->position.y = self->positions[i].y;
108
109
foreach_active(Player, player)
110
{
111
#if MANIA_USE_PLUS
112
if (player->state != Player_State_MightyHammerDrop) {
113
#endif
114
Sol_HandlePlayerHurt();
115
#if MANIA_USE_PLUS
116
}
117
#endif
118
}
119
}
120
}
121
122
self->position.x = storeX;
123
self->position.y = storeY;
124
125
foreach_active(Player, player)
126
{
127
if (Player_CheckBadnikTouch(player, self, &Sol->hitboxBadnik) && Player_CheckBadnikBreak(player, self, false)) {
128
int32 angle = self->angle;
129
for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {
130
if ((1 << i) & self->activeOrbs) {
131
self->position.x = self->positions[i].x;
132
self->position.y = self->positions[i].y;
133
134
EntitySol *sol = CREATE_ENTITY(Sol, INT_TO_VOID(true), self->positions[i].x, self->positions[i].y);
135
136
sol->state = Sol_State_ActiveFireball;
137
#if MANIA_USE_PLUS
138
if (player->state == Player_State_MightyHammerDrop)
139
sol->interaction = false;
140
#endif
141
sol->velocity.x = 0x380 * RSDK.Cos256(angle);
142
sol->velocity.y = 0x380 * RSDK.Sin256(angle);
143
}
144
145
angle += (0x100 / SOL_FLAMEORB_COUNT);
146
}
147
148
destroyEntity(self);
149
}
150
}
151
}
152
153
void Sol_HandlePlayerHurt(void)
154
{
155
RSDK_THIS(Sol);
156
157
foreach_active(Player, player)
158
{
159
if (Player_CheckCollisionTouch(player, self, &Sol->hitboxOrb)) {
160
Player_ElementHurt(player, self, SHIELD_FIRE);
161
}
162
}
163
}
164
165
void Sol_HandleRotation(void)
166
{
167
RSDK_THIS(Sol);
168
169
int32 angle = self->angle;
170
if (self->direction)
171
self->angle = (angle - 1) & 0xFF;
172
else
173
self->angle = (angle + 1) & 0xFF;
174
175
for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {
176
if ((1 << i) & self->activeOrbs) {
177
self->positions[i].x = (RSDK.Cos256(angle) << 12) + self->position.x;
178
self->positions[i].y = (RSDK.Sin256(angle) << 12) + self->position.y;
179
}
180
181
angle += (0x100 / SOL_FLAMEORB_COUNT);
182
}
183
}
184
185
void Sol_CheckOffScreen(void)
186
{
187
RSDK_THIS(Sol);
188
189
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
190
self->position = self->startPos;
191
self->direction = self->startDir;
192
Sol_Create(NULL);
193
}
194
}
195
196
void Sol_State_Init(void)
197
{
198
RSDK_THIS(Sol);
199
200
self->active = ACTIVE_NORMAL;
201
202
self->state = Sol_State_Moving;
203
Sol_State_Moving();
204
}
205
206
void Sol_State_Moving(void)
207
{
208
RSDK_THIS(Sol);
209
210
RSDK.ProcessAnimation(&self->ballAnimator);
211
212
self->position.x += self->velocity.x;
213
self->position.y = (RSDK.Sin256(self->oscillateAngle) << 10) + self->startPos.y;
214
self->oscillateAngle += 4;
215
216
Sol_HandleRotation();
217
Sol_HandlePlayerInteractions();
218
219
if (self->fireOrbs) {
220
EntityPlayer *playerPtr = NULL;
221
int32 distanceX = 0x7FFFFFFF;
222
int32 distanceY = 0x7FFFFFFF;
223
224
foreach_active(Player, player)
225
{
226
if (abs(player->position.y - self->position.y) < distanceY)
227
distanceY = abs(player->position.y - self->position.y);
228
229
if (abs(player->position.y - self->position.y) < 0x400000) {
230
if (!playerPtr) {
231
if (abs(player->position.x - self->position.x) < distanceX) {
232
distanceX = abs(player->position.x - self->position.x);
233
playerPtr = player;
234
}
235
}
236
else {
237
if (abs(player->position.x - self->position.x) < distanceX) {
238
distanceX = abs(player->position.x - self->position.x);
239
playerPtr = player;
240
}
241
}
242
}
243
}
244
245
if (!playerPtr)
246
playerPtr = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
247
248
if (distanceX <= 0x800000) {
249
self->state = Sol_State_ShootingOrbs;
250
self->mainAnimator.frameID = 1;
251
}
252
253
self->direction = playerPtr->position.x >= self->position.x;
254
}
255
256
Sol_CheckOffScreen();
257
}
258
259
void Sol_State_ShootingOrbs(void)
260
{
261
RSDK_THIS(Sol);
262
263
RSDK.ProcessAnimation(&self->ballAnimator);
264
265
self->position.x += self->velocity.x;
266
self->position.y = (RSDK.Sin256(self->oscillateAngle) << 10) + self->startPos.y;
267
self->oscillateAngle += 4;
268
269
uint8 angle = self->angle;
270
Sol_HandleRotation();
271
272
for (int32 i = 0; i < SOL_FLAMEORB_COUNT; ++i) {
273
if (angle == 0x40) {
274
if ((1 << i) & self->activeOrbs) {
275
self->activeOrbs &= ~(1 << i);
276
EntitySol *sol = CREATE_ENTITY(Sol, INT_TO_VOID(true), self->positions[i].x, self->positions[i].y);
277
sol->velocity.x = self->direction == FLIP_NONE ? -0x20000 : 0x20000;
278
}
279
}
280
281
angle += (0x100 / SOL_FLAMEORB_COUNT);
282
}
283
284
Sol_HandlePlayerInteractions();
285
286
if (!self->activeOrbs) {
287
self->state = Sol_State_NoOrbs;
288
self->velocity.x = self->direction == FLIP_NONE ? -0x4000 : 0x4000;
289
}
290
291
if (self->mainAnimator.timer >= 0x10)
292
self->mainAnimator.frameID = 2;
293
else
294
self->mainAnimator.timer++;
295
296
Sol_CheckOffScreen();
297
}
298
299
void Sol_State_NoOrbs(void)
300
{
301
RSDK_THIS(Sol);
302
303
RSDK.ProcessAnimation(&self->ballAnimator);
304
305
self->position.x += self->velocity.x;
306
self->position.y = (RSDK.Sin256(self->oscillateAngle) << 10) + self->startPos.y;
307
self->oscillateAngle += 4;
308
309
Sol_HandleRotation();
310
Sol_HandlePlayerInteractions();
311
Sol_CheckOffScreen();
312
}
313
314
void Sol_State_SmallFireball(void)
315
{
316
RSDK_THIS(Sol);
317
318
RSDK.ProcessAnimation(&self->mainAnimator);
319
320
self->position.x += self->velocity.x;
321
322
if (RSDK.CheckOnScreen(self, &self->updateRange))
323
Sol_HandlePlayerHurt();
324
else
325
destroyEntity(self);
326
}
327
328
void Sol_State_ActiveFireball(void)
329
{
330
RSDK_THIS(Sol);
331
332
if (RSDK.CheckOnScreen(self, &self->updateRange)) {
333
self->position.x += self->velocity.x;
334
self->position.y += self->velocity.y;
335
self->velocity.y += 0x3800;
336
337
self->rotation = 2 * RSDK.ATan2(self->velocity.x >> 16, self->velocity.y >> 16) + 384;
338
339
int32 offsetX = RSDK.Sin512(512 - self->rotation) << 10;
340
int32 offsetY = RSDK.Cos512(512 - self->rotation) << 10;
341
int32 cmode = 3 - (((self->rotation - 0x40) >> 7) & 3);
342
343
bool32 collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, cmode, 1, offsetX, offsetY, true);
344
if (!collided)
345
collided = RSDK.ObjectTileCollision(self, Zone->collisionLayers, cmode, 0, offsetX, offsetY, true);
346
347
if (collided) {
348
RSDK.SetSpriteAnimation(Sol->aniFrames, 2, &self->mainAnimator, true, 0);
349
self->state = Sol_State_FlameDissipate;
350
self->rotation = (self->rotation + 64) & 0x180;
351
}
352
353
int32 spawnX = self->position.x + offsetX;
354
int32 spawnY = self->position.y + offsetY;
355
uint16 tile = RSDK.GetTile(Zone->fgLayer[1], spawnX >> 20, (spawnY - 0x10000) >> 20);
356
if (tile == (uint16)-1)
357
tile = RSDK.GetTile(Zone->fgLayer[0], spawnX >> 20, (spawnY - 0x10000) >> 20);
358
359
int32 tileFlags = RSDK.GetTileFlags(tile, 0);
360
if (((tileFlags == OOZ_TFLAGS_OILSTRIP || tileFlags == OOZ_TFLAGS_OILSLIDE) && collided) || tileFlags == OOZ_TFLAGS_OILPOOL) {
361
self->position.x = spawnX - 0x40000;
362
self->position.y = spawnY - 0x80000;
363
self->rotation = 0;
364
self->velocity.x = -0x40000;
365
self->velocity.y = 0;
366
RSDK.SetSpriteAnimation(Sol->aniFrames, 3, &self->mainAnimator, true, 0);
367
self->state = Sol_State_FireballOilFlame;
368
369
EntitySol *sol = CREATE_ENTITY(Sol, INT_TO_VOID(true), spawnX, spawnY - 0x80000);
370
sol->velocity.x = 0x40000;
371
sol->velocity.y = 0;
372
RSDK.SetSpriteAnimation(Sol->aniFrames, 3, &sol->mainAnimator, true, 0);
373
sol->state = Sol_State_FireballOilFlame;
374
sol->oscillateAngle = sol->position.x & 0xF00000;
375
376
if (tileFlags == OOZ_TFLAGS_OILPOOL) {
377
self->position.y = (self->position.y & 0xFFF00000) + 0x20000;
378
sol->position.y = (sol->position.y & 0xFFF00000) + 0x20000;
379
sol->state = Sol_State_OilFlame;
380
self->state = Sol_State_OilFlame;
381
}
382
else {
383
self->position.y -= 0x80000;
384
}
385
}
386
387
if (self->interaction)
388
Sol_HandlePlayerHurt();
389
}
390
else {
391
destroyEntity(self);
392
}
393
}
394
395
void Sol_State_FlameDissipate(void)
396
{
397
RSDK_THIS(Sol);
398
399
RSDK.ProcessAnimation(&self->mainAnimator);
400
401
if (!RSDK.CheckOnScreen(self, &self->updateRange) || self->mainAnimator.frameID == self->mainAnimator.frameCount - 1) {
402
destroyEntity(self);
403
}
404
}
405
406
void Sol_State_FireballOilFlame(void)
407
{
408
RSDK_THIS(Sol);
409
410
if (RSDK.CheckOnScreen(self, &self->updateRange)) {
411
bool32 collided = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 1, 0, 0x80000, 16);
412
if (!collided)
413
collided = RSDK.ObjectTileGrip(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0x80000, 16);
414
415
if (collided) {
416
uint16 tile = RSDK.GetTile(Zone->fgLayer[1], self->position.x >> 20, (self->position.y + 0x90000) >> 20);
417
if (tile == (uint16)-1)
418
tile = RSDK.GetTile(Zone->fgLayer[0], self->position.x >> 20, (self->position.y + 0x90000) >> 20);
419
420
self->rotation = 2 * RSDK.GetTileAngle(tile, 0, 0);
421
}
422
423
uint16 tile = RSDK.GetTile(Zone->fgLayer[1], self->position.x >> 20, (self->position.y + 0x70000) >> 20);
424
if (tile == (uint16)-1)
425
tile = RSDK.GetTile(Zone->fgLayer[0], self->position.x >> 20, (self->position.y + 0x70000) >> 20);
426
427
int32 tileFlags = RSDK.GetTileFlags(tile, 0);
428
if (tileFlags == OOZ_TFLAGS_NORMAL || tileFlags == OOZ_TFLAGS_OILFALL) {
429
if (collided) {
430
RSDK.SetSpriteAnimation(Sol->aniFrames, 2, &self->mainAnimator, true, 0);
431
self->state = Sol_State_FlameDissipate;
432
}
433
else {
434
self->state = Sol_State_ActiveFireball;
435
}
436
}
437
else {
438
self->position.y -= 0x80000;
439
if ((self->position.x & 0xF00000) != self->oscillateAngle)
440
OOZSetup_StartFire((self->position.x & 0xFFF00000) + 0x70000, self->position.y & 0xFFFF0000, self->rotation >> 1);
441
442
self->oscillateAngle = self->position.x & 0xF00000;
443
}
444
445
self->position.x += self->velocity.x;
446
self->position.y += 0x80000;
447
448
RSDK.ProcessAnimation(&self->mainAnimator);
449
450
Sol_HandlePlayerHurt();
451
}
452
else {
453
destroyEntity(self);
454
}
455
}
456
457
void Sol_State_OilFlame(void)
458
{
459
RSDK_THIS(Sol);
460
461
if (RSDK.CheckOnScreen(self, &self->updateRange)) {
462
uint16 tile = RSDK.GetTile(Zone->fgLayer[1], self->position.x >> 20, (self->position.y + 0xF0000) >> 20);
463
if (tile == (uint16)-1)
464
tile = RSDK.GetTile(Zone->fgLayer[0], self->position.x >> 20, (self->position.y + 0xF0000) >> 20);
465
466
if (RSDK.GetTileFlags(tile, 0) == OOZ_TFLAGS_OILPOOL) {
467
if ((self->position.x & 0xF00000) != self->oscillateAngle)
468
OOZSetup_StartFire((self->position.x & 0xFFF00000) + 0x70000, self->position.y & 0xFFFF0000, self->rotation >> 1);
469
470
self->oscillateAngle = self->position.x & 0xF00000;
471
}
472
else {
473
RSDK.SetSpriteAnimation(Sol->aniFrames, 2, &self->mainAnimator, true, 0);
474
self->state = Sol_State_FlameDissipate;
475
}
476
477
self->position.x += self->velocity.x;
478
479
RSDK.ProcessAnimation(&self->mainAnimator);
480
481
Sol_HandlePlayerHurt();
482
}
483
else {
484
destroyEntity(self);
485
}
486
}
487
488
#if GAME_INCLUDE_EDITOR
489
void Sol_EditorDraw(void)
490
{
491
RSDK_THIS(Sol);
492
493
int32 angle = self->angle;
494
Sol_HandleRotation();
495
self->angle = angle;
496
497
Sol_Draw();
498
}
499
500
void Sol_EditorLoad(void)
501
{
502
Sol->aniFrames = RSDK.LoadSpriteAnimation("OOZ/Sol.bin", SCOPE_STAGE);
503
504
RSDK_ACTIVE_VAR(Sol, direction);
505
RSDK_ENUM_VAR("Left", FLIP_NONE);
506
RSDK_ENUM_VAR("Right", FLIP_X);
507
}
508
#endif
509
510
void Sol_Serialize(void)
511
{
512
RSDK_EDITABLE_VAR(Sol, VAR_UINT8, direction);
513
RSDK_EDITABLE_VAR(Sol, VAR_BOOL, fireOrbs);
514
}
515
516