Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/Puyo/PuyoGame.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: PuyoGame Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
#include <time.h>
10
11
ObjectPuyoGame *PuyoGame;
12
13
void PuyoGame_Update(void)
14
{
15
RSDK_THIS(PuyoGame);
16
17
if (!self->started) {
18
PuyoGame_SetupStartingEntities();
19
self->started = true;
20
}
21
22
StateMachine_Run(self->state);
23
24
RSDK.ProcessAnimation(&self->animator);
25
26
if ((ControllerInfo->keyStart.press || Unknown_pausePress) && !RSDK_GET_ENTITY(SLOT_PAUSEMENU, PauseMenu)->classID) {
27
RSDK.ResetEntitySlot(SLOT_PAUSEMENU, PauseMenu->classID, NULL);
28
RSDK_GET_ENTITY(SLOT_PAUSEMENU, PauseMenu)->disableRestart = true;
29
RSDK.PlaySfx(PauseMenu->sfxAccept, false, 0xFF);
30
RSDK.SetEngineState(ENGINESTATE_FROZEN);
31
}
32
}
33
34
void PuyoGame_LateUpdate(void) {}
35
36
void PuyoGame_StaticUpdate(void) {}
37
38
void PuyoGame_Draw(void) {}
39
40
void PuyoGame_Create(void *data)
41
{
42
RSDK_THIS(PuyoGame);
43
44
self->active = ACTIVE_NORMAL;
45
self->drawGroup = Zone->objectDrawGroup[0];
46
self->startPos = self->position;
47
self->visible = false;
48
self->drawFX = FX_FLIP;
49
self->updateRange.x = 0x800000;
50
self->updateRange.y = 0x800000;
51
52
if (!SceneInfo->inEditor)
53
RSDK.AddCamera(&self->position, ScreenInfo->center.x << 16, ScreenInfo->center.y << 16, true);
54
55
self->state = PuyoGame_State_Init;
56
}
57
58
void PuyoGame_StageLoad(void)
59
{
60
PuyoGame->aniFrames = RSDK.LoadSpriteAnimation("Puyo/PuyoBeans.bin", SCOPE_STAGE);
61
62
foreach_all(FXFade, fxFade) { PuyoGame->fxFade = fxFade; }
63
64
String text;
65
Localization_GetString(&text, STR_RPC_PLAYING);
66
API_SetRichPresence(PRESENCE_GENERIC, &text);
67
destroyEntitySlot(SLOT_ZONE);
68
}
69
70
void PuyoGame_SetupStartingEntities(void)
71
{
72
RSDK_THIS(PuyoGame);
73
74
EntityMenuParam *param = MenuParam_GetParam();
75
EntityCompetitionSession *session = CompetitionSession_GetSession();
76
77
ScreenInfo->position.x = (self->position.x >> 16) - ScreenInfo->center.x;
78
ScreenInfo->position.y = (self->position.y >> 16) - ScreenInfo->center.y;
79
80
foreach_all(PuyoScore, score)
81
{
82
int32 playerID = score->playerID;
83
if (score->counter) {
84
PuyoGame->score2[playerID] = score;
85
86
if (param->puyoSelection == PUYO_SELECTION_TIE_BREAKER)
87
score->score = session->wins[playerID];
88
}
89
else {
90
PuyoGame->score1[playerID] = score;
91
}
92
}
93
94
foreach_all(PuyoLevelSelect, levelSel) { PuyoGame->levelSel[levelSel->playerID] = levelSel; }
95
96
if (param->puyoSelection == PUYO_SELECTION_TIE_BREAKER) {
97
self->selectedLevels[0] = 1;
98
self->selectedLevels[1] = 1;
99
self->state = PuyoGame_State_SetupRound;
100
}
101
else {
102
self->state = PuyoGame_State_SelectingLevel;
103
}
104
}
105
106
void PuyoGame_SetLoser(uint8 loser)
107
{
108
RSDK_THIS(PuyoGame);
109
110
EntityPuyoMatch *manager = PuyoGame->managers[loser];
111
EntityCollapsingPlatform *platform = PuyoGame->platforms[loser];
112
113
int32 winner = loser ^ 1;
114
self->determinedLoser = true;
115
self->roundWinner = winner;
116
platform->stoodPos.x = manager->position.x;
117
manager->timer = 7;
118
PuyoAI->isAI[0] = false;
119
PuyoAI->isAI[1] = false;
120
121
EntityPuyoMatch *foeManager = PuyoGame->managers[winner];
122
EntityPuyoScore *foeScore = PuyoGame->score2[winner];
123
++foeScore->score;
124
foeScore->flashing = true;
125
foeManager->state = StateMachine_None;
126
127
PuyoBean_DestroyPuyoBeans();
128
PuyoGame_CheckMatchFinish();
129
130
self->timer = 0;
131
self->state = self->finishedMatch ? PuyoGame_State_ShowMatchResults : PuyoGame_State_ShowRoundResults;
132
}
133
134
void PuyoGame_DestroyPuyoBeans(void)
135
{
136
foreach_all(PuyoBean, bean) { destroyEntity(bean); }
137
}
138
139
void PuyoGame_SetupGameState(void)
140
{
141
int32 fgHighRebuild = RSDK.GetTileLayerID("FG High Rebuild");
142
int32 fgHigh = RSDK.GetTileLayerID("FG High");
143
144
RSDK.CopyTileLayer(fgHigh, 0, 0, fgHighRebuild, 0, 0, 32, 16);
145
146
EntityPuyoScore *scoreP1 = PuyoGame->score2[0];
147
EntityPuyoScore *scoreP2 = PuyoGame->score2[1];
148
149
PuyoBean->comboChainCount[0] = 0;
150
PuyoBean->disableBeanLink[0] = false;
151
scoreP1->flashing = false;
152
153
PuyoBean->comboChainCount[1] = 0;
154
PuyoBean->disableBeanLink[1] = false;
155
scoreP2->flashing = false;
156
157
for (int32 i = 0; i < 0x100; ++i) PuyoBean->playfield[i] = NULL;
158
159
foreach_all(PuyoMatch, match)
160
{
161
match->score = 0;
162
match->comboScore = 0;
163
match->comboCount = 0;
164
match->comboBeanCount = 0;
165
match->comboBonusTable = PuyoMatch->comboBonus;
166
match->concurrentBonus = 0;
167
match->beanBonus = 0;
168
match->timer = false;
169
match->junkDropCount = 0;
170
match->junkBeanCount = 0;
171
172
PuyoGame->score1[0]->score = match->score;
173
}
174
175
foreach_all(CollapsingPlatform, platform) { platform->stoodPos.x = 0; }
176
}
177
178
void PuyoGame_CheckMatchFinish(void)
179
{
180
RSDK_THIS(PuyoGame);
181
182
EntityPuyoScore *scoreP1 = PuyoGame->score2[0];
183
EntityPuyoScore *scoreP2 = PuyoGame->score2[1];
184
185
int32 score = MAX(scoreP1->score, scoreP2->score);
186
187
if (score >= 2) {
188
self->matchWinner = scoreP1->score <= scoreP2->score;
189
self->finishedMatch = true;
190
PuyoGame->indicators[self->matchWinner]->state = PuyoIndicator_ShowWinner;
191
PuyoGame->indicators[self->matchWinner ^ 1]->state = PuyoIndicator_ShowLoser;
192
}
193
}
194
195
void PuyoGame_State_Init(void)
196
{
197
RSDK_THIS(PuyoGame);
198
199
self->state = PuyoGame_State_Wait;
200
}
201
202
void PuyoGame_State_Wait(void)
203
{
204
// Gaming(?)
205
}
206
207
void PuyoGame_State_SelectingLevel(void)
208
{
209
RSDK_THIS(PuyoGame);
210
211
EntityMenuParam *param = MenuParam_GetParam();
212
213
EntityPuyoLevelSelect *levelSelP1 = PuyoGame->levelSel[0];
214
EntityPuyoLevelSelect *levelSelP2 = PuyoGame->levelSel[1];
215
216
levelSelP1->canSelectLevels = true;
217
if (param->puyoSelection == PUYO_SELECTION_VS_CPU || param->puyoSelection == PUYO_SELECTION_NONE)
218
levelSelP2->ready = true;
219
220
levelSelP2->canSelectLevels = true;
221
222
if (levelSelP1->ready && levelSelP2->ready) {
223
levelSelP1->canSelectLevels = false;
224
levelSelP2->canSelectLevels = false;
225
self->selectedLevels[0] = levelSelP1->optionID;
226
self->selectedLevels[1] = levelSelP2->optionID;
227
self->state = PuyoGame_State_SetupRound;
228
}
229
}
230
231
void PuyoGame_State_SetupRound(void)
232
{
233
RSDK_THIS(PuyoGame);
234
235
if (self->timer >= 60) {
236
self->timer = 0;
237
self->state = PuyoGame_State_SetupEntities;
238
}
239
else {
240
if (!self->timer) {
241
PuyoGame_SetupGameState();
242
foreach_all(PuyoIndicator, indicator) { indicator->state = PuyoIndicator_ShowReady; }
243
int32 key = (int32)time(NULL);
244
int32 matchKey = RSDK.RandSeeded(0, 512, &key);
245
246
foreach_all(PuyoMatch, match)
247
{
248
RSDK.SetSpriteAnimation(-1, 0, &match->beanLAnimator, true, 0);
249
RSDK.SetSpriteAnimation(-1, 0, &match->beanRAnimator, true, 0);
250
match->active = ACTIVE_NORMAL;
251
match->matchKey = matchKey;
252
match->selectedLevel = self->selectedLevels[match->playerID];
253
PuyoMatch_SetupNextBeans(match);
254
}
255
}
256
257
++self->timer;
258
}
259
}
260
261
void PuyoGame_State_SetupEntities(void)
262
{
263
RSDK_THIS(PuyoGame);
264
265
EntityMenuParam *param = MenuParam_GetParam();
266
267
self->determinedLoser = false;
268
self->roundWinner = 0;
269
270
int32 matchID = 0;
271
foreach_all(PuyoMatch, match)
272
{
273
match->timer = true;
274
match->active = ACTIVE_NORMAL;
275
match->state = PuyoMatch_State_HandleMatch;
276
277
if (match->playerID) {
278
if (param->puyoSelection == PUYO_SELECTION_VS_CPU || param->puyoSelection == PUYO_SELECTION_NONE) {
279
match->stateInput = PuyoAI_Input_AI;
280
PuyoAI->lastBeanY[match->playerID] = PUYO_PLAYFIELD_H;
281
PuyoAI->desiredColumn[match->playerID] = 0;
282
PuyoAI->desiredRotation[match->playerID] = 0;
283
PuyoAI->isAI[match->playerID] = true;
284
PuyoAI->controlInterval[match->playerID] = PuyoAI->controlIntervals[self->selectedLevels[0]];
285
PuyoAI->controlChance[match->playerID] = PuyoAI->controlChances[self->selectedLevels[0]];
286
}
287
}
288
289
PuyoGame->managers[matchID++] = match;
290
}
291
292
int32 indicatorID = 0;
293
foreach_all(PuyoIndicator, indicator)
294
{
295
indicator->state = StateMachine_None;
296
PuyoGame->indicators[indicatorID++] = indicator;
297
}
298
299
int32 platformID = 0;
300
foreach_all(CollapsingPlatform, platform) { PuyoGame->platforms[platformID++] = platform; }
301
302
self->state = PuyoGame_State_HandleRound;
303
PuyoGame_State_HandleRound();
304
}
305
306
void PuyoGame_State_HandleRound(void)
307
{
308
for (int32 p = 0; p < 2; ++p) {
309
EntityPuyoMatch *match = PuyoGame->managers[p];
310
311
PuyoGame->score1[p]->score = match->score;
312
if (match->state == PuyoMatch_State_Lose)
313
PuyoGame_SetLoser(p);
314
}
315
}
316
317
void PuyoGame_State_ShowRoundResults(void)
318
{
319
RSDK_THIS(PuyoGame);
320
EntityMenuParam *param = MenuParam_GetParam();
321
322
if (self->timer >= 60) {
323
int32 count = param->puyoSelection >= PUYO_SELECTION_VS_2P ? 2 : 1;
324
bool32 buttonPressed = false;
325
326
RSDKControllerState *controller = &ControllerInfo[CONT_P1];
327
for (int32 i = 0; i < count; ++i) {
328
buttonPressed |= controller[i].keyA.down || controller[i].keyB.down || controller[i].keyC.down || controller[i].keyX.down
329
|| controller[i].keyY.down || controller[i].keyZ.down;
330
}
331
332
if (buttonPressed) {
333
PuyoGame_DestroyPuyoBeans();
334
self->timer = 0;
335
self->state = PuyoGame_State_SetupRound;
336
}
337
}
338
else {
339
self->timer++;
340
}
341
}
342
343
void PuyoGame_State_ShowMatchResults(void)
344
{
345
RSDK_THIS(PuyoGame);
346
347
EntityMenuParam *param = MenuParam_GetParam();
348
349
if (self->timer >= 60) {
350
int32 count = param->puyoSelection >= PUYO_SELECTION_VS_2P ? 2 : 1;
351
bool32 buttonPressed = false;
352
353
RSDKControllerState *controller = &ControllerInfo[CONT_P1];
354
for (int32 i = 0; i < count; ++i) {
355
buttonPressed |= controller[i].keyA.down || controller[i].keyB.down || controller[i].keyC.down || controller[i].keyX.down
356
|| controller[i].keyY.down || controller[i].keyZ.down;
357
}
358
359
if (buttonPressed) {
360
EntityFXFade *fxFade = PuyoGame->fxFade;
361
fxFade->timer = 0;
362
fxFade->speedIn = 16;
363
fxFade->drawGroup = 15;
364
fxFade->state = FXFade_State_FadeOut;
365
self->state = PuyoGame_State_FadeToMenu;
366
}
367
}
368
else {
369
self->timer++;
370
}
371
}
372
373
void PuyoGame_State_FadeToMenu(void)
374
{
375
RSDK_THIS(PuyoGame);
376
377
EntityCompetitionSession *session = CompetitionSession_GetSession();
378
EntityMenuParam *param = MenuParam_GetParam();
379
380
EntityFXFade *fxFade = PuyoGame->fxFade;
381
if (fxFade->timer == 512) {
382
if (param->puyoSelection == PUYO_SELECTION_TIE_BREAKER)
383
session->wins[self->matchWinner]++;
384
385
destroyEntity(self);
386
387
RSDK.SetScene("Presentation", "Menu");
388
RSDK.LoadScene();
389
}
390
}
391
392
#if GAME_INCLUDE_EDITOR
393
void PuyoGame_EditorDraw(void)
394
{
395
RSDK_THIS(PuyoGame);
396
397
RSDK.SetSpriteAnimation(PuyoGame->aniFrames, 24, &self->animator, false, 0);
398
RSDK.DrawSprite(&self->animator, NULL, false);
399
}
400
401
void PuyoGame_EditorLoad(void) { PuyoGame->aniFrames = RSDK.LoadSpriteAnimation("Puyo/PuyoBeans.bin", SCOPE_STAGE); }
402
#endif
403
404
void PuyoGame_Serialize(void) {}
405
406