Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/Global/Animals.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Animals Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectAnimals *Animals;
11
12
void Animals_Update(void)
13
{
14
RSDK_THIS(Animals);
15
16
StateMachine_Run(self->state);
17
18
if (!self->behaviour && !RSDK.CheckOnScreen(self, NULL))
19
destroyEntity(self);
20
}
21
22
void Animals_LateUpdate(void) {}
23
24
void Animals_StaticUpdate(void) {}
25
26
void Animals_Draw(void)
27
{
28
RSDK_THIS(Animals);
29
30
RSDK.DrawSprite(&self->animator, NULL, false);
31
}
32
33
void Animals_Create(void *data)
34
{
35
RSDK_THIS(Animals);
36
37
if (self->behaviour == ANIMAL_BEHAVE_FIXED)
38
self->active = ACTIVE_BOUNDS;
39
else
40
self->active = ACTIVE_NORMAL;
41
42
self->drawFX |= FX_FLIP;
43
self->visible = true;
44
self->updateRange.x = TO_FIXED(64);
45
self->updateRange.y = TO_FIXED(64);
46
self->drawGroup = Zone->objectDrawGroup[0];
47
48
int32 type = ANIMAL_POCKY;
49
#if MANIA_USE_PLUS
50
if (!(globals->secrets & SECRET_RICKYMODE))
51
#endif
52
type = VOID_TO_INT(data);
53
54
if (!self->type && ZONE_RAND(0, 256) == 21) {
55
type = ANIMAL_POCKY;
56
self->velocity.y = -TO_FIXED(4);
57
self->type = type - 1;
58
self->state = Animals_State_Fall;
59
self->hitboxAnimal.top = -Animals->hitboxes[self->type] >> 16;
60
self->hitboxAnimal.left = -4;
61
self->hitboxAnimal.right = 4;
62
self->hitboxAnimal.bottom = Animals->hitboxes[self->type] >> 16;
63
RSDK.SetSpriteAnimation(Animals->aniFrames, 2 * self->type, &self->animator, true, 0);
64
}
65
else if (type) {
66
self->velocity.y = -TO_FIXED(4);
67
self->type = type - 1;
68
self->state = Animals_State_Fall;
69
70
self->hitboxAnimal.top = -FROM_FIXED(Animals->hitboxes[self->type]);
71
self->hitboxAnimal.left = -4;
72
self->hitboxAnimal.right = 4;
73
self->hitboxAnimal.bottom = FROM_FIXED(Animals->hitboxes[self->type]);
74
75
RSDK.SetSpriteAnimation(Animals->aniFrames, 2 * self->type, &self->animator, true, 0);
76
}
77
else if (self->behaviour == ANIMAL_BEHAVE_FOLLOW) {
78
self->active = ACTIVE_BOUNDS;
79
switch (self->type) {
80
case ANIMAL_FLICKY:
81
case ANIMAL_CUCKY:
82
case ANIMAL_LOCKY: self->state = Animals_State_Fly; break;
83
84
case ANIMAL_RICKY:
85
case ANIMAL_POCKY:
86
case ANIMAL_PECKY:
87
case ANIMAL_PICKY:
88
case ANIMAL_ROCKY:
89
case ANIMAL_BECKY:
90
case ANIMAL_TOCKY:
91
case ANIMAL_WOCKY:
92
case ANIMAL_MICKY: self->state = Animals_State_Bounce; break;
93
94
default: break;
95
}
96
97
Animals_CheckDirection();
98
self->velocity.y = Animals->yVelocity[self->type];
99
if (self->direction == FLIP_NONE)
100
self->velocity.x = -Animals->xVelocity[self->type];
101
else
102
self->velocity.x = Animals->xVelocity[self->type];
103
RSDK.SetSpriteAnimation(Animals->aniFrames, 2 * self->type + 1, &self->animator, true, 0);
104
}
105
else {
106
self->state = Animals_State_Placed;
107
}
108
}
109
110
void Animals_StageLoad(void)
111
{
112
Animals->aniFrames = RSDK.LoadSpriteAnimation("Global/Animals.bin", SCOPE_STAGE);
113
114
if (RSDK.FindObject("Platform"))
115
Animals->hasPlatform = true;
116
117
if (RSDK.FindObject("Bridge"))
118
Animals->hasBridge = true;
119
}
120
121
void Animals_CheckDirection(void)
122
{
123
RSDK_THIS(Animals);
124
125
switch (self->behaviour) {
126
default:
127
case ANIMAL_BEHAVE_FREE: self->direction = FLIP_X; break;
128
129
case ANIMAL_BEHAVE_FOLLOW: {
130
EntityPlayer *player = RSDK_GET_ENTITY(SLOT_PLAYER1, Player);
131
if (!player) {
132
self->direction = FLIP_NONE;
133
}
134
else if (self->position.x < player->position.x) {
135
self->direction = FLIP_NONE;
136
}
137
else {
138
self->direction = FLIP_X;
139
}
140
break;
141
}
142
143
case ANIMAL_BEHAVE_FIXED: self->direction = ZONE_RAND(0, 2); break;
144
}
145
146
if (!self->direction)
147
self->velocity.x = -Animals->xVelocity[self->type];
148
else
149
self->velocity.x = Animals->xVelocity[self->type];
150
}
151
152
bool32 Animals_CheckPlatformCollision(void *p)
153
{
154
RSDK_THIS(Animals);
155
EntityPlatform *platform = (EntityPlatform *)p;
156
157
bool32 collided = false;
158
if (platform->state != Platform_State_Falling2 && platform->state != Platform_State_Hold) {
159
platform->position.x = platform->drawPos.x - platform->collisionOffset.x;
160
platform->position.y = platform->drawPos.y - platform->collisionOffset.y;
161
162
if (platform->collision <= PLATFORM_C_SOLID) {
163
collided = RSDK.CheckObjectCollisionPlatform(platform, RSDK.GetHitbox(&platform->animator, 0), self, &self->hitboxAnimal, true);
164
}
165
else if (platform->collision == PLATFORM_C_TILED
166
&& RSDK.CheckObjectCollisionTouchBox(platform, &platform->hitbox, self, &self->hitboxAnimal)) {
167
if (self->collisionLayers & Zone->moveLayerMask) {
168
TileLayer *move = RSDK.GetTileLayer(Zone->moveLayer);
169
move->position.x = -(platform->drawPos.x + platform->tileOrigin.x) >> 16;
170
move->position.y = -(platform->drawPos.y + platform->tileOrigin.y) >> 16;
171
}
172
173
if (self->velocity.y >= 0x3800)
174
collided = true;
175
}
176
platform->position.x = platform->centerPos.x;
177
platform->position.y = platform->centerPos.y;
178
}
179
180
return collided;
181
}
182
183
bool32 Animals_CheckGroundCollision(void)
184
{
185
RSDK_THIS(Animals);
186
187
if (self->velocity.y <= 0)
188
return false;
189
190
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, Animals->hitboxes[self->type], false))
191
return true;
192
193
if (Animals->hasPlatform) {
194
foreach_active(Platform, platform)
195
{
196
if (Animals_CheckPlatformCollision(platform))
197
return true;
198
}
199
}
200
201
if (Animals->hasBridge) {
202
foreach_active(Bridge, bridge)
203
{
204
bool32 collided = Bridge_HandleCollisions(self, bridge, &self->hitboxAnimal, false, false);
205
if (collided) {
206
foreach_return true;
207
}
208
}
209
}
210
return false;
211
}
212
213
void Animals_State_Fall(void)
214
{
215
RSDK_THIS(Animals);
216
217
self->position.y += self->velocity.y;
218
self->velocity.y += 0x3800;
219
220
RSDK.ProcessAnimation(&self->animator);
221
222
if (Animals_CheckGroundCollision()) {
223
RSDK.SetSpriteAnimation(Animals->aniFrames, 2 * self->type + 1, &self->animator, true, 0);
224
switch (self->type) {
225
case ANIMAL_FLICKY:
226
case ANIMAL_CUCKY:
227
case ANIMAL_LOCKY: self->state = Animals_State_Fly; break;
228
229
case ANIMAL_RICKY:
230
case ANIMAL_POCKY:
231
case ANIMAL_PECKY:
232
case ANIMAL_PICKY:
233
case ANIMAL_ROCKY:
234
case ANIMAL_BECKY:
235
case ANIMAL_TOCKY:
236
case ANIMAL_WOCKY:
237
case ANIMAL_MICKY: self->state = Animals_State_Bounce; break;
238
239
default: break;
240
}
241
242
Animals_CheckDirection();
243
self->velocity.y = Animals->yVelocity[self->type];
244
}
245
}
246
247
void Animals_State_Bounce(void)
248
{
249
RSDK_THIS(Animals);
250
251
self->position.x += self->velocity.x;
252
self->position.y += self->velocity.y;
253
self->velocity.y += Animals->gravityStrength[self->type];
254
255
if (Animals_CheckGroundCollision()) {
256
Animals_CheckDirection();
257
self->velocity.y = Animals->yVelocity[self->type];
258
}
259
260
self->animator.frameID = self->velocity.y < 0;
261
}
262
263
void Animals_State_Fly(void)
264
{
265
RSDK_THIS(Animals);
266
267
self->position.x += self->velocity.x;
268
self->position.y += self->velocity.y;
269
self->velocity.y += Animals->gravityStrength[self->type];
270
271
if (Animals_CheckGroundCollision()) {
272
Animals_CheckDirection();
273
self->velocity.y = Animals->yVelocity[self->type];
274
}
275
276
RSDK.ProcessAnimation(&self->animator);
277
}
278
279
void Animals_State_Placed(void)
280
{
281
RSDK_THIS(Animals);
282
283
if (self->timer <= 0)
284
self->state = Animals_State_Fall;
285
else
286
self->timer--;
287
}
288
289
#if GAME_INCLUDE_EDITOR
290
void Animals_EditorDraw(void)
291
{
292
RSDK_THIS(Animals);
293
294
switch (self->behaviour) {
295
default: break;
296
case ANIMAL_BEHAVE_FREE: RSDK.SetSpriteAnimation(Animals->aniFrames, 2 * self->type, &self->animator, true, 0); break;
297
case ANIMAL_BEHAVE_FOLLOW:
298
case ANIMAL_BEHAVE_FIXED: RSDK.SetSpriteAnimation(Animals->aniFrames, 2 * self->type + 1, &self->animator, true, 0); break;
299
}
300
301
RSDK.DrawSprite(&self->animator, NULL, false);
302
}
303
304
void Animals_EditorLoad(void)
305
{
306
Animals->aniFrames = RSDK.LoadSpriteAnimation("Global/Animals.bin", SCOPE_STAGE);
307
308
RSDK_ACTIVE_VAR(Animals, type);
309
RSDK_ENUM_VAR("Flicky", ANIMAL_FLICKY);
310
RSDK_ENUM_VAR("Ricky", ANIMAL_RICKY);
311
RSDK_ENUM_VAR("Pocky", ANIMAL_POCKY);
312
RSDK_ENUM_VAR("Pecky", ANIMAL_PECKY);
313
RSDK_ENUM_VAR("Picky", ANIMAL_PICKY);
314
RSDK_ENUM_VAR("Cucky", ANIMAL_CUCKY);
315
RSDK_ENUM_VAR("Rocky", ANIMAL_ROCKY);
316
RSDK_ENUM_VAR("Becky", ANIMAL_BECKY);
317
RSDK_ENUM_VAR("Locky", ANIMAL_LOCKY);
318
RSDK_ENUM_VAR("Tocky", ANIMAL_TOCKY);
319
RSDK_ENUM_VAR("Wocky", ANIMAL_WOCKY);
320
RSDK_ENUM_VAR("Mickey", ANIMAL_MICKY);
321
322
RSDK_ACTIVE_VAR(Animals, behaviour);
323
RSDK_ENUM_VAR("Free", ANIMAL_BEHAVE_FREE);
324
RSDK_ENUM_VAR("Follow", ANIMAL_BEHAVE_FOLLOW);
325
RSDK_ENUM_VAR("Fixed", ANIMAL_BEHAVE_FIXED);
326
}
327
#endif
328
329
void Animals_Serialize(void)
330
{
331
RSDK_EDITABLE_VAR(Animals, VAR_ENUM, type);
332
RSDK_EDITABLE_VAR(Animals, VAR_ENUM, behaviour);
333
}
334
335