Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/AIZ/Sweep.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Sweep Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectSweep *Sweep;
11
12
void Sweep_Update(void)
13
{
14
RSDK_THIS(Sweep);
15
StateMachine_Run(self->state);
16
if (self->state != Sweep_State_Projectile) {
17
EntityWater *water = self->water;
18
if (water)
19
self->position.y = water->position.y - (water->size.y >> 1) - 0x90000;
20
else
21
self->position.y = Water->waterLevel - 0x90000;
22
}
23
}
24
25
void Sweep_LateUpdate(void) {}
26
27
void Sweep_StaticUpdate(void) {}
28
29
void Sweep_Draw(void)
30
{
31
RSDK_THIS(Sweep);
32
RSDK.DrawSprite(&self->animator, NULL, false);
33
}
34
35
void Sweep_Create(void *data)
36
{
37
RSDK_THIS(Sweep);
38
39
if (!SceneInfo->inEditor) {
40
self->visible = true;
41
self->drawFX |= FX_FLIP;
42
self->drawGroup = Zone->objectDrawGroup[0];
43
self->startPos = self->position;
44
self->startDir = self->direction;
45
self->timer = 128;
46
self->hasShot = false;
47
48
if (data) {
49
self->active = ACTIVE_NORMAL;
50
self->updateRange.x = 0x200000;
51
self->updateRange.y = 0x200000;
52
RSDK.SetSpriteAnimation(Sweep->aniFrames, 4, &self->animator, true, 0);
53
self->state = Sweep_State_Projectile;
54
}
55
else {
56
self->active = ACTIVE_BOUNDS;
57
self->updateRange.x = 0x800000;
58
self->updateRange.y = 0x800000;
59
RSDK.SetSpriteAnimation(Sweep->aniFrames, 0, &self->animator, true, 0);
60
61
foreach_all(Water, water)
62
{
63
Hitbox hitboxWater;
64
Hitbox hitbox;
65
66
hitboxWater.right = water->size.x >> 17;
67
hitboxWater.left = -(water->size.x >> 17);
68
hitboxWater.bottom = water->size.y >> 17;
69
hitboxWater.top = -(water->size.y >> 17);
70
71
hitbox.left = 1;
72
hitbox.top = 64;
73
hitbox.right = 1;
74
hitbox.bottom = 64;
75
if (water->type == WATER_POOL && RSDK.CheckObjectCollisionTouchBox(water, &hitboxWater, self, &hitbox)) {
76
self->water = water;
77
}
78
}
79
self->state = Sweep_State_Init;
80
}
81
}
82
}
83
84
void Sweep_StageLoad(void)
85
{
86
if (RSDK.CheckSceneFolder("CPZ"))
87
Sweep->aniFrames = RSDK.LoadSpriteAnimation("CPZ/Sweep.bin", SCOPE_STAGE);
88
#if MANIA_USE_PLUS
89
else if (RSDK.CheckSceneFolder("AIZ"))
90
Sweep->aniFrames = RSDK.LoadSpriteAnimation("AIZ/Sweep.bin", SCOPE_STAGE);
91
#endif
92
93
Sweep->hitboxBadnik.left = -10;
94
Sweep->hitboxBadnik.top = -7;
95
Sweep->hitboxBadnik.right = 10;
96
Sweep->hitboxBadnik.bottom = 4;
97
98
Sweep->hitboxRange.left = -256;
99
Sweep->hitboxRange.top = -16;
100
Sweep->hitboxRange.right = 0;
101
Sweep->hitboxRange.bottom = 16;
102
103
Sweep->hitboxProjectile.left = -13;
104
Sweep->hitboxProjectile.top = -3;
105
Sweep->hitboxProjectile.right = -8;
106
Sweep->hitboxProjectile.bottom = 3;
107
108
Sweep->sfxPon = RSDK.GetSfx("Stage/Pon.wav");
109
110
DEBUGMODE_ADD_OBJ(Sweep);
111
}
112
113
void Sweep_DebugSpawn(void)
114
{
115
RSDK_THIS(DebugMode);
116
117
EntitySweep *sweep = CREATE_ENTITY(Sweep, NULL, self->position.x, self->position.y);
118
sweep->direction = self->direction;
119
sweep->startDir = self->direction;
120
}
121
122
void Sweep_DebugDraw(void)
123
{
124
RSDK.SetSpriteAnimation(Sweep->aniFrames, 0, &DebugMode->animator, true, 0);
125
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
126
}
127
128
void Sweep_CheckOffScreen(void)
129
{
130
RSDK_THIS(Sweep);
131
132
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
133
self->position = self->startPos;
134
self->direction = self->startDir;
135
Sweep_Create(NULL);
136
}
137
}
138
139
void Sweep_CheckPlayerCollisions(void)
140
{
141
RSDK_THIS(Sweep);
142
143
foreach_active(Player, player)
144
{
145
Hitbox hitbox;
146
Hitbox *playerHitbox = Player_GetHitbox(player);
147
RSDK.GetHitbox(&player->animator, 0);
148
149
EntityShield *shield = RSDK_GET_ENTITY(Player->playerCount + RSDK.GetEntitySlot(player), Shield);
150
if (shield->classID == Shield->classID && shield->state == Shield_State_Insta) {
151
hitbox.left = 2 * playerHitbox->left - (playerHitbox->left >> 1);
152
hitbox.top = 2 * playerHitbox->top - (playerHitbox->top >> 1);
153
hitbox.right = 2 * playerHitbox->right - (playerHitbox->right >> 1);
154
hitbox.bottom = 2 * playerHitbox->bottom - (playerHitbox->bottom >> 1);
155
playerHitbox = &hitbox;
156
}
157
158
int32 side = MathHelpers_CheckBoxCollision(self, &Sweep->hitboxBadnik, player, playerHitbox);
159
if (side) {
160
if (self->state != Sweep_State_Turn
161
&& ((self->direction == FLIP_NONE && side == C_LEFT) || (self->direction == FLIP_X && side == C_RIGHT)))
162
Player_Hurt(player, self);
163
else
164
Player_CheckBadnikBreak(player, self, true);
165
}
166
}
167
}
168
169
void Sweep_CheckShoot(void)
170
{
171
RSDK_THIS(Sweep);
172
173
if (!self->hasShot && self->timer <= 16) {
174
foreach_active(Player, player)
175
{
176
if (Player_CheckCollisionTouch(player, self, &Sweep->hitboxRange)) {
177
RSDK.SetSpriteAnimation(Sweep->aniFrames, 3, &self->animator, true, 0);
178
EntitySweep *projectile = CREATE_ENTITY(Sweep, INT_TO_VOID(true), self->position.x, self->position.y);
179
if (!self->direction)
180
projectile->velocity.x = -0x30000;
181
else
182
projectile->velocity.x = 0x30000;
183
projectile->direction = self->direction;
184
projectile->active = ACTIVE_NORMAL;
185
RSDK.PlaySfx(Sweep->sfxPon, false, 255);
186
self->hasShot = true;
187
self->stateStore = self->state;
188
self->state = Sweep_State_FiredShot;
189
foreach_break;
190
}
191
}
192
}
193
}
194
195
void Sweep_State_Init(void)
196
{
197
RSDK_THIS(Sweep);
198
199
self->active = ACTIVE_NORMAL;
200
self->timer = 32;
201
self->hasShot = false;
202
self->state = Sweep_State_Idle;
203
Sweep_State_Idle();
204
}
205
206
void Sweep_State_Idle(void)
207
{
208
RSDK_THIS(Sweep);
209
210
self->timer--;
211
if (self->timer) {
212
Sweep_CheckShoot();
213
}
214
else {
215
self->hasShot = false;
216
self->timer = 64;
217
RSDK.SetSpriteAnimation(Sweep->aniFrames, 0, &self->animator, true, 1);
218
self->state = Sweep_State_Dash;
219
}
220
221
Sweep_CheckPlayerCollisions();
222
Sweep_CheckOffScreen();
223
}
224
225
void Sweep_State_Dash(void)
226
{
227
RSDK_THIS(Sweep);
228
229
RSDK.ProcessAnimation(&self->animator);
230
self->timer--;
231
if (self->timer <= 0) {
232
self->timer = 32;
233
self->hasShot = false;
234
RSDK.SetSpriteAnimation(Sweep->aniFrames, 1, &self->animator, true, 0);
235
self->state = Sweep_State_Stop;
236
}
237
else {
238
if (self->direction && self->velocity.x < 0x20000) {
239
self->velocity.x += 0x3800;
240
}
241
else if (!self->direction && self->velocity.x > -0x20000) {
242
self->velocity.x -= 0x3800;
243
}
244
self->position.x += self->velocity.x;
245
}
246
247
Sweep_CheckPlayerCollisions();
248
Sweep_CheckOffScreen();
249
}
250
251
void Sweep_State_Stop(void)
252
{
253
RSDK_THIS(Sweep);
254
255
RSDK.ProcessAnimation(&self->animator);
256
self->timer--;
257
if (self->timer <= 0) {
258
RSDK.SetSpriteAnimation(Sweep->aniFrames, 2, &self->animator, true, 0);
259
self->state = Sweep_State_Turn;
260
}
261
else if (!self->velocity.x) {
262
Sweep_CheckShoot();
263
}
264
else {
265
if (self->direction) {
266
if (self->velocity.x > 0)
267
self->velocity.x -= 0x3800;
268
else
269
self->velocity.x = 0;
270
}
271
else {
272
if (self->velocity.x > 0)
273
self->velocity.x += 0x3800;
274
else
275
self->velocity.x = 0;
276
}
277
self->position.x += self->velocity.x;
278
}
279
280
Sweep_CheckPlayerCollisions();
281
Sweep_CheckOffScreen();
282
}
283
284
void Sweep_State_FiredShot(void)
285
{
286
RSDK_THIS(Sweep);
287
288
RSDK.ProcessAnimation(&self->animator);
289
290
if (self->animator.frameID == self->animator.frameCount - 1) {
291
RSDK.SetSpriteAnimation(Sweep->aniFrames, 1, &self->animator, true, 4);
292
self->state = self->stateStore;
293
StateMachine_Run(self->state);
294
}
295
else {
296
Sweep_CheckPlayerCollisions();
297
Sweep_CheckOffScreen();
298
}
299
}
300
301
void Sweep_State_Turn(void)
302
{
303
RSDK_THIS(Sweep);
304
305
self->position.x += self->velocity.x;
306
307
RSDK.ProcessAnimation(&self->animator);
308
309
if (self->animator.frameID == self->animator.frameCount - 1) {
310
RSDK.SetSpriteAnimation(Sweep->aniFrames, 0, &self->animator, true, 0);
311
self->timer = 32;
312
self->direction ^= FLIP_X;
313
self->state = Sweep_State_Idle;
314
Sweep_State_Idle();
315
}
316
else {
317
Sweep_CheckPlayerCollisions();
318
Sweep_CheckOffScreen();
319
}
320
}
321
322
void Sweep_State_Projectile(void)
323
{
324
RSDK_THIS(Sweep);
325
326
self->position.x += self->velocity.x;
327
328
if (RSDK.CheckOnScreen(self, NULL)) {
329
RSDK.ProcessAnimation(&self->animator);
330
331
foreach_active(Player, player)
332
{
333
if (Player_CheckCollisionTouch(player, self, &Sweep->hitboxProjectile)) {
334
Player_ProjectileHurt(player, self);
335
}
336
}
337
}
338
else {
339
destroyEntity(self);
340
}
341
}
342
343
#if GAME_INCLUDE_EDITOR
344
void Sweep_EditorDraw(void)
345
{
346
RSDK_THIS(Sweep);
347
RSDK.SetSpriteAnimation(Sweep->aniFrames, 0, &self->animator, true, 0);
348
Sweep_Draw();
349
}
350
351
void Sweep_EditorLoad(void)
352
{
353
if (RSDK.CheckSceneFolder("CPZ"))
354
Sweep->aniFrames = RSDK.LoadSpriteAnimation("CPZ/Sweep.bin", SCOPE_STAGE);
355
#if MANIA_USE_PLUS
356
else if (RSDK.CheckSceneFolder("AIZ"))
357
Sweep->aniFrames = RSDK.LoadSpriteAnimation("AIZ/Sweep.bin", SCOPE_STAGE);
358
#endif
359
}
360
#endif
361
362
void Sweep_Serialize(void) {}
363
364