Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-Mania-Decompilation
Path: blob/master/SonicMania/Objects/Global/Competition.c
338 views
1
// ---------------------------------------------------------------------
2
// RSDK Project: Sonic Mania
3
// Object Description: Competition Object
4
// Object Author: Christian Whitehead/Simon Thomley/Hunter Bridges
5
// Decompiled by: Rubberduckycooly & RMGRich
6
// ---------------------------------------------------------------------
7
8
#include "Game.h"
9
10
ObjectCompetition *Competition;
11
12
void Competition_Update(void)
13
{
14
RSDK_THIS(Competition);
15
16
StateMachine_Run(self->state);
17
}
18
19
void Competition_LateUpdate(void) {}
20
21
void Competition_StaticUpdate(void) {}
22
23
void Competition_Draw(void)
24
{
25
RSDK_THIS(Competition);
26
27
#if MANIA_USE_PLUS
28
if (RSDK_GET_ENTITY(SceneInfo->currentScreenID, Player)->classID == Player->classID) {
29
#endif
30
if (!self->playerFinished[SceneInfo->currentScreenID]) {
31
Vector2 drawPos;
32
drawPos.x = TO_FIXED(ScreenInfo[SceneInfo->currentScreenID].center.x - 4);
33
drawPos.y = TO_FIXED(26);
34
self->animator.frameID = self->timer / 10;
35
RSDK.DrawSprite(&self->animator, &drawPos, true);
36
37
drawPos.x += TO_FIXED(8);
38
self->animator.frameID = self->timer % 10;
39
RSDK.DrawSprite(&self->animator, &drawPos, true);
40
}
41
#if MANIA_USE_PLUS
42
}
43
#endif
44
}
45
46
void Competition_Create(void *data)
47
{
48
RSDK_THIS(Competition);
49
50
if (!SceneInfo->inEditor) {
51
self->isPermanent = true;
52
self->active = ACTIVE_NORMAL;
53
self->visible = true;
54
self->drawGroup = Zone->hudDrawGroup - 1;
55
56
self->seconds = SceneInfo->seconds;
57
if (SceneInfo->minutes == 9) {
58
self->timer = 0;
59
60
if (60 - SceneInfo->seconds > 0)
61
self->timer = 60 - SceneInfo->seconds;
62
63
if (!SceneInfo->milliseconds)
64
SceneInfo->milliseconds = 1;
65
}
66
else {
67
self->timer = 60;
68
}
69
70
self->state = Competition_State_Manager;
71
RSDK.SetSpriteAnimation(Competition->aniFrames, 1, &self->animator, true, 0);
72
}
73
}
74
75
void Competition_StageLoad(void)
76
{
77
Competition->sessionManager = NULL;
78
79
Competition->aniFrames = RSDK.LoadSpriteAnimation("Global/HUD.bin", SCOPE_STAGE);
80
}
81
82
void Competition_State_Manager(void)
83
{
84
RSDK_THIS(Competition);
85
86
#if MANIA_USE_PLUS
87
if (self->timer <= 0) {
88
Zone->gotTimeOver = true;
89
SceneInfo->timeEnabled = false;
90
for (int32 p = 0; p < Player->playerCount; ++p) {
91
EntityPlayer *player = RSDK_GET_ENTITY(p, Player);
92
if (player->classID == Player->classID && player->state == Player_State_Death)
93
player->visible = true;
94
}
95
self->state = StateMachine_None;
96
}
97
else {
98
if (self->seconds != SceneInfo->seconds) {
99
self->seconds = SceneInfo->seconds;
100
101
self->timer--;
102
if (self->timer == 12) {
103
Music_PlayJingle(TRACK_DROWNING);
104
}
105
else if (!self->timer) {
106
Zone->gotTimeOver = true;
107
SceneInfo->timeEnabled = false;
108
for (int32 p = 0; p < Player->playerCount; ++p) {
109
if (!self->playerFinished[p]) {
110
EntityPlayer *player = RSDK_GET_ENTITY(p, Player);
111
if (player->classID == Player->classID)
112
player->deathType = PLAYER_DEATH_DIE_USESFX;
113
}
114
}
115
}
116
}
117
}
118
#else
119
if (self->timer > 0) {
120
if (self->seconds != SceneInfo->seconds) {
121
self->seconds = SceneInfo->seconds;
122
123
self->timer--;
124
if (!self->timer) {
125
Zone->gotTimeOver = true;
126
for (int32 p = 0; p < Player->playerCount; ++p) {
127
if (!self->playerFinished[p]) {
128
EntityPlayer *player = RSDK_GET_ENTITY(p, Player);
129
player->deathType = PLAYER_DEATH_DIE_USESFX;
130
self->state = StateMachine_None;
131
}
132
}
133
}
134
}
135
}
136
#endif
137
}
138
139
#if MANIA_USE_PLUS
140
void Competition_ResetOptions(void)
141
{
142
EntityCompetitionSession *session = CompetitionSession_GetSession();
143
session->inMatch = false;
144
session->matchID = 0;
145
session->matchCount = 0;
146
session->stageIndex = 0;
147
148
for (int32 i = 0; i < COMPETITION_STAGE_COUNT; ++i) {
149
session->completedStages[i] = false;
150
session->matchWinner[i] = 0;
151
}
152
153
for (int32 p = 0; p < PLAYER_COUNT; ++p) {
154
session->finishState[p] = FINISHTYPE_NOTFINISHED;
155
session->playerID[p] = ID_NONE;
156
session->time[p].minutes = 0;
157
session->time[p].seconds = 0;
158
session->time[p].milliseconds = 0;
159
session->rings[p] = 0;
160
session->score[p] = 0;
161
session->items[p] = 0;
162
session->totalRings[p] = 0;
163
session->wins[p] = 0;
164
session->lives[p] = 0;
165
}
166
}
167
168
void Competition_ClearMatchData(void)
169
{
170
EntityCompetitionSession *session = CompetitionSession_GetSession();
171
172
session->matchWinner[session->matchID] = 0;
173
174
for (int32 p = 0; p < PLAYER_COUNT; ++p) {
175
session->finishState[p] = FINISHTYPE_NOTFINISHED;
176
session->time[p].minutes = 0;
177
session->time[p].seconds = 0;
178
session->time[p].milliseconds = 0;
179
session->rings[p] = 0;
180
session->score[p] = 0;
181
session->items[p] = 0;
182
session->totalRings[p] = 0;
183
}
184
}
185
186
void Competition_DeriveWinner(int32 playerID, uint8 finishType)
187
{
188
EntityCompetitionSession *session = CompetitionSession_GetSession();
189
session->finishState[playerID] = finishType;
190
191
if (finishType == FINISHTYPE_GAMEOVER) {
192
session->totalRings[playerID] = 0;
193
session->items[playerID] = 0;
194
session->rings[playerID] = 0;
195
session->score[playerID] = 0;
196
session->time[playerID].minutes = 9;
197
session->time[playerID].seconds = 59;
198
session->time[playerID].milliseconds = 59;
199
}
200
201
int32 deathCount = 0;
202
bool32 allPlayersFinished = true;
203
for (int32 p = 0; p < session->playerCount; ++p) {
204
if (!session->lives[p] || session->finishState[p] == FINISHTYPE_GAMEOVER)
205
++deathCount;
206
}
207
208
if (deathCount < session->playerCount - 1) {
209
for (int32 p = 0; p < session->playerCount; ++p) allPlayersFinished = allPlayersFinished && (!session->lives[p] || session->finishState[p]);
210
}
211
212
if (allPlayersFinished) {
213
if (!session->matchWinner[session->matchID]) {
214
uint32 winnerTime = 0xFFFFFFFF;
215
int32 winnerRings = 0;
216
int32 winnerScore = 0;
217
int32 winnerItems = 0;
218
int32 winnerTotalRings = 0;
219
220
uint32 times[PLAYER_COUNT];
221
for (int32 p = 0; p < session->playerCount; ++p) {
222
int32 mins = session->time[p].minutes;
223
int32 secs = session->time[p].seconds;
224
int32 ms = session->time[p].milliseconds;
225
uint32 time = ms + 100 * (secs + 60 * mins);
226
times[p] = time;
227
228
if (session->rings[p] > winnerRings)
229
winnerRings = session->rings[p];
230
231
if (session->totalRings[p] > winnerTotalRings)
232
winnerTotalRings = session->totalRings[p];
233
234
if (session->score[p] > winnerScore)
235
winnerScore = session->score[p];
236
237
if (session->items[p] > winnerItems)
238
winnerItems = session->items[p];
239
240
if (time < winnerTime)
241
winnerTime = time;
242
}
243
244
int32 scores[PLAYER_COUNT];
245
memset(scores, 0, PLAYER_COUNT * sizeof(int32));
246
247
int32 winner = 0;
248
for (int32 p = 0; p < session->playerCount; ++p) {
249
if (session->finishState[p] == FINISHTYPE_PASSEDSIGNPOST) {
250
int32 score = 0;
251
if (session->rings[p] == winnerRings)
252
score++;
253
254
if (session->totalRings[p] == winnerTotalRings)
255
++score;
256
257
if (session->score[p] == winnerScore)
258
++score;
259
260
if (times[p] == winnerTime)
261
++score;
262
263
if (session->items[p] == winnerItems)
264
++score;
265
266
LogHelpers_Print("player %d => score %d", p, score);
267
268
scores[p] = score;
269
if (score > winner)
270
winner = score;
271
}
272
}
273
274
for (int32 p = 0; p < session->playerCount; ++p) {
275
bool32 isWinner = session->lives[p] > 0 && session->finishState[p] != FINISHTYPE_GAMEOVER && scores[p] == winner;
276
if (isWinner) {
277
Competition_WinMatchFor(p);
278
}
279
}
280
}
281
}
282
}
283
284
void Competition_WinMatchFor(int32 playerID)
285
{
286
EntityCompetitionSession *session = CompetitionSession_GetSession();
287
288
++session->wins[playerID];
289
session->matchWinner[session->matchID] |= 1 << playerID;
290
}
291
#endif
292
293
#if GAME_INCLUDE_EDITOR
294
void Competition_EditorDraw(void) {}
295
296
void Competition_EditorLoad(void) {}
297
#endif
298
299
void Competition_Serialize(void) {}
300
301