Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/TMZ/PopOut.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PopOut Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPopOut *PopOut;
11
12
void PopOut_Update(void)
13
{
14
RSDK_THIS(PopOut);
15
16
int32 storeDir = self->direction;
17
int32 storeX = self->position.x;
18
int32 storeY = self->position.y;
19
20
EntitySpring *child = RSDK_GET_ENTITY(SceneInfo->entitySlot + 1, Spring);
21
if (child->classID != Spring->classID && child->classID != Spikes->classID)
22
child = NULL;
23
24
self->direction = FLIP_NONE;
25
if (!self->manualTrigger) {
26
self->shouldAppear = false;
27
foreach_active(Player, player)
28
{
29
if (Player_CheckCollisionTouch(player, self, &self->hitboxRange)) {
30
self->shouldAppear = true;
31
foreach_break;
32
}
33
}
34
}
35
else if (PopOut->hasButton) {
36
foreach_active(Button, button)
37
{
38
if (button->tag == self->tag && button->activated)
39
self->shouldAppear = true;
40
}
41
}
42
43
if (self->shouldAppear) {
44
if (self->timer < self->delay) {
45
self->timer++;
46
}
47
else {
48
if (self->appearTimer < 8) {
49
self->appearTimer++;
50
if (self->childType <= POPOUT_CHILD_SPRING_YELLOW && child && self->appearTimer == 8) {
51
child->sfxTimer = 0;
52
child->animator.speed = 0;
53
child->animator.frameID = 0;
54
}
55
}
56
}
57
}
58
else {
59
self->timer = 0;
60
if (self->appearTimer > 0) {
61
self->appearTimer--;
62
if (self->childType <= POPOUT_CHILD_SPRING_YELLOW && child && self->appearTimer == 7) {
63
child->sfxTimer = 0;
64
child->animator.speed = 0;
65
child->animator.frameID = 0;
66
}
67
}
68
}
69
70
if (child) {
71
if (self->appearTimer == 8) {
72
child->active = ACTIVE_BOUNDS;
73
child->visible = true;
74
}
75
else {
76
child->active = ACTIVE_NEVER;
77
child->visible = false;
78
}
79
}
80
81
self->active = (self->appearTimer <= 0) ? ACTIVE_BOUNDS : ACTIVE_NORMAL;
82
83
self->position.x += -32 * self->appearVelocity.x + 4 * self->appearTimer * self->appearVelocity.x;
84
self->position.y += -32 * self->appearVelocity.y + 4 * self->appearTimer * self->appearVelocity.y;
85
foreach_active(Player, playerLoop) { Player_CheckCollisionBox(playerLoop, self, &self->hitboxSolid); }
86
self->direction = storeDir;
87
self->position.x = storeX;
88
self->position.y = storeY;
89
}
90
91
void PopOut_LateUpdate(void) {}
92
93
void PopOut_StaticUpdate(void) {}
94
95
void PopOut_Draw(void)
96
{
97
RSDK_THIS(PopOut);
98
99
int32 dir = self->direction;
100
int32 storeX = self->position.x;
101
int32 storeY = self->position.y;
102
self->position.x = -16 * self->appearVelocity.x + self->position.x + 2 * self->appearTimer * self->appearVelocity.x;
103
self->position.y = -16 * self->appearVelocity.y + self->position.y + 2 * self->appearTimer * self->appearVelocity.y;
104
self->rotation = self->orientation << 7;
105
106
if (!self->appearTimer) {
107
int32 off = 128;
108
if (!dir)
109
off = -128;
110
self->rotation += off;
111
}
112
else if (self->appearTimer < 8) {
113
int32 off = 16;
114
if (!dir)
115
off = -16;
116
self->rotation += (7 - self->appearTimer) * off;
117
}
118
119
RSDK.DrawSprite(&self->mountAnimator, NULL, false);
120
121
if (self->appearTimer < 8)
122
RSDK.DrawSprite(&self->childAnimator, NULL, false);
123
124
self->position.x = storeX;
125
self->position.y = storeY;
126
self->direction = dir;
127
self->rotation = 0;
128
}
129
130
void PopOut_Create(void *data)
131
{
132
RSDK_THIS(PopOut);
133
self->drawFX = FX_ROTATE | FX_FLIP;
134
135
if (!SceneInfo->inEditor) {
136
self->active = ACTIVE_BOUNDS;
137
self->drawGroup = Zone->objectDrawGroup[0];
138
self->startPos.x = self->position.x;
139
self->startPos.y = self->position.y;
140
self->visible = true;
141
self->updateRange.x = 0x800000;
142
self->updateRange.y = 0x800000;
143
RSDK.SetSpriteAnimation(PopOut->aniFrames, 0, &self->mountAnimator, true, 0);
144
145
EntitySpring *child = RSDK_GET_ENTITY(SceneInfo->entitySlot + 1, Spring);
146
if (child->classID != Spring->classID && child->classID != Spikes->classID)
147
child = NULL;
148
149
if (child->classID == Spring->classID) {
150
self->childType = (child->type & 1) ? POPOUT_CHILD_SPRING_RED : POPOUT_CHILD_SPRING_YELLOW;
151
RSDK.SetSpriteAnimation(PopOut->aniFrames, 1, &self->childAnimator, true, self->childType);
152
}
153
else {
154
// Assume its spikes
155
self->childType = POPOUT_CHILD_SPIKES;
156
RSDK.SetSpriteAnimation(PopOut->aniFrames, 2, &self->childAnimator, true, 0);
157
}
158
PopOut_SetupHitboxes();
159
160
switch (self->orientation + 4 * self->direction) {
161
case 0:
162
case 4:
163
self->appearVelocity.x = 0;
164
self->appearVelocity.y = -0x10000;
165
break;
166
167
case 1:
168
case 5:
169
self->appearVelocity.y = 0;
170
self->appearVelocity.x = 0x10000;
171
break;
172
173
case 2:
174
case 6:
175
self->appearVelocity.x = 0;
176
self->appearVelocity.y = 0x10000;
177
break;
178
179
default:
180
case 3:
181
case 7:
182
self->appearVelocity.y = 0;
183
self->appearVelocity.x = -0x10000;
184
break;
185
}
186
}
187
}
188
189
void PopOut_StageLoad(void)
190
{
191
PopOut->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/PopOut.bin", SCOPE_STAGE);
192
193
if (RSDK.FindObject("Button"))
194
PopOut->hasButton = true;
195
}
196
197
void PopOut_SetupHitboxes(void)
198
{
199
RSDK_THIS(PopOut);
200
self->hitboxRange.left = 0;
201
self->hitboxRange.top = 0;
202
self->hitboxRange.right = 0;
203
self->hitboxRange.bottom = 0;
204
205
self->hitboxSolid.left = 0;
206
self->hitboxSolid.top = 0;
207
self->hitboxSolid.right = 0;
208
self->hitboxSolid.bottom = 0;
209
210
switch (self->orientation + 4 * self->direction) {
211
case 0:
212
self->hitboxRange.right = 80;
213
self->hitboxRange.top = -64;
214
self->hitboxRange.bottom = 32;
215
216
self->hitboxSolid.left = -32;
217
self->hitboxSolid.top = -32;
218
break;
219
220
case 1:
221
self->hitboxRange.right = 80;
222
self->hitboxRange.bottom = 64;
223
self->hitboxRange.left = -32;
224
225
self->hitboxSolid.top = -32;
226
self->hitboxSolid.right = 32;
227
break;
228
229
case 2:
230
self->hitboxRange.left = -80;
231
self->hitboxRange.top = -32;
232
self->hitboxRange.bottom = 64;
233
234
self->hitboxSolid.right = 32;
235
self->hitboxSolid.bottom = 32;
236
break;
237
238
case 3:
239
self->hitboxRange.left = -64;
240
self->hitboxRange.top = -80;
241
self->hitboxRange.right = 32;
242
243
self->hitboxSolid.left = -32;
244
self->hitboxSolid.bottom = 32;
245
break;
246
247
case 4:
248
self->hitboxRange.left = -80;
249
self->hitboxRange.top = -63;
250
self->hitboxRange.bottom = 32;
251
252
self->hitboxSolid.top = -32;
253
self->hitboxSolid.right = 32;
254
break;
255
256
case 5:
257
self->hitboxRange.top = -80;
258
self->hitboxRange.right = 64;
259
self->hitboxRange.left = -32;
260
261
self->hitboxSolid.right = 32;
262
self->hitboxSolid.bottom = 32;
263
break;
264
265
case 6:
266
self->hitboxRange.right = 80;
267
self->hitboxRange.bottom = 64;
268
self->hitboxRange.top = -32;
269
270
self->hitboxSolid.left = -32;
271
self->hitboxSolid.bottom = 32;
272
break;
273
274
default:
275
case 7:
276
self->hitboxRange.right = 80;
277
self->hitboxRange.bottom = 32;
278
self->hitboxRange.left = -64;
279
280
self->hitboxSolid.left = -32;
281
self->hitboxSolid.top = -32;
282
break;
283
}
284
}
285
286
#if GAME_INCLUDE_EDITOR
287
void PopOut_EditorDraw(void)
288
{
289
RSDK_THIS(PopOut);
290
291
PopOut->hasButton = false;
292
if (RSDK.FindObject("Button"))
293
PopOut->hasButton = true;
294
295
RSDK.SetSpriteAnimation(PopOut->aniFrames, 0, &self->mountAnimator, true, 0);
296
297
EntitySpring *child = RSDK_GET_ENTITY(SceneInfo->entitySlot + 1, Spring);
298
if (child->classID != Spring->classID && child->classID != Spikes->classID)
299
child = NULL;
300
301
if (child && child->classID == Spring->classID) {
302
self->childType = (child->type & 1) ? POPOUT_CHILD_SPRING_RED : POPOUT_CHILD_SPRING_YELLOW;
303
RSDK.SetSpriteAnimation(PopOut->aniFrames, 1, &self->childAnimator, true, self->childType);
304
}
305
else {
306
self->childType = POPOUT_CHILD_SPIKES;
307
RSDK.SetSpriteAnimation(PopOut->aniFrames, 2, &self->childAnimator, true, 0);
308
}
309
310
self->appearTimer = 0;
311
self->appearVelocity.x = 0;
312
self->appearVelocity.y = 0;
313
314
int32 storeX = self->position.x;
315
int32 storeY = self->position.y;
316
317
PopOut_Draw();
318
319
if (showGizmos()) {
320
PopOut_SetupHitboxes();
321
322
switch (self->orientation + 4 * self->direction) {
323
case 0:
324
case 4:
325
self->appearVelocity.x = 0;
326
self->appearVelocity.y = -0x10000;
327
break;
328
329
case 1:
330
case 5:
331
self->appearVelocity.y = 0;
332
self->appearVelocity.x = 0x10000;
333
break;
334
335
case 2:
336
case 6:
337
self->appearVelocity.x = 0;
338
self->appearVelocity.y = 0x10000;
339
break;
340
341
default:
342
case 3:
343
case 7:
344
self->appearVelocity.y = 0;
345
self->appearVelocity.x = -0x10000;
346
break;
347
}
348
349
DrawHelpers_DrawHitboxOutline(self->position.x, self->position.y, &self->hitboxRange, FLIP_NONE, 0xFF0000);
350
351
self->appearTimer = 8;
352
self->position.x = -16 * self->appearVelocity.x + self->position.x + 2 * self->appearTimer * self->appearVelocity.x;
353
self->position.y = -16 * self->appearVelocity.y + self->position.y + 2 * self->appearTimer * self->appearVelocity.y;
354
self->inkEffect = INK_BLEND;
355
356
PopOut_Draw();
357
358
self->inkEffect = INK_NONE;
359
self->position.x = storeX;
360
self->position.y = storeY;
361
362
if (self->manualTrigger && PopOut->hasButton) {
363
EntityButton *taggedButton = NULL;
364
foreach_all(Button, button)
365
{
366
if (button->tag == self->tag) {
367
taggedButton = button;
368
foreach_break;
369
}
370
}
371
372
if (taggedButton) {
373
RSDK_DRAWING_OVERLAY(true);
374
if (taggedButton) {
375
DrawHelpers_DrawArrow(taggedButton->position.x, taggedButton->position.y, self->position.x, self->position.y, 0xFFFF00, INK_NONE,
376
0xFF);
377
}
378
RSDK_DRAWING_OVERLAY(false);
379
}
380
}
381
}
382
}
383
384
void PopOut_EditorLoad(void) { PopOut->aniFrames = RSDK.LoadSpriteAnimation("TMZ1/PopOut.bin", SCOPE_STAGE); }
385
#endif
386
387
void PopOut_Serialize(void)
388
{
389
RSDK_EDITABLE_VAR(PopOut, VAR_UINT8, direction);
390
RSDK_EDITABLE_VAR(PopOut, VAR_UINT8, orientation);
391
RSDK_EDITABLE_VAR(PopOut, VAR_UINT8, tag);
392
RSDK_EDITABLE_VAR(PopOut, VAR_BOOL, manualTrigger);
393
RSDK_EDITABLE_VAR(PopOut, VAR_ENUM, delay);
394
}
395
396