Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/SBZ/Orbinaut.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Orbinaut Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectOrbinaut *Orbinaut = NULL;
11
12
void Orbinaut_Update(void)
13
{
14
RSDK_THIS(Orbinaut);
15
StateMachine_Run(self->state);
16
}
17
18
void Orbinaut_LateUpdate(void) {}
19
20
void Orbinaut_StaticUpdate(void) {}
21
22
void Orbinaut_Draw(void)
23
{
24
RSDK_THIS(Orbinaut);
25
26
for (int32 o = 0; o < ORBINAUT_ORB_COUNT; ++o) {
27
if ((1 << o) & self->activeOrbs) {
28
RSDK.DrawSprite(&self->animatorOrb, &self->orbPositions[o], false);
29
}
30
}
31
32
RSDK.DrawSprite(&self->animatorFace, NULL, false);
33
}
34
35
void Orbinaut_Create(void *data)
36
{
37
RSDK_THIS(Orbinaut);
38
39
self->visible = true;
40
if (self->planeFilter > 0 && ((self->planeFilter - 1) & 2))
41
self->drawGroup = Zone->objectDrawGroup[1];
42
else
43
self->drawGroup = Zone->objectDrawGroup[0];
44
self->drawFX |= FX_FLIP;
45
self->startPos = self->position;
46
self->startDir = self->direction;
47
self->active = ACTIVE_BOUNDS;
48
self->updateRange.x = 0x800000;
49
self->updateRange.y = 0x800000;
50
self->activeOrbs = 1 | 2 | 4 | 8;
51
if (data) {
52
RSDK.SetSpriteAnimation(Orbinaut->aniFrames, 1, &self->animatorFace, true, 0);
53
self->state = Orbinaut_State_Orb;
54
}
55
else {
56
RSDK.SetSpriteAnimation(Orbinaut->aniFrames, 0, &self->animatorFace, true, 0);
57
RSDK.SetSpriteAnimation(Orbinaut->aniFrames, 1, &self->animatorOrb, true, 0);
58
self->state = Orbinaut_State_Init;
59
if (self->fireOrbs) {
60
self->velocity.x = 0;
61
}
62
else {
63
if (self->direction == FLIP_NONE)
64
self->velocity.x = -0x4000;
65
else
66
self->velocity.x = 0x4000;
67
}
68
}
69
}
70
71
void Orbinaut_StageLoad(void)
72
{
73
if (RSDK.CheckSceneFolder("MMZ"))
74
Orbinaut->aniFrames = RSDK.LoadSpriteAnimation("MMZ/Orbinaut.bin", SCOPE_STAGE);
75
76
Orbinaut->hitboxBadnik.left = -8;
77
Orbinaut->hitboxBadnik.top = -8;
78
Orbinaut->hitboxBadnik.right = 8;
79
Orbinaut->hitboxBadnik.bottom = 8;
80
81
Orbinaut->hitboxOrb.left = -4;
82
Orbinaut->hitboxOrb.top = -4;
83
Orbinaut->hitboxOrb.right = 4;
84
Orbinaut->hitboxOrb.bottom = 4;
85
86
DEBUGMODE_ADD_OBJ(Orbinaut);
87
}
88
89
void Orbinaut_DebugSpawn(void)
90
{
91
RSDK_THIS(Orbinaut);
92
CREATE_ENTITY(Orbinaut, NULL, self->position.x, self->position.y);
93
}
94
95
void Orbinaut_DebugDraw(void)
96
{
97
RSDK.SetSpriteAnimation(Orbinaut->aniFrames, 0, &DebugMode->animator, true, 0);
98
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
99
}
100
101
void Orbinaut_HandlePlayerInteractions(void)
102
{
103
RSDK_THIS(Orbinaut);
104
105
int32 storeX = self->position.x;
106
int32 storeY = self->position.y;
107
for (int32 i = 0; i < ORBINAUT_ORB_COUNT; ++i) {
108
if ((1 << i) & self->activeOrbs) {
109
self->position.x = self->orbPositions[i].x;
110
self->position.y = self->orbPositions[i].y;
111
foreach_active(Player, player)
112
{
113
if (self->planeFilter <= 0 || player->collisionPlane == (uint8)((self->planeFilter - 1) & 1)) {
114
if (Player_CheckCollisionTouch(player, self, &Orbinaut->hitboxOrb)) {
115
Player_Hurt(player, self);
116
}
117
}
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, &Orbinaut->hitboxBadnik) && Player_CheckBadnikBreak(player, self, false)) {
128
int32 angle = self->angle;
129
for (int32 i = 0; i < ORBINAUT_ORB_COUNT; ++i) {
130
if ((1 << i) & self->activeOrbs) {
131
self->position.x = self->orbPositions[i].x;
132
self->position.y = self->orbPositions[i].y;
133
EntityOrbinaut *orb = CREATE_ENTITY(Orbinaut, INT_TO_VOID(true), self->orbPositions[i].x, self->orbPositions[i].y);
134
135
orb->state = Orbinaut_State_OrbDebris;
136
orb->velocity.x = 0x380 * RSDK.Cos256(angle);
137
orb->velocity.y = 0x380 * RSDK.Sin256(angle);
138
}
139
angle += (0x100 / ORBINAUT_ORB_COUNT);
140
}
141
destroyEntity(self);
142
}
143
}
144
}
145
146
void Orbinaut_HandleRotation(void)
147
{
148
RSDK_THIS(Orbinaut);
149
150
int32 angle = self->angle;
151
if (self->direction)
152
self->angle = (angle - 1) & 0xFF;
153
else
154
self->angle = (angle + 1) & 0xFF;
155
156
for (int32 i = 0; i < ORBINAUT_ORB_COUNT; ++i) {
157
if ((1 << i) & self->activeOrbs) {
158
self->orbPositions[i].x = (RSDK.Cos256(angle) << 12) + self->position.x;
159
self->orbPositions[i].y = (RSDK.Sin256(angle) << 12) + self->position.y;
160
}
161
angle += (0x100 / ORBINAUT_ORB_COUNT);
162
}
163
}
164
165
void Orbinaut_CheckOffScreen(void)
166
{
167
RSDK_THIS(Orbinaut);
168
169
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
170
self->position = self->startPos;
171
self->direction = self->startDir;
172
Orbinaut_Create(NULL);
173
}
174
}
175
176
void Orbinaut_State_Init(void)
177
{
178
RSDK_THIS(Orbinaut);
179
180
self->active = ACTIVE_NORMAL;
181
self->state = Orbinaut_State_Moving;
182
Orbinaut_State_Moving();
183
}
184
185
void Orbinaut_State_Moving(void)
186
{
187
RSDK_THIS(Orbinaut);
188
189
self->position.x += self->velocity.x;
190
191
Orbinaut_HandleRotation();
192
Orbinaut_HandlePlayerInteractions();
193
194
if (self->fireOrbs) {
195
EntityPlayer *playerPtr = NULL;
196
int32 distanceX = 0x7FFFFFFF;
197
int32 distanceY = 0x7FFFFFFF;
198
foreach_active(Player, player)
199
{
200
if (abs(player->position.y - self->position.y) < distanceY)
201
distanceY = abs(player->position.y - self->position.y);
202
203
if (abs(player->position.y - self->position.y) < 0x400000) {
204
if (!playerPtr) {
205
if (abs(player->position.x - self->position.x) < distanceX) {
206
distanceX = abs(player->position.x - self->position.x);
207
playerPtr = player;
208
}
209
}
210
else {
211
if (abs(player->position.x - self->position.x) < distanceX) {
212
distanceX = abs(player->position.x - self->position.x);
213
playerPtr = player;
214
}
215
}
216
}
217
}
218
219
if (!playerPtr)
220
playerPtr = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
221
222
if (distanceX <= 0x800000) {
223
self->state = Orbinaut_State_ReleasingOrbs;
224
self->animatorFace.frameID = 1;
225
}
226
227
self->direction = playerPtr->position.x >= self->position.x;
228
}
229
230
Orbinaut_CheckOffScreen();
231
}
232
233
void Orbinaut_State_ReleasingOrbs(void)
234
{
235
RSDK_THIS(Orbinaut);
236
237
uint8 angle = self->angle;
238
Orbinaut_HandleRotation();
239
240
for (int32 i = 0; i < ORBINAUT_ORB_COUNT; ++i) {
241
if (angle == 64) {
242
if ((1 << i) & self->activeOrbs) {
243
self->activeOrbs &= ~(1 << i);
244
EntityOrbinaut *orb = CREATE_ENTITY(Orbinaut, INT_TO_VOID(true), self->orbPositions[i].x, self->orbPositions[i].y);
245
if (self->direction == FLIP_NONE)
246
orb->velocity.x = -0x20000;
247
else
248
orb->velocity.x = 0x20000;
249
}
250
}
251
angle += (0x100 / ORBINAUT_ORB_COUNT);
252
}
253
Orbinaut_HandlePlayerInteractions();
254
255
if (!self->activeOrbs) {
256
self->state = Orbinaut_State_Orbless;
257
if (self->direction == FLIP_NONE)
258
self->velocity.x = -0x4000;
259
else
260
self->velocity.x = 0x4000;
261
}
262
263
if (self->animatorFace.timer >= 0x10)
264
self->animatorFace.frameID = 2;
265
else
266
self->animatorFace.timer++;
267
268
Orbinaut_CheckOffScreen();
269
}
270
271
void Orbinaut_State_Orbless(void)
272
{
273
RSDK_THIS(Orbinaut);
274
275
self->position.x += self->velocity.x;
276
277
Orbinaut_HandlePlayerInteractions();
278
Orbinaut_CheckOffScreen();
279
}
280
281
void Orbinaut_State_Orb(void)
282
{
283
RSDK_THIS(Orbinaut);
284
285
if (RSDK.CheckOnScreen(self, &self->updateRange)) {
286
self->position.x += self->velocity.x;
287
288
foreach_active(Player, player)
289
{
290
if (self->planeFilter <= 0 || player->collisionPlane == (uint8)((self->planeFilter - 1) & 1)) {
291
if (Player_CheckCollisionTouch(player, self, &Orbinaut->hitboxOrb)) {
292
Player_Hurt(player, self);
293
}
294
}
295
}
296
}
297
else {
298
destroyEntity(self);
299
}
300
}
301
302
void Orbinaut_State_OrbDebris(void)
303
{
304
RSDK_THIS(Orbinaut);
305
306
if (RSDK.CheckOnScreen(self, &self->updateRange)) {
307
self->position.x += self->velocity.x;
308
self->position.y += self->velocity.y;
309
self->velocity.y += 0x3800;
310
}
311
else {
312
destroyEntity(self);
313
}
314
}
315
316
#if GAME_INCLUDE_EDITOR
317
void Orbinaut_EditorDraw(void)
318
{
319
RSDK_THIS(Orbinaut);
320
321
int32 angle = self->angle;
322
Orbinaut_HandleRotation();
323
self->angle = angle;
324
325
Orbinaut_Draw();
326
}
327
328
void Orbinaut_EditorLoad(void)
329
{
330
Orbinaut->aniFrames = RSDK.LoadSpriteAnimation("MMZ/Orbinaut.bin", SCOPE_STAGE);
331
332
RSDK_ACTIVE_VAR(Orbinaut, planeFilter);
333
RSDK_ENUM_VAR("None", PLANEFILTER_NONE);
334
RSDK_ENUM_VAR("AL", PLANEFILTER_AL);
335
RSDK_ENUM_VAR("BL", PLANEFILTER_BL);
336
RSDK_ENUM_VAR("AH", PLANEFILTER_AH);
337
RSDK_ENUM_VAR("BH", PLANEFILTER_BH);
338
339
RSDK_ACTIVE_VAR(Orbinaut, direction);
340
RSDK_ENUM_VAR("Left", FLIP_NONE);
341
RSDK_ENUM_VAR("Right", FLIP_X);
342
}
343
#endif
344
345
void Orbinaut_Serialize(void)
346
{
347
RSDK_EDITABLE_VAR(Orbinaut, VAR_UINT8, direction);
348
RSDK_EDITABLE_VAR(Orbinaut, VAR_ENUM, planeFilter);
349
RSDK_EDITABLE_VAR(Orbinaut, VAR_BOOL, fireOrbs);
350
}
351
352