Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/PGZ/PetalPile.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PetalPile Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPetalPile *PetalPile;
11
12
void PetalPile_Update(void)
13
{
14
RSDK_THIS(PetalPile);
15
16
StateMachine_Run(self->state);
17
18
if (!self->animator.animationID)
19
RSDK.ProcessAnimation(&self->animator);
20
}
21
22
void PetalPile_LateUpdate(void) {}
23
24
void PetalPile_StaticUpdate(void) {}
25
26
void PetalPile_Draw(void)
27
{
28
RSDK_THIS(PetalPile);
29
StateMachine_Run(self->stateDraw);
30
}
31
32
void PetalPile_Create(void *data)
33
{
34
RSDK_THIS(PetalPile);
35
36
self->active = ACTIVE_BOUNDS;
37
self->visible = true;
38
self->drawGroup = Zone->objectDrawGroup[1];
39
self->drawFX = FX_FLIP;
40
self->updateRange.x = 0x100000;
41
self->updateRange.y = 0x100000;
42
43
if (SceneInfo->inEditor) {
44
if (!self->maxSpeed.x)
45
self->maxSpeed.x = 0x18000;
46
47
if (!self->pileSize.x && !self->pileSize.y) {
48
self->pileSize.x = 0x300000;
49
self->pileSize.y = 0x80000;
50
}
51
}
52
else {
53
if (self->tileLayer)
54
self->layerID = RSDK.GetTileLayerID("FG Low");
55
else
56
self->layerID = RSDK.GetTileLayerID("FG High");
57
}
58
59
RSDK.SetSpriteAnimation(PetalPile->aniFrames, 0, &self->animator, true, 0);
60
self->state = PetalPile_State_Init;
61
}
62
63
void PetalPile_StageLoad(void)
64
{
65
if (RSDK.CheckSceneFolder("PSZ1"))
66
PetalPile->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Petal.bin", SCOPE_STAGE);
67
else if (RSDK.CheckSceneFolder("PSZ2"))
68
PetalPile->aniFrames = RSDK.LoadSpriteAnimation("PSZ2/Petal.bin", SCOPE_STAGE);
69
70
PetalPile->sfxPetals = RSDK.GetSfx("PSZ/Petals.wav");
71
}
72
73
int32 PetalPile_GetLeafPattern(Vector2 *patternPtr)
74
{
75
RSDK_THIS(PetalPile);
76
77
int32 count = PetalPile->patternSize[self->leafPattern];
78
int32 *pattern = NULL;
79
switch (self->leafPattern) {
80
case PETALPILE_PATTERN_0: pattern = PetalPile->pattern1; break;
81
case PETALPILE_PATTERN_1: pattern = PetalPile->pattern2; break;
82
case PETALPILE_PATTERN_2: pattern = PetalPile->pattern3; break;
83
case PETALPILE_PATTERN_3: pattern = PetalPile->pattern4; break;
84
case PETALPILE_PATTERN_4: pattern = PetalPile->pattern5; break;
85
default: return 0;
86
}
87
88
int32 sizeX = MAX(self->pileSize.x, 0x20000);
89
int32 sizeY = MAX(self->pileSize.y, 0x20000);
90
for (int32 i = 0; i < count; ++i) {
91
patternPtr[i].x = pattern[(i * 2) + 0] * (sizeX >> 17);
92
patternPtr[i].y = pattern[(i * 2) + 1] * (sizeY >> 17);
93
}
94
95
return count;
96
}
97
98
void PetalPile_State_Init(void)
99
{
100
RSDK_THIS(PetalPile);
101
102
self->hitbox.left = -(self->pileSize.x >> 17);
103
self->hitbox.top = -(self->pileSize.y >> 17);
104
self->hitbox.right = self->pileSize.x >> 17;
105
self->hitbox.bottom = self->pileSize.y >> 17;
106
107
if (self->noRemoveTiles) {
108
self->state = PetalPile_State_SetupEmitter;
109
PetalPile_State_SetupEmitter();
110
}
111
else {
112
self->state = PetalPile_State_HandleInteractions;
113
PetalPile_State_HandleInteractions();
114
}
115
}
116
117
void PetalPile_State_HandleInteractions(void)
118
{
119
RSDK_THIS(PetalPile);
120
121
foreach_active(Player, player)
122
{
123
if (Player_CheckCollisionTouch(player, self, &self->hitbox)) {
124
if (!player->sidekick) {
125
if (abs(player->groundVel) >= 0x60000 || player->velocity.y > 0x60000 || player->velocity.y < -0x70000
126
|| player->state == Player_State_Spindash || player->state == Player_State_DropDash) {
127
bool32 isFast = false;
128
if (player->state == Player_State_Spindash || player->state == Player_State_DropDash || abs(player->groundVel) >= 0x60000)
129
isFast = true;
130
131
self->petalDir = isFast * (2 * (player->direction != FLIP_NONE) - 1);
132
133
if (player->state == Player_State_Spindash || player->state == Player_State_DropDash)
134
self->petalRadius = 0xF5555;
135
else
136
self->petalRadius = 0xB5555;
137
138
self->petalVel = player->groundVel >> 1;
139
self->distance.x = player->position.x - self->position.x;
140
self->distance.y = 0;
141
RSDK.PlaySfx(PetalPile->sfxPetals, false, 255);
142
self->state = PetalPile_State_SetupEmitter;
143
144
foreach_break;
145
}
146
}
147
148
if (!self->emitterMode && abs(player->groundVel) < 0x60000 && abs(player->groundVel) > abs(self->maxSpeed.x))
149
player->groundVel =
150
player->groundVel - ((abs(player->groundVel) - abs(self->maxSpeed.x)) >> 1) * (((player->groundVel >> 31) & -2) + 1);
151
}
152
}
153
154
if (self->state != PetalPile_State_SetupEmitter) {
155
Hitbox hitbox;
156
hitbox.left = -8;
157
hitbox.top = -8;
158
hitbox.right = 8;
159
hitbox.bottom = 8;
160
161
foreach_active(Explosion, explosion)
162
{
163
if (RSDK.CheckObjectCollisionTouchBox(self, &self->hitbox, explosion, &hitbox)) {
164
self->petalDir = 0;
165
self->petalRadius = 0xF5555;
166
self->distance.x = explosion->position.x - self->position.x;
167
self->distance.y = 0;
168
RSDK.PlaySfx(PetalPile->sfxPetals, false, 255);
169
self->state = PetalPile_State_SetupEmitter;
170
171
foreach_break;
172
}
173
}
174
}
175
}
176
177
void PetalPile_State_SetupEmitter(void)
178
{
179
RSDK_THIS(PetalPile);
180
181
Vector2 pattern[0x100];
182
memset(pattern, 0, sizeof(pattern));
183
int32 count = PetalPile_GetLeafPattern(pattern);
184
185
int32 offsetX = 0, offsetY = 0;
186
switch (self->petalDir) {
187
case -1:
188
offsetX = self->position.x + ((self->hitbox.right + 16) << 16);
189
offsetY = self->position.y + ((self->hitbox.bottom + 32) << 16);
190
break;
191
192
case 0:
193
offsetX = self->position.x + self->distance.x;
194
offsetY = self->position.y + ((self->hitbox.bottom + 32) << 16);
195
break;
196
197
case 1:
198
offsetX = self->position.x + ((self->hitbox.left - 16) << 16);
199
offsetY = self->position.y + ((self->hitbox.bottom + 32) << 16);
200
break;
201
}
202
203
int32 pos = 0;
204
for (int32 i = 0; i < count; ++i) pos = MAX(pos, abs((self->position.x - offsetX) + pattern[i].x));
205
206
for (int32 i = 0; i < count; ++i) {
207
int32 spawnX = pattern[i].x + self->position.x;
208
int32 spawnY = pattern[i].y + self->position.y;
209
210
int32 angle = RSDK.ATan2(spawnX - offsetX, spawnY - offsetY);
211
EntityPetalPile *petal = CREATE_ENTITY(PetalPile, self, spawnX, spawnY);
212
petal->state = PetalPile_StateLeaf_Setup;
213
petal->stateDraw = PetalPile_Draw_Leaf;
214
215
int32 radius = self->petalRadius >> 1;
216
if (self->petalDir) {
217
petal->direction = self->petalDir <= 0;
218
petal->petalVel = self->petalVel;
219
radius = (self->petalRadius >> 8) * ((16 * (abs(spawnX - offsetX) / (pos >> 16))) >> 12);
220
petal->timer = (pos - abs(spawnX - offsetX)) >> 18;
221
}
222
else {
223
petal->direction = ZONE_RAND(FLIP_NONE, FLIP_X);
224
}
225
226
petal->velStore.x = (radius >> 8) * RSDK.Cos256(angle);
227
petal->velStore.y = (radius >> 9) * RSDK.Sin256(angle) - 0x20000;
228
petal->drawGroup = self->tileLayer ? Zone->objectDrawGroup[0] : Zone->objectDrawGroup[1];
229
}
230
231
if (self->emitterMode) {
232
self->state = PetalPile_State_Emitter;
233
}
234
else {
235
if (!self->noRemoveTiles) {
236
int32 left = (self->position.x >> 16) + self->hitbox.left;
237
int32 right = (self->position.x >> 16) + self->hitbox.right;
238
int32 top = (self->position.y >> 16) + self->hitbox.top;
239
int32 bottom = (self->position.y >> 16) + self->hitbox.bottom;
240
241
int32 sizeX = (right >> 4) - (left >> 4);
242
int32 sizeY = (bottom >> 4) - (top >> 4);
243
for (int32 x = 0; x <= sizeX; ++x) {
244
for (int32 y = 0; y <= sizeY; ++y) {
245
RSDK.SetTile(self->layerID, x + (left >> 4), y + (top >> 4), -1);
246
}
247
}
248
}
249
250
destroyEntity(self);
251
}
252
}
253
254
void PetalPile_State_Emitter(void)
255
{
256
RSDK_THIS(PetalPile);
257
258
bool32 collided = false;
259
foreach_active(Player, player)
260
{
261
if (Player_CheckCollisionTouch(player, self, &self->hitbox))
262
collided = true;
263
}
264
265
if (!collided)
266
self->state = PetalPile_State_Init;
267
}
268
269
void PetalPile_StateLeaf_Setup(void)
270
{
271
RSDK_THIS(PetalPile);
272
273
self->hitbox.left = -1;
274
self->hitbox.top = -1;
275
self->hitbox.right = 1;
276
self->hitbox.bottom = 1;
277
278
self->active = ACTIVE_NORMAL;
279
self->updateRange.x = 0x10000;
280
self->updateRange.y = 0x10000;
281
RSDK.SetSpriteAnimation(PetalPile->aniFrames, 0, &self->animator, true, 0);
282
283
self->state = PetalPile_StateLeaf_Delay;
284
PetalPile_StateLeaf_Delay();
285
}
286
287
void PetalPile_StateLeaf_Delay(void)
288
{
289
RSDK_THIS(PetalPile);
290
291
if (self->timer <= 0) {
292
self->state = PetalPile_StateLeaf_HandleVelocity;
293
self->timer = 0;
294
self->velocity = self->velStore;
295
}
296
else {
297
self->timer--;
298
}
299
300
if (!RSDK.CheckOnScreen(self, &self->updateRange))
301
destroyEntity(self);
302
}
303
304
void PetalPile_StateLeaf_HandleVelocity(void)
305
{
306
RSDK_THIS(PetalPile);
307
308
if (self->petalVel > 0) {
309
self->petalVel -= 4096;
310
if (self->petalVel < 0)
311
self->petalVel = 0;
312
}
313
else if (self->petalVel < 0) {
314
self->petalVel += 0x1000;
315
if (self->petalVel > 0)
316
self->petalVel = 0;
317
}
318
319
self->position.x += self->petalVel;
320
321
if (self->velocity.x <= 0)
322
self->velocity.x += MIN(abs(self->velocity.x), 0x8000);
323
else
324
self->velocity.x -= MIN(abs(self->velocity.x), 0x8000);
325
self->velocity.y += 0x4000;
326
327
if (self->velocity.y > 0)
328
self->velocity.y = 0;
329
330
self->position.x += self->velocity.x;
331
self->position.y += self->velocity.y;
332
333
if (++self->timer > 2) {
334
if (ZONE_RAND(0, 10) > 6)
335
self->direction = self->direction == FLIP_NONE;
336
337
self->timer = 0;
338
}
339
340
if (self->velocity.y >= 0 && !self->velocity.x) {
341
self->petalOffset = ZONE_RAND(0, 255);
342
self->state = PetalPile_StateLeaf_Fall;
343
}
344
345
if (!RSDK.CheckOnScreen(self, &self->updateRange))
346
destroyEntity(self);
347
}
348
349
void PetalPile_StateLeaf_Fall(void)
350
{
351
RSDK_THIS(PetalPile);
352
353
if (self->petalVel > 0) {
354
self->petalVel -= 4096;
355
if (self->petalVel < 0)
356
self->petalVel = 0;
357
}
358
else if (self->petalVel < 0) {
359
self->petalVel += 0x1000;
360
if (self->petalVel > 0)
361
self->petalVel = 0;
362
}
363
364
self->position.x += self->petalVel;
365
366
self->velocity.y += 0x4000;
367
if (self->velocity.y > 0x10000)
368
self->velocity.y = 0x10000;
369
370
self->velocity.x = RSDK.Sin256(4 * self->petalOffset) << 8;
371
372
self->position.x += self->velocity.x;
373
self->position.y += self->velocity.y;
374
375
++self->timer;
376
if (self->timer > 3) {
377
if (ZONE_RAND(0, 10) > 6)
378
self->direction = self->direction == FLIP_NONE;
379
380
self->timer = 0;
381
}
382
383
if (!RSDK.CheckOnScreen(self, &self->updateRange))
384
destroyEntity(self);
385
386
self->petalOffset++;
387
}
388
389
void PetalPile_Draw_Leaf(void)
390
{
391
RSDK_THIS(PetalPile);
392
393
RSDK.DrawSprite(&self->animator, NULL, false);
394
}
395
396
#if GAME_INCLUDE_EDITOR
397
void PetalPile_EditorDraw(void)
398
{
399
RSDK_THIS(PetalPile);
400
401
DrawHelpers_DrawRectOutline(self->position.x, self->position.y, self->pileSize.x, self->pileSize.y, 0xFFFF00);
402
}
403
404
void PetalPile_EditorLoad(void)
405
{
406
if (RSDK.CheckSceneFolder("PSZ1"))
407
PetalPile->aniFrames = RSDK.LoadSpriteAnimation("PSZ1/Petal.bin", SCOPE_STAGE);
408
else if (RSDK.CheckSceneFolder("PSZ2"))
409
PetalPile->aniFrames = RSDK.LoadSpriteAnimation("PSZ2/Petal.bin", SCOPE_STAGE);
410
411
RSDK_ACTIVE_VAR(PetalPile, leafPattern);
412
RSDK_ENUM_VAR("Pattern 0", PETALPILE_PATTERN_0);
413
RSDK_ENUM_VAR("Pattern 1", PETALPILE_PATTERN_1);
414
RSDK_ENUM_VAR("Pattern 2", PETALPILE_PATTERN_2);
415
RSDK_ENUM_VAR("Pattern 3", PETALPILE_PATTERN_3);
416
RSDK_ENUM_VAR("Pattern 4", PETALPILE_PATTERN_4);
417
418
RSDK_ACTIVE_VAR(PetalPile, tileLayer);
419
RSDK_ENUM_VAR("FG High", PETALPILE_FGHIGH);
420
RSDK_ENUM_VAR("FG Low", PETALPILE_FGLOW);
421
}
422
#endif
423
424
void PetalPile_Serialize(void)
425
{
426
RSDK_EDITABLE_VAR(PetalPile, VAR_INT8, leafPattern);
427
RSDK_EDITABLE_VAR(PetalPile, VAR_INT8, tileLayer);
428
RSDK_EDITABLE_VAR(PetalPile, VAR_VECTOR2, pileSize);
429
RSDK_EDITABLE_VAR(PetalPile, VAR_VECTOR2, maxSpeed);
430
RSDK_EDITABLE_VAR(PetalPile, VAR_BOOL, emitterMode);
431
}
432
433