Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/OOZ/Aquis.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Aquis Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectAquis *Aquis;
11
12
void Aquis_Update(void)
13
{
14
RSDK_THIS(Aquis);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Aquis_LateUpdate(void) {}
20
21
void Aquis_StaticUpdate(void) {}
22
23
void Aquis_Draw(void)
24
{
25
RSDK_THIS(Aquis);
26
27
if (self->mainAnimator.animationID == 4) {
28
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
29
}
30
else {
31
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
32
RSDK.DrawSprite(&self->wingAnimator, NULL, false);
33
}
34
}
35
36
void Aquis_Create(void *data)
37
{
38
RSDK_THIS(Aquis);
39
40
self->visible = true;
41
self->drawGroup = Zone->objectDrawGroup[0];
42
self->drawFX |= FX_FLIP;
43
self->startPos = self->position;
44
self->startDir = self->direction;
45
self->timer = 128;
46
self->playerInRange = 0;
47
48
if (data) {
49
self->active = ACTIVE_NORMAL;
50
self->updateRange.x = 0x200000;
51
self->updateRange.y = 0x200000;
52
RSDK.SetSpriteAnimation(Aquis->aniFrames, 2, &self->mainAnimator, true, 0);
53
self->state = Aquis_State_Shot;
54
}
55
else {
56
self->active = ACTIVE_BOUNDS;
57
self->updateRange.x = 0x800000;
58
self->updateRange.y = 0x800000;
59
self->remainingTurns = 3;
60
RSDK.SetSpriteAnimation(Aquis->aniFrames, 0, &self->mainAnimator, true, 0);
61
RSDK.SetSpriteAnimation(Aquis->aniFrames, 3, &self->wingAnimator, true, 0);
62
self->state = Aquis_State_Init;
63
}
64
}
65
66
void Aquis_StageLoad(void)
67
{
68
if (RSDK.CheckSceneFolder("OOZ1") || RSDK.CheckSceneFolder("OOZ2"))
69
Aquis->aniFrames = RSDK.LoadSpriteAnimation("OOZ/Aquis.bin", SCOPE_STAGE);
70
71
Aquis->hitboxBadnik.left = -10;
72
Aquis->hitboxBadnik.top = -16;
73
Aquis->hitboxBadnik.right = 10;
74
Aquis->hitboxBadnik.bottom = 16;
75
76
Aquis->hitboxRange.left = -96;
77
Aquis->hitboxRange.top = -64;
78
Aquis->hitboxRange.right = 64;
79
Aquis->hitboxRange.bottom = 128;
80
81
Aquis->hitboxProjectile.left = -3;
82
Aquis->hitboxProjectile.top = -3;
83
Aquis->hitboxProjectile.right = 3;
84
Aquis->hitboxProjectile.bottom = 3;
85
86
Aquis->sfxShot = RSDK.GetSfx("Stage/Shot.wav");
87
88
DEBUGMODE_ADD_OBJ(Aquis);
89
}
90
91
void Aquis_DebugSpawn(void)
92
{
93
RSDK_THIS(Aquis);
94
95
EntityAquis *aquis = CREATE_ENTITY(Aquis, NULL, self->position.x, self->position.y);
96
aquis->direction = self->direction;
97
aquis->startDir = self->direction;
98
}
99
100
void Aquis_DebugDraw(void)
101
{
102
RSDK.SetSpriteAnimation(Aquis->aniFrames, 0, &DebugMode->animator, true, 0);
103
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
104
}
105
106
void Aquis_CheckPlayerCollisions(void)
107
{
108
RSDK_THIS(Aquis);
109
110
foreach_active(Player, player)
111
{
112
if (Player_CheckBadnikTouch(player, self, &Aquis->hitboxBadnik))
113
Player_CheckBadnikBreak(player, self, true);
114
}
115
}
116
117
void Aquis_CheckOffScreen(void)
118
{
119
RSDK_THIS(Aquis);
120
121
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
122
self->position = self->startPos;
123
self->direction = self->startDir;
124
Aquis_Create(NULL);
125
}
126
}
127
128
void Aquis_State_Init(void)
129
{
130
RSDK_THIS(Aquis);
131
132
self->active = ACTIVE_NORMAL;
133
self->timer = 32;
134
135
self->state = Aquis_State_Idle;
136
Aquis_State_Idle();
137
}
138
139
void Aquis_State_Idle(void)
140
{
141
RSDK_THIS(Aquis);
142
143
if (!--self->timer) {
144
if (self->remainingTurns--) {
145
self->velocity.y = -0x10000;
146
self->timer = 128;
147
self->playerInRange = false;
148
self->state = Aquis_State_Moving;
149
}
150
else {
151
self->velocity.y = 0;
152
153
if (self->direction == FLIP_X) {
154
self->velocity.x = 0;
155
self->state = Aquis_State_Turning;
156
RSDK.SetSpriteAnimation(Aquis->aniFrames, 4, &self->mainAnimator, true, 0);
157
}
158
else {
159
self->velocity.x = -0x20000;
160
self->state = Aquis_State_Flee;
161
}
162
}
163
}
164
165
RSDK.ProcessAnimation(&self->mainAnimator);
166
RSDK.ProcessAnimation(&self->wingAnimator);
167
168
Aquis_CheckPlayerCollisions();
169
Aquis_CheckOffScreen();
170
}
171
172
void Aquis_State_Moving(void)
173
{
174
RSDK_THIS(Aquis);
175
176
self->position.x += self->velocity.x;
177
self->position.y += self->velocity.y;
178
179
EntityPlayer *playerPtr = Player_GetNearestPlayer();
180
if (playerPtr) {
181
bool32 changeDir = false;
182
if (playerPtr->position.x >= self->position.x) {
183
self->velocity.x += 0x1000;
184
185
if (self->velocity.x > 0x10000)
186
self->velocity.x = 0x10000;
187
188
changeDir = self->direction == FLIP_NONE;
189
}
190
else {
191
self->velocity.x -= 0x1000;
192
193
if (self->velocity.x < -0x10000)
194
self->velocity.x = -0x10000;
195
196
changeDir = self->direction == FLIP_X;
197
}
198
199
if (changeDir) {
200
self->state = Aquis_State_Turning;
201
RSDK.SetSpriteAnimation(Aquis->aniFrames, 4, &self->mainAnimator, true, 0);
202
}
203
204
if (playerPtr->position.y >= self->position.y) {
205
self->velocity.y += 0x1000;
206
207
if (self->velocity.y > 0x10000)
208
self->velocity.y = 0x10000;
209
}
210
else {
211
self->velocity.y -= 0x1000;
212
213
if (self->velocity.y < -0x10000)
214
self->velocity.y = -0x10000;
215
}
216
}
217
218
if (self->state != Aquis_State_Turning) {
219
if (!self->timer--) {
220
self->timer = 32;
221
self->state = Aquis_State_Idle;
222
self->velocity.x = 0;
223
self->velocity.y = 0;
224
}
225
226
if (!self->playerInRange) {
227
foreach_active(Player, player)
228
{
229
if (player->velocity.y < 0 && !player->onGround)
230
continue;
231
232
if (Player_CheckCollisionTouch(player, self, &Aquis->hitboxRange)) {
233
self->playerInRange = true;
234
self->timer = 64;
235
RSDK.SetSpriteAnimation(Aquis->aniFrames, 1, &self->mainAnimator, true, 0);
236
self->state = Aquis_State_Shoot;
237
238
if (player->position.x >= self->position.x) {
239
if (player->velocity.x <= (self->position.x - player->position.x) >> 5) {
240
RSDK.SetSpriteAnimation(Aquis->aniFrames, 4, &self->mainAnimator, true, 0);
241
self->state = Aquis_State_Turning;
242
}
243
}
244
else if (player->velocity.x >= (self->position.x - player->position.x) >> 5) {
245
RSDK.SetSpriteAnimation(Aquis->aniFrames, 4, &self->mainAnimator, true, 0);
246
self->state = Aquis_State_Turning;
247
}
248
}
249
}
250
}
251
}
252
253
RSDK.ProcessAnimation(&self->mainAnimator);
254
RSDK.ProcessAnimation(&self->wingAnimator);
255
256
Aquis_CheckPlayerCollisions();
257
Aquis_CheckOffScreen();
258
}
259
260
void Aquis_State_Shoot(void)
261
{
262
RSDK_THIS(Aquis);
263
264
if (--self->timer) {
265
if (self->timer == 33) {
266
EntityAquis *shot = CREATE_ENTITY(Aquis, INT_TO_VOID(true), self->position.x, self->position.y);
267
268
if (self->direction) {
269
shot->position.x += 0x100000;
270
shot->velocity.x = 0x30000;
271
}
272
else {
273
shot->position.x -= 0x100000;
274
shot->velocity.x = -0x30000;
275
}
276
277
shot->position.y -= 0xA0000;
278
shot->velocity.y = 0x20000;
279
shot->direction = self->direction;
280
shot->active = ACTIVE_NORMAL;
281
RSDK.PlaySfx(Aquis->sfxShot, false, 255);
282
}
283
}
284
else {
285
self->timer = 32;
286
self->remainingTurns = 0;
287
self->state = Aquis_State_Idle;
288
self->velocity.x = 0;
289
self->velocity.y = 0;
290
}
291
292
RSDK.ProcessAnimation(&self->mainAnimator);
293
RSDK.ProcessAnimation(&self->wingAnimator);
294
295
Aquis_CheckPlayerCollisions();
296
Aquis_CheckOffScreen();
297
}
298
299
void Aquis_State_Turning(void)
300
{
301
RSDK_THIS(Aquis);
302
303
self->position.x += self->velocity.x;
304
self->position.y += self->velocity.y;
305
306
RSDK.ProcessAnimation(&self->mainAnimator);
307
308
if (self->mainAnimator.frameID == self->mainAnimator.frameCount - 1) {
309
RSDK.SetSpriteAnimation(Aquis->aniFrames, 0, &self->mainAnimator, true, 0);
310
self->direction ^= FLIP_X;
311
312
if (self->remainingTurns < 0) {
313
self->velocity.x = -0x20000;
314
315
self->state = Aquis_State_Flee;
316
Aquis_State_Flee();
317
}
318
else if (self->playerInRange) {
319
self->timer = 64;
320
RSDK.SetSpriteAnimation(Aquis->aniFrames, 1, &self->mainAnimator, true, 0);
321
322
self->state = Aquis_State_Shoot;
323
Aquis_State_Shoot();
324
}
325
else {
326
self->state = Aquis_State_Moving;
327
Aquis_State_Moving();
328
}
329
}
330
else {
331
if (self->timer > 1)
332
self->timer--;
333
334
Aquis_CheckPlayerCollisions();
335
Aquis_CheckOffScreen();
336
}
337
}
338
339
void Aquis_State_Flee(void)
340
{
341
RSDK_THIS(Aquis);
342
343
self->position.x += self->velocity.x;
344
self->position.y += self->velocity.y;
345
346
RSDK.ProcessAnimation(&self->wingAnimator);
347
348
Aquis_CheckPlayerCollisions();
349
Aquis_CheckOffScreen();
350
}
351
352
void Aquis_State_Shot(void)
353
{
354
RSDK_THIS(Aquis);
355
356
self->position.x += self->velocity.x;
357
self->position.y += self->velocity.y;
358
359
if (RSDK.CheckOnScreen(self, NULL)) {
360
RSDK.ProcessAnimation(&self->mainAnimator);
361
362
foreach_active(Player, player)
363
{
364
if (Player_CheckCollisionTouch(player, self, &Aquis->hitboxProjectile))
365
Player_ProjectileHurt(player, self);
366
}
367
}
368
else {
369
destroyEntity(self);
370
}
371
}
372
373
#if GAME_INCLUDE_EDITOR
374
void Aquis_EditorDraw(void)
375
{
376
RSDK_THIS(Aquis);
377
378
RSDK.DrawSprite(&self->mainAnimator, NULL, false);
379
RSDK.DrawSprite(&self->wingAnimator, NULL, false);
380
}
381
382
void Aquis_EditorLoad(void) { Aquis->aniFrames = RSDK.LoadSpriteAnimation("OOZ/Aquis.bin", SCOPE_STAGE); }
383
#endif
384
385
void Aquis_Serialize(void) {}
386
387