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