Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/SPZ/PopcornMachine.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PopcornMachine Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectPopcornMachine *PopcornMachine;
11
12
void PopcornMachine_Update(void)
13
{
14
RSDK_THIS(PopcornMachine);
15
StateMachine_Run(self->state);
16
}
17
18
void PopcornMachine_LateUpdate(void) {}
19
20
void PopcornMachine_StaticUpdate(void) {}
21
22
void PopcornMachine_Draw(void)
23
{
24
RSDK_THIS(PopcornMachine);
25
Vector2 drawPos;
26
27
// Draw Dispenser
28
drawPos.x = self->position.x;
29
drawPos.y = self->position.y;
30
drawPos.x += self->dispenserPos.x;
31
drawPos.y = drawPos.y - 0x200000 + self->dispenserPos.y;
32
self->animator.frameID = 9;
33
RSDK.DrawSprite(&self->animator, &drawPos, false);
34
35
// Draw Dispenser Holder
36
drawPos = self->position;
37
drawPos.x += self->dispenserHolderPos.x;
38
drawPos.y = drawPos.y - 0x200000 + self->dispenserHolderPos.y;
39
self->animator.frameID = 10;
40
RSDK.DrawSprite(&self->animator, &drawPos, false);
41
42
// Draw Sign
43
self->animator.frameID = 0;
44
RSDK.DrawSprite(&self->animator, NULL, false);
45
46
// Draw Top
47
self->animator.frameID = 1;
48
RSDK.DrawSprite(&self->animator, NULL, false);
49
50
// Draw Entries
51
switch (self->type) {
52
case POPCORNMACHINE_LEFT:
53
self->animator.frameID = 2;
54
RSDK.DrawSprite(&self->animator, NULL, false);
55
break;
56
case POPCORNMACHINE_RIGHT:
57
self->animator.frameID = 3;
58
RSDK.DrawSprite(&self->animator, NULL, false);
59
break;
60
case POPCORNMACHINE_BOTH:
61
self->animator.frameID = 2;
62
RSDK.DrawSprite(&self->animator, NULL, false);
63
64
self->animator.frameID = 3;
65
RSDK.DrawSprite(&self->animator, NULL, false);
66
break;
67
}
68
69
// Draw Top
70
drawPos = self->position;
71
drawPos.y += -0xD00000 - 0xA00000 * self->height;
72
int32 storeY1 = drawPos.y;
73
int32 storeY2 = self->position.y - 0x300000;
74
self->animator.frameID = 4;
75
RSDK.DrawSprite(&self->animator, &drawPos, false);
76
77
self->animator.frameID = 5;
78
RSDK.DrawSprite(&self->animator, &drawPos, false);
79
80
// Draw (Initial) Machine Glass Edges
81
self->animator.frameID = 6;
82
RSDK.DrawSprite(&self->animator, &drawPos, false);
83
84
self->animator.frameID = 7;
85
RSDK.DrawSprite(&self->animator, &drawPos, false);
86
87
// Draw Machine Glass Edges
88
for (int32 y = 0; y < self->height; ++y) {
89
drawPos.y += 0xA00000;
90
self->animator.frameID = 6;
91
RSDK.DrawSprite(&self->animator, &drawPos, false);
92
self->animator.frameID = 7;
93
RSDK.DrawSprite(&self->animator, &drawPos, false);
94
}
95
96
// Draw City Reflection FX
97
RSDKScreenInfo *screen = &ScreenInfo[SceneInfo->currentScreenID];
98
99
self->inkEffect = INK_ADD;
100
self->animator.frameID = 8;
101
RSDK.SetClipBounds(SceneInfo->currentScreenID, 0, (storeY1 >> 16) - screen->position.y, screen->size.x, (storeY2 >> 16) - screen->position.y + 1);
102
103
drawPos = self->position;
104
drawPos.x -= 0x600000;
105
drawPos.y = (self->position.y + ((screen->center.y - 160 + screen->position.y) << 16)) >> 1;
106
RSDK.DrawSprite(&self->animator, &drawPos, false);
107
108
drawPos.x += 0xC00000;
109
drawPos.y = (self->position.y + ((screen->center.y - 384 + screen->position.y) << 16)) >> 1;
110
self->direction = FLIP_XY;
111
RSDK.DrawSprite(&self->animator, &drawPos, false);
112
113
self->direction = FLIP_NONE;
114
self->inkEffect = INK_NONE;
115
RSDK.SetClipBounds(SceneInfo->currentScreenID, 0, 0, screen->size.x, screen->size.y);
116
}
117
118
void PopcornMachine_Create(void *data)
119
{
120
RSDK_THIS(PopcornMachine);
121
122
if (!SceneInfo->inEditor) {
123
if (data) {
124
self->active = ACTIVE_NORMAL;
125
self->visible = false;
126
self->player = (EntityPlayer *)data;
127
self->state = PopcornMachine_StateController_ReadyPlayer;
128
}
129
else {
130
self->active = ACTIVE_BOUNDS;
131
self->updateRange.x = 0xB00000;
132
self->visible = true;
133
self->updateRange.y = 0xA00000 * self->height + 0x1000000;
134
self->drawGroup = Zone->objectDrawGroup[1];
135
self->drawFX = FX_FLIP;
136
self->alpha = 0xE0;
137
self->dispenserHolderPos.y = -0x100000;
138
self->dispenserPos.y = -0x100000;
139
140
int32 top = -0x100 - 0xA0 * self->height;
141
self->hitboxSideL.top = top;
142
self->hitboxSideL.left = -128;
143
self->hitboxSideL.right = -120;
144
self->hitboxSideL.bottom = -32;
145
146
self->hitboxSideR.left = 120;
147
self->hitboxSideR.top = top;
148
self->hitboxSideR.right = 128;
149
self->hitboxSideR.bottom = -32;
150
151
self->hitboxTop.left = -128;
152
self->hitboxTop.top = top;
153
self->hitboxTop.right = 128;
154
self->hitboxTop.bottom = top + 16;
155
156
self->state = PopcornMachine_State_Idle;
157
RSDK.SetSpriteAnimation(PopcornMachine->aniFrames, 0, &self->animator, true, 0);
158
}
159
}
160
}
161
162
void PopcornMachine_StageLoad(void)
163
{
164
PopcornMachine->aniFrames = RSDK.LoadSpriteAnimation("SPZ1/PopcornMachine.bin", SCOPE_STAGE);
165
166
PopcornMachine->hitboxEntryL.left = -176;
167
PopcornMachine->hitboxEntryL.right = -128;
168
PopcornMachine->hitboxEntryL.top = -16;
169
PopcornMachine->hitboxEntryL.bottom = 24;
170
171
PopcornMachine->hitboxEntryR.left = 128;
172
PopcornMachine->hitboxEntryR.right = 176;
173
PopcornMachine->hitboxEntryR.top = -16;
174
PopcornMachine->hitboxEntryR.bottom = 24;
175
176
PopcornMachine->sfxFanStart = RSDK.GetSfx("Stage/FanStart.wav");
177
PopcornMachine->sfxShoot = RSDK.GetSfx("Stage/Shoot1.wav");
178
PopcornMachine->sfxPopcornLaunch = RSDK.GetSfx("Stage/PopcornLaunch.wav");
179
}
180
181
void PopcornMachine_LinkPlayer(EntityPlayer *player)
182
{
183
RSDK_THIS(PopcornMachine);
184
185
player->nextAirState = StateMachine_None;
186
player->nextGroundState = StateMachine_None;
187
player->state = Player_State_Static;
188
player->onGround = false;
189
player->velocity.x = player->position.x < self->position.x ? 0xA0000 : -0xA0000;
190
player->tileCollisions = TILECOLLISION_NONE;
191
RSDK.SetSpriteAnimation(player->aniFrames, ANI_JUMP, &player->animator, false, 0);
192
193
EntityPopcornMachine *machine = CREATE_ENTITY(PopcornMachine, player, self->position.x, self->position.y);
194
machine->isPermanent = true;
195
machine->parent = self;
196
if (!player->sidekick)
197
machine->bounds[player->playerID] = Zone->cameraBoundsB[player->playerID];
198
}
199
void PopcornMachine_CheckPlayerCollisions(void)
200
{
201
RSDK_THIS(PopcornMachine);
202
203
foreach_active(Player, player)
204
{
205
Player_CheckCollisionBox(player, self, &self->hitboxSideL);
206
Player_CheckCollisionBox(player, self, &self->hitboxSideR);
207
Player_CheckCollisionPlatform(player, self, &self->hitboxTop);
208
209
if (player->state != Player_State_Static) {
210
211
switch (self->type) {
212
case POPCORNMACHINE_LEFT:
213
if (player->onGround && Player_CheckCollisionTouch(player, self, &PopcornMachine->hitboxEntryL)) {
214
PopcornMachine_LinkPlayer(player);
215
}
216
else if (!player->onGround) {
217
Player_CheckCollisionBox(player, self, &PopcornMachine->hitboxEntryL);
218
}
219
break;
220
221
case POPCORNMACHINE_RIGHT:
222
if (player->onGround && Player_CheckCollisionTouch(player, self, &PopcornMachine->hitboxEntryL)) {
223
PopcornMachine_LinkPlayer(player);
224
}
225
else if (!player->onGround) {
226
Player_CheckCollisionBox(player, self, &PopcornMachine->hitboxEntryR);
227
}
228
break;
229
230
case POPCORNMACHINE_BOTH:
231
if (player->onGround) {
232
if (Player_CheckCollisionTouch(player, self, &PopcornMachine->hitboxEntryL)) {
233
PopcornMachine_LinkPlayer(player);
234
}
235
else {
236
if (Player_CheckCollisionTouch(player, self, &PopcornMachine->hitboxEntryR))
237
PopcornMachine_LinkPlayer(player);
238
}
239
}
240
else {
241
Player_CheckCollisionBox(player, self, &PopcornMachine->hitboxEntryL);
242
Player_CheckCollisionBox(player, self, &PopcornMachine->hitboxEntryR);
243
}
244
break;
245
}
246
}
247
}
248
}
249
250
void PopcornMachine_State_Idle(void) { PopcornMachine_CheckPlayerCollisions(); }
251
252
void PopcornMachine_State_ShowDispenser(void)
253
{
254
RSDK_THIS(PopcornMachine);
255
256
PopcornMachine_CheckPlayerCollisions();
257
258
self->dispenserHolderPos.y -= 0x8000;
259
if (self->dispenserHolderPos.y <= -0x200000)
260
self->dispenserHolderPos.y = -0x200000;
261
262
self->dispenserPos.y -= 0x18000;
263
if (self->dispenserPos.y <= -0x400000) {
264
self->dispenserPos.y = -0x400000;
265
self->timer = 0;
266
self->state = PopcornMachine_State_Shaking;
267
}
268
}
269
270
void PopcornMachine_State_Shaking(void)
271
{
272
RSDK_THIS(PopcornMachine);
273
274
PopcornMachine_CheckPlayerCollisions();
275
276
self->dispenserHolderPos.x = RSDK.Rand(-0x20000, 0x20000);
277
self->dispenserHolderPos.y = RSDK.Rand(-0x20000, 0x20000) - 0x1E0000;
278
279
self->dispenserPos.x = RSDK.Rand(-0x20000, 0x20000);
280
self->dispenserPos.y = self->dispenserHolderPos.y - 0x1E0000 + RSDK.Rand(-0x20000, 0x20000);
281
282
self->timer++;
283
if (self->timer >= 25 && self->timer < 160) {
284
if (!(self->timer & 1)) {
285
EntityPopcornKernel *kernel = CREATE_ENTITY(PopcornKernel, NULL, self->position.x, self->position.y - 0x400000);
286
kernel->velocity.x = RSDK.Rand(-0x30000, 0x30000);
287
kernel->velocity.y = RSDK.Rand(-0xC0000, -0x60000);
288
kernel->angleVel = RSDK.Rand(-0x60000, 0x60000);
289
kernel->bounds.x = self->position.x;
290
kernel->bounds.y = self->position.y;
291
}
292
293
if (!(self->timer & 7))
294
RSDK.PlaySfx(PopcornMachine->sfxShoot, false, 255);
295
}
296
297
if (self->timer == 160) {
298
foreach_active(PopcornKernel, kernel)
299
{
300
kernel->state = PopcornKernel_State_RiseUp;
301
kernel->velocity.x = 0;
302
kernel->velocity.y = RSDK.Rand(-0xA0000, -0x60000);
303
kernel->maxY = self->position.y - (0xA00000 * self->height) - 0xD00000;
304
}
305
306
RSDK.PlaySfx(PopcornMachine->sfxPopcornLaunch, false, 255);
307
self->state = PopcornMachine_State_HideDispenser;
308
}
309
}
310
311
void PopcornMachine_State_HideDispenser(void)
312
{
313
RSDK_THIS(PopcornMachine);
314
315
PopcornMachine_CheckPlayerCollisions();
316
317
self->dispenserHolderPos.y += 0x8000;
318
if (self->dispenserHolderPos.y >= 0)
319
self->dispenserHolderPos.y = 0;
320
321
self->dispenserPos.y += 0x18000;
322
if (self->dispenserPos.y >= 0) {
323
self->dispenserPos.y = 0;
324
self->state = PopcornMachine_State_Idle;
325
}
326
}
327
328
void PopcornMachine_StateController_ReadyPlayer(void)
329
{
330
RSDK_THIS(PopcornMachine);
331
332
EntityPopcornMachine *parent = self->parent;
333
EntityPlayer *player = self->player;
334
335
if (Player_CheckValidState(player)) {
336
if (player->position.y < self->position.y - 0x300000) {
337
player->position.y = self->position.y - 0x300000;
338
player->velocity.y = 0;
339
self->state = PopcornMachine_StateController_FirePlayer;
340
}
341
342
if (!Player_CheckValidState(player)) {
343
if (!player->sidekick)
344
Zone->cameraBoundsB[player->playerID] = self->bounds[player->playerID];
345
346
destroyEntity(self);
347
}
348
}
349
else {
350
destroyEntity(self);
351
}
352
353
if (abs(self->position.x - player->position.x) < 0x100000) {
354
player->position.x = self->position.x;
355
player->groundVel = 0;
356
player->velocity.x = 0;
357
player->velocity.y = -0x80000;
358
359
if (!player->sidekick)
360
Zone->cameraBoundsB[player->playerID] = (self->position.y >> 16) + 32;
361
362
if (parent->state == PopcornMachine_State_Idle || parent->state == PopcornMachine_State_HideDispenser) {
363
parent->state = PopcornMachine_State_ShowDispenser;
364
RSDK.PlaySfx(PopcornMachine->sfxFanStart, false, 255);
365
}
366
367
self->state = PopcornMachine_StateController_RisePlayer;
368
}
369
370
if (!Player_CheckValidState(player)) {
371
if (!player->sidekick)
372
Zone->cameraBoundsB[player->playerID] = self->bounds[player->playerID];
373
374
destroyEntity(self);
375
}
376
}
377
378
void PopcornMachine_StateController_RisePlayer(void)
379
{
380
RSDK_THIS(PopcornMachine);
381
382
EntityPlayer *player = self->player;
383
384
if (Player_CheckValidState(player)) {
385
if (player->position.y < self->position.y - 0x300000) {
386
player->position.y = self->position.y - 0x300000;
387
player->velocity.y = 0;
388
self->state = PopcornMachine_StateController_FirePlayer;
389
}
390
391
if (!Player_CheckValidState(player)) {
392
if (!player->sidekick)
393
Zone->cameraBoundsB[player->playerID] = self->bounds[player->playerID];
394
395
destroyEntity(self);
396
}
397
}
398
else {
399
destroyEntity(self);
400
}
401
}
402
403
void PopcornMachine_StateController_FirePlayer(void)
404
{
405
RSDK_THIS(PopcornMachine);
406
EntityPopcornMachine *parent = self->parent;
407
EntityPlayer *player = self->player;
408
409
if (Player_CheckValidState(player)) {
410
if (parent->state == PopcornMachine_State_HideDispenser) {
411
player->state = Player_State_Air;
412
player->gravityStrength = 0x80;
413
player->velocity.y = -0xD8000 - (parent->height << 16);
414
player->position.y += player->velocity.y;
415
416
RSDK.SetSpriteAnimation(player->aniFrames, ANI_FAN, &player->animator, false, 0);
417
if (!player->sidekick)
418
Zone->cameraBoundsB[player->playerID] = self->bounds[player->playerID];
419
420
self->state = PopcornMachine_StateController_HandleFinish;
421
}
422
}
423
else {
424
destroyEntity(self);
425
}
426
}
427
428
void PopcornMachine_StateController_HandleFinish(void)
429
{
430
RSDK_THIS(PopcornMachine);
431
EntityPopcornMachine *parent = self->parent;
432
EntityPlayer *player = self->player;
433
434
if (Player_CheckValidState(player)) {
435
if (player->position.y < parent->position.y - 0xA00000 * parent->height + 0xD00000) {
436
player->tileCollisions = TILECOLLISION_DOWN;
437
Player_UpdatePhysicsState(player);
438
destroyEntity(self);
439
}
440
}
441
else {
442
destroyEntity(self);
443
}
444
}
445
446
#if GAME_INCLUDE_EDITOR
447
void PopcornMachine_EditorDraw(void)
448
{
449
RSDK_THIS(PopcornMachine);
450
self->active = ACTIVE_BOUNDS;
451
self->updateRange.x = 0xB00000;
452
self->visible = true;
453
self->updateRange.y = 0xA00000 * self->height + 0x1000000;
454
self->drawGroup = Zone->objectDrawGroup[1];
455
self->drawFX = FX_FLIP;
456
self->alpha = 0xE0;
457
self->dispenserHolderPos.y = -0x100000;
458
self->dispenserPos.y = -0x100000;
459
RSDK.SetSpriteAnimation(PopcornMachine->aniFrames, 0, &self->animator, true, 0);
460
461
// Draw !!
462
Vector2 drawPos;
463
464
// Draw Dispenser
465
drawPos.x = self->position.x;
466
drawPos.y = self->position.y;
467
drawPos.x += self->dispenserPos.x;
468
drawPos.y = drawPos.y - 0x200000 + self->dispenserPos.y;
469
self->animator.frameID = 9;
470
RSDK.DrawSprite(&self->animator, &drawPos, false);
471
472
// Draw Dispenser Holder
473
drawPos = self->position;
474
drawPos.x += self->dispenserHolderPos.x;
475
drawPos.y = drawPos.y - 0x200000 + self->dispenserHolderPos.y;
476
self->animator.frameID = 10;
477
RSDK.DrawSprite(&self->animator, &drawPos, false);
478
479
// Draw Sign
480
self->animator.frameID = 0;
481
RSDK.DrawSprite(&self->animator, NULL, false);
482
483
// Draw Top
484
self->animator.frameID = 1;
485
RSDK.DrawSprite(&self->animator, NULL, false);
486
487
// Draw Entries
488
switch (self->type) {
489
case POPCORNMACHINE_LEFT:
490
self->animator.frameID = 2;
491
RSDK.DrawSprite(&self->animator, NULL, false);
492
break;
493
case POPCORNMACHINE_RIGHT:
494
self->animator.frameID = 3;
495
RSDK.DrawSprite(&self->animator, NULL, false);
496
break;
497
case POPCORNMACHINE_BOTH:
498
self->animator.frameID = 2;
499
RSDK.DrawSprite(&self->animator, NULL, false);
500
501
self->animator.frameID = 3;
502
RSDK.DrawSprite(&self->animator, NULL, false);
503
break;
504
}
505
506
// Draw Top
507
drawPos = self->position;
508
drawPos.y += -0xD00000 - 0xA00000 * self->height;
509
self->animator.frameID = 4;
510
RSDK.DrawSprite(&self->animator, &drawPos, false);
511
512
self->animator.frameID = 5;
513
RSDK.DrawSprite(&self->animator, &drawPos, false);
514
515
// Draw (Initial) Machine Glass Edges
516
self->animator.frameID = 6;
517
RSDK.DrawSprite(&self->animator, &drawPos, false);
518
519
self->animator.frameID = 7;
520
RSDK.DrawSprite(&self->animator, &drawPos, false);
521
522
// Draw Machine Glass Edges
523
for (int32 y = 0; y < self->height; ++y) {
524
drawPos.y += 0xA00000;
525
self->animator.frameID = 6;
526
RSDK.DrawSprite(&self->animator, &drawPos, false);
527
self->animator.frameID = 7;
528
RSDK.DrawSprite(&self->animator, &drawPos, false);
529
}
530
}
531
532
void PopcornMachine_EditorLoad(void)
533
{
534
PopcornMachine->aniFrames = RSDK.LoadSpriteAnimation("SPZ1/PopcornMachine.bin", SCOPE_STAGE);
535
536
RSDK_ACTIVE_VAR(PopcornMachine, type);
537
RSDK_ENUM_VAR("Left Entry", POPCORNMACHINE_LEFT);
538
RSDK_ENUM_VAR("Right Entry", POPCORNMACHINE_RIGHT);
539
RSDK_ENUM_VAR("Double Entry", POPCORNMACHINE_BOTH);
540
}
541
#endif
542
543
void PopcornMachine_Serialize(void)
544
{
545
RSDK_EDITABLE_VAR(PopcornMachine, VAR_UINT8, type);
546
RSDK_EDITABLE_VAR(PopcornMachine, VAR_UINT8, height);
547
}
548
549