Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/CPZ/Spiny.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Spiny Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectSpiny *Spiny;
11
12
void Spiny_Update(void)
13
{
14
RSDK_THIS(Spiny);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Spiny_LateUpdate(void) {}
20
21
void Spiny_StaticUpdate(void) {}
22
23
void Spiny_Draw(void)
24
{
25
RSDK_THIS(Spiny);
26
27
RSDK.DrawSprite(&self->animator, NULL, false);
28
}
29
30
void Spiny_Create(void *data)
31
{
32
RSDK_THIS(Spiny);
33
34
self->visible = true;
35
self->drawGroup = Zone->objectDrawGroup[0];
36
self->active = ACTIVE_BOUNDS;
37
self->updateRange.x = 0x800000;
38
self->updateRange.y = 0x800000;
39
40
if (data) {
41
self->drawGroup = Zone->objectDrawGroup[0] - 1;
42
RSDK.SetSpriteAnimation(Spiny->aniFrames, 4, &self->animator, true, 0);
43
self->state = Spiny_State_Shot;
44
}
45
else {
46
self->startPos = self->position;
47
self->startDir = self->direction;
48
self->drawFX = FX_FLIP;
49
50
if (self->type == SPINY_FLOOR) {
51
RSDK.SetSpriteAnimation(Spiny->aniFrames, 0, &self->animator, true, 0);
52
self->state = Spiny_State_Init;
53
54
if (!(self->direction & FLIP_X))
55
self->velocity.x = -0x4000;
56
else
57
self->velocity.x = 0x4000;
58
}
59
else {
60
RSDK.SetSpriteAnimation(Spiny->aniFrames, 2, &self->animator, true, 0);
61
self->state = Spiny_State_Init;
62
63
if (!(self->direction & FLIP_Y))
64
self->velocity.y = -0x4000;
65
else
66
self->velocity.y = 0x4000;
67
}
68
}
69
}
70
71
void Spiny_StageLoad(void)
72
{
73
Spiny->aniFrames = RSDK.LoadSpriteAnimation("CPZ/Spiny.bin", SCOPE_STAGE);
74
75
Spiny->hitboxSpiny.left = -12;
76
Spiny->hitboxSpiny.top = -15;
77
Spiny->hitboxSpiny.right = 12;
78
Spiny->hitboxSpiny.bottom = 15;
79
80
Spiny->hitboxRange.left = -96;
81
Spiny->hitboxRange.top = -256;
82
Spiny->hitboxRange.right = 96;
83
Spiny->hitboxRange.bottom = 256;
84
85
Spiny->hitboxShot.left = -4;
86
Spiny->hitboxShot.top = -4;
87
Spiny->hitboxShot.right = 4;
88
Spiny->hitboxShot.bottom = 4;
89
90
DEBUGMODE_ADD_OBJ(Spiny);
91
92
Spiny->sfxShot = RSDK.GetSfx("Stage/Shot.wav");
93
}
94
95
void Spiny_DebugSpawn(void)
96
{
97
RSDK_THIS(Spiny);
98
99
EntitySpiny *spiny = CREATE_ENTITY(Spiny, NULL, self->position.x, self->position.y);
100
spiny->direction = self->direction;
101
}
102
103
void Spiny_DebugDraw(void)
104
{
105
RSDK.SetSpriteAnimation(Spiny->aniFrames, 0, &DebugMode->animator, true, 0);
106
RSDK.DrawSprite(&DebugMode->animator, NULL, false);
107
}
108
109
void Spiny_CheckPlayerCollisions(void)
110
{
111
RSDK_THIS(Spiny);
112
113
foreach_active(Player, player)
114
{
115
if (Player_CheckBadnikTouch(player, self, &Spiny->hitboxSpiny))
116
Player_CheckBadnikBreak(player, self, true);
117
}
118
}
119
120
void Spiny_CheckOffScreen(void)
121
{
122
RSDK_THIS(Spiny);
123
124
if (!RSDK.CheckOnScreen(self, NULL) && !RSDK.CheckPosOnScreen(&self->startPos, &self->updateRange)) {
125
self->position = self->startPos;
126
self->dirChangeTimer = 0;
127
self->moveTimer = 128;
128
self->direction = self->startDir;
129
Spiny_Create(NULL);
130
}
131
}
132
133
void Spiny_State_Init(void)
134
{
135
RSDK_THIS(Spiny);
136
137
self->active = ACTIVE_NORMAL;
138
if (self->type == SPINY_FLOOR) {
139
self->state = Spiny_State_Floor;
140
Spiny_State_Floor();
141
}
142
else {
143
self->state = Spiny_State_Wall;
144
Spiny_State_Wall();
145
}
146
}
147
148
void Spiny_State_Floor(void)
149
{
150
RSDK_THIS(Spiny);
151
152
RSDK.ProcessAnimation(&self->animator);
153
154
if (++self->dirChangeTimer >= 256) {
155
self->dirChangeTimer = 0;
156
self->direction ^= FLIP_X;
157
self->moveTimer = 128;
158
self->velocity.x = -self->velocity.x;
159
}
160
161
int32 distance = 0x7FFFFFFF;
162
self->position.x += self->velocity.x;
163
164
if (!self->moveTimer) {
165
foreach_active(Player, player)
166
{
167
if (Player_CheckCollisionTouch(player, self, &Spiny->hitboxRange)) {
168
self->moveTimer = 40;
169
self->state = Spiny_State_Shoot_Floor;
170
RSDK.SetSpriteAnimation(Spiny->aniFrames, 1, &self->animator, true, 0);
171
172
if (abs(player->position.x - self->position.x) < distance) {
173
distance = abs(player->position.x - self->position.x);
174
if (player->position.x > self->position.x)
175
self->shotVelocity = 0x10000;
176
else
177
self->shotVelocity = -0x10000;
178
}
179
}
180
}
181
}
182
else {
183
self->moveTimer--;
184
}
185
186
Spiny_CheckPlayerCollisions();
187
Spiny_CheckOffScreen();
188
}
189
190
void Spiny_State_Shoot_Floor(void)
191
{
192
RSDK_THIS(Spiny);
193
194
RSDK.ProcessAnimation(&self->animator);
195
196
if (--self->moveTimer == 20) {
197
RSDK.PlaySfx(Spiny->sfxShot, false, 0xFF);
198
199
EntitySpiny *shot = CREATE_ENTITY(Spiny, INT_TO_VOID(true), self->position.x, self->position.y);
200
shot->velocity.x = self->shotVelocity;
201
if (!(self->direction & 2))
202
shot->velocity.y = -0x30000;
203
else
204
shot->velocity.y = 0x20000;
205
}
206
else {
207
if (self->moveTimer < 0) {
208
RSDK.SetSpriteAnimation(Spiny->aniFrames, 0, &self->animator, true, 0);
209
self->moveTimer = 64;
210
self->state = Spiny_State_Floor;
211
}
212
}
213
214
Spiny_CheckPlayerCollisions();
215
Spiny_CheckOffScreen();
216
}
217
218
void Spiny_State_Wall(void)
219
{
220
RSDK_THIS(Spiny);
221
222
RSDK.ProcessAnimation(&self->animator);
223
224
if (++self->dirChangeTimer >= 256) {
225
self->dirChangeTimer = 0;
226
self->direction ^= FLIP_Y;
227
self->moveTimer = 128;
228
self->velocity.y = -self->velocity.y;
229
}
230
231
self->position.y += self->velocity.y;
232
233
if (!self->moveTimer) {
234
foreach_active(Player, player)
235
{
236
if (Player_CheckCollisionTouch(player, self, &Spiny->hitboxRange)) {
237
self->moveTimer = 40;
238
self->state = Spiny_State_Shoot_Wall;
239
RSDK.SetSpriteAnimation(Spiny->aniFrames, 3, &self->animator, true, 0);
240
241
if (!(self->direction & 1))
242
self->shotVelocity = -0x30000;
243
else
244
self->shotVelocity = 0x30000;
245
}
246
}
247
}
248
else {
249
self->moveTimer--;
250
}
251
252
Spiny_CheckPlayerCollisions();
253
Spiny_CheckOffScreen();
254
}
255
256
void Spiny_State_Shoot_Wall(void)
257
{
258
RSDK_THIS(Spiny);
259
260
RSDK.ProcessAnimation(&self->animator);
261
262
if (--self->moveTimer == 20) {
263
RSDK.PlaySfx(Spiny->sfxShot, false, 0xFF);
264
CREATE_ENTITY(Spiny, INT_TO_VOID(true), self->position.x, self->position.y)->velocity.x = self->shotVelocity;
265
}
266
else {
267
if (self->moveTimer < 0) {
268
RSDK.SetSpriteAnimation(Spiny->aniFrames, 2, &self->animator, true, 0);
269
self->moveTimer = 64;
270
self->state = Spiny_State_Wall;
271
}
272
}
273
274
Spiny_CheckPlayerCollisions();
275
Spiny_CheckOffScreen();
276
}
277
278
void Spiny_State_Shot(void)
279
{
280
RSDK_THIS(Spiny);
281
282
self->position.x += self->velocity.x;
283
self->position.y += self->velocity.y;
284
self->velocity.y += 0x2000;
285
286
if (RSDK.CheckOnScreen(self, &self->updateRange)) {
287
RSDK.ProcessAnimation(&self->animator);
288
289
if (RSDK.ObjectTileCollision(self, Zone->collisionLayers, CMODE_FLOOR, 0, 0, 0, true)) {
290
self->inkEffect |= INK_ADD;
291
self->alpha = 0x100;
292
self->state = Spiny_State_ShotDisappear;
293
}
294
295
foreach_active(Player, player)
296
{
297
if (Player_CheckCollisionTouch(player, self, &Spiny->hitboxShot))
298
Player_ProjectileHurt(player, self);
299
}
300
}
301
else {
302
destroyEntity(self);
303
}
304
}
305
306
void Spiny_State_ShotDisappear(void)
307
{
308
RSDK_THIS(Spiny);
309
310
RSDK.ProcessAnimation(&self->animator);
311
312
self->position.x += self->velocity.x;
313
self->position.y += self->velocity.y;
314
315
self->alpha -= 0x20;
316
if (self->alpha <= 0)
317
destroyEntity(self);
318
}
319
320
#if GAME_INCLUDE_EDITOR
321
void Spiny_EditorDraw(void)
322
{
323
RSDK_THIS(Spiny);
324
self->drawFX = FX_FLIP;
325
326
if (self->type == SPINY_FLOOR)
327
RSDK.SetSpriteAnimation(Spiny->aniFrames, 0, &self->animator, false, 0);
328
else
329
RSDK.SetSpriteAnimation(Spiny->aniFrames, 2, &self->animator, false, 0);
330
331
Spiny_Draw();
332
}
333
334
void Spiny_EditorLoad(void)
335
{
336
Spiny->aniFrames = RSDK.LoadSpriteAnimation("CPZ/Spiny.bin", SCOPE_STAGE);
337
338
RSDK_ACTIVE_VAR(Spiny, type);
339
RSDK_ENUM_VAR("Floor", SPINY_FLOOR);
340
RSDK_ENUM_VAR("Wall", SPINY_WALL);
341
342
RSDK_ACTIVE_VAR(Spiny, direction);
343
RSDK_ENUM_VAR("No Flip", FLIP_NONE);
344
RSDK_ENUM_VAR("Flip X", FLIP_X);
345
RSDK_ENUM_VAR("Flip Y", FLIP_Y);
346
RSDK_ENUM_VAR("Flip XY", FLIP_XY);
347
}
348
#endif
349
350
void Spiny_Serialize(void)
351
{
352
RSDK_EDITABLE_VAR(Spiny, VAR_UINT8, type);
353
RSDK_EDITABLE_VAR(Spiny, VAR_UINT8, direction);
354
}
355
356