Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-1-2-2013-Decompilation
Path: blob/main/RSDKv4/NativeObjects/MenuControl.cpp
817 views
1
#include "RetroEngine.hpp"
2
3
bool usePhysicalControls = false;
4
5
void MenuControl_Create(void *objPtr)
6
{
7
RSDK_THIS(MenuControl);
8
SetMusicTrack("MainMenu.ogg", 0, true, 106596);
9
CREATE_ENTITY(MenuBG);
10
11
self->buttons[self->buttonCount] = (NativeEntity_AchievementsButton *)CREATE_ENTITY(StartGameButton);
12
self->buttonFlags[self->buttonCount] = BUTTON_STARTGAME;
13
self->buttonCount++;
14
15
self->buttons[self->buttonCount] = (NativeEntity_AchievementsButton *)CREATE_ENTITY(TimeAttackButton);
16
self->buttonFlags[self->buttonCount] = BUTTON_TIMEATTACK;
17
self->buttonCount++;
18
19
#if RETRO_USE_MOD_LOADER
20
int vsID = GetSceneID(STAGELIST_PRESENTATION, "2P VS");
21
if (vsID != -1) {
22
#else
23
if (Engine.gameType == GAME_SONIC2) {
24
#endif
25
self->buttons[self->buttonCount] = (NativeEntity_AchievementsButton *)CREATE_ENTITY(MultiplayerButton);
26
self->buttonFlags[self->buttonCount] = BUTTON_MULTIPLAYER;
27
self->buttonCount++;
28
}
29
30
if (Engine.onlineActive) {
31
self->buttons[self->buttonCount] = CREATE_ENTITY(AchievementsButton);
32
self->buttonFlags[self->buttonCount] = BUTTON_ACHIEVEMENTS;
33
self->buttonCount++;
34
35
self->buttons[self->buttonCount] = (NativeEntity_AchievementsButton *)CREATE_ENTITY(LeaderboardsButton);
36
self->buttonFlags[self->buttonCount] = BUTTON_LEADERBOARDS;
37
self->buttonCount++;
38
}
39
40
self->buttons[self->buttonCount] = (NativeEntity_AchievementsButton *)CREATE_ENTITY(OptionsButton);
41
self->buttonFlags[self->buttonCount] = BUTTON_OPTIONS;
42
self->buttonCount++;
43
44
self->backButton = CREATE_ENTITY(BackButton);
45
self->backButton->visible = false;
46
self->backButton->x = 240.0;
47
self->backButton->y = -160.0;
48
self->backButton->z = 0.0;
49
50
self->segaIDButton = CREATE_ENTITY(SegaIDButton);
51
self->segaIDButton->y = -92.0;
52
self->segaIDButton->texX = 0.0;
53
self->segaIDButton->x = SCREEN_CENTERX_F - 32.0;
54
55
self->buttonIncline = 0.15707964f; // this but less precise ---> M_PI / 2
56
self->buttonSpacing = 0.078539819f; // this but less precise ---> M_PI / 4
57
self->menuEndPos = (self->buttonCount * self->buttonIncline) * 0.5;
58
59
float offset = 0.0;
60
for (int b = 0; b < self->buttonCount; ++b) {
61
NativeEntity_AchievementsButton *button = self->buttons[b];
62
float sin = sinf(self->buttonMovePos + offset);
63
float cos = cosf(self->buttonMovePos + offset);
64
button->x = 1024.0 * sin;
65
button->z = (cos * -512.0) + 672.0;
66
button->y = (128.0 * sin) + 16.0;
67
button->visible = button->z <= 288.0;
68
offset += self->buttonIncline;
69
}
70
71
PlayMusic(0, 0);
72
if (Engine.gameDeviceType == RETRO_STANDARD)
73
usePhysicalControls = true;
74
BackupNativeObjects();
75
}
76
void MenuControl_Main(void *objPtr)
77
{
78
RSDK_THIS(MenuControl);
79
NativeEntity_SegaIDButton *segaIDButton = self->segaIDButton;
80
NativeEntity_BackButton *backButton = self->backButton;
81
82
switch (self->state) {
83
case MENUCONTROL_STATE_MAIN: {
84
CheckKeyDown(&keyDown);
85
CheckKeyPress(&keyPress);
86
87
if (segaIDButton->alpha < 0x100 && Engine.language != RETRO_JP && !(Engine.language == RETRO_ZH || Engine.language == RETRO_ZS)
88
&& Engine.gameDeviceType == RETRO_MOBILE)
89
segaIDButton->alpha += 8;
90
91
if (!usePhysicalControls) {
92
switch (self->stateInput) {
93
case MENUCONTROL_STATEINPUT_CHECKTOUCH: {
94
if (touches > 0) {
95
if (!keyDown.left && !keyDown.right) {
96
segaIDButton->state = SEGAIDBUTTON_STATE_IDLE;
97
if (CheckTouchRect(0.0, 16.0, 56.0, 56.0) >= 0) {
98
BackupNativeObjects();
99
self->releaseTouchX = touchXF[0];
100
self->stateInput = MENUCONTROL_STATEINPUT_HANDLERELEASE;
101
self->buttonID = ceilf(self->buttonMovePos / -self->buttonSpacing);
102
self->buttons[self->buttonID]->g = 0xC0;
103
}
104
else {
105
if (CheckTouchRect(self->segaIDButton->x, self->segaIDButton->y, 20.0, 20.0) >= 0 && segaIDButton->alpha > 64) {
106
segaIDButton->state = SEGAIDBUTTON_STATE_PRESSED;
107
}
108
else {
109
self->stateInput = MENUCONTROL_STATEINPUT_HANDLEDRAG;
110
self->lastDragTouchDistance = 0.0;
111
self->dragTouchX = touchXF[0];
112
self->lastButtonMovePos = self->buttonMovePos;
113
}
114
}
115
}
116
else {
117
segaIDButton->state = SEGAIDBUTTON_STATE_IDLE;
118
usePhysicalControls = true;
119
self->buttonID = ceilf(self->buttonMovePos / -self->buttonSpacing);
120
self->buttons[self->buttonID]->g = 0xC0;
121
}
122
}
123
else if (segaIDButton->state == SEGAIDBUTTON_STATE_PRESSED) {
124
segaIDButton->state = SEGAIDBUTTON_STATE_IDLE;
125
PlaySfxByName("Menu Select", false);
126
ShowPromoPopup(0, "MoreGames");
127
}
128
else if (keyDown.left || keyDown.right) {
129
segaIDButton->state = SEGAIDBUTTON_STATE_IDLE;
130
usePhysicalControls = true;
131
self->buttonID = ceilf(self->buttonMovePos / -self->buttonSpacing);
132
self->buttons[self->buttonID]->g = 0xC0;
133
}
134
break;
135
}
136
137
case MENUCONTROL_STATEINPUT_HANDLEDRAG: {
138
if (touches <= 0) {
139
self->stateInput = MENUCONTROL_STATEINPUT_HANDLEMOVEMENT;
140
}
141
else {
142
self->autoButtonMoveVelocity = 0.0;
143
self->dragTouchDistance = (self->dragTouchX - touchXF[0]) * -0.0007;
144
if (abs(self->lastDragTouchDistance) > 0.0) {
145
self->autoButtonMoveVelocity = self->dragTouchDistance - self->lastDragTouchDistance;
146
self->buttonMovePos += self->autoButtonMoveVelocity;
147
}
148
self->lastDragTouchDistance = self->dragTouchDistance;
149
}
150
break;
151
}
152
153
case MENUCONTROL_STATEINPUT_HANDLEMOVEMENT: {
154
self->autoButtonMoveVelocity /= (1.125 * (60.0 * Engine.deltaTime));
155
self->buttonMovePos += self->autoButtonMoveVelocity;
156
float max = -(self->menuEndPos - self->buttonSpacing);
157
158
if (max - 0.05 > self->buttonMovePos || self->buttonMovePos > 0.05)
159
self->autoButtonMoveVelocity = 0.0;
160
161
if (abs(self->autoButtonMoveVelocity) < 0.0025) {
162
if (self->buttonMovePos == self->lastButtonMovePos && self->dragTouchX < 0.0) {
163
self->buttonMovePos += 0.00001;
164
}
165
166
if (self->buttonMovePos <= self->lastButtonMovePos) {
167
self->targetButtonMovePos = floorf(self->buttonMovePos / self->buttonSpacing) * self->buttonSpacing;
168
169
if (self->targetButtonMovePos > self->lastButtonMovePos - self->buttonSpacing)
170
self->targetButtonMovePos = self->lastButtonMovePos - self->buttonSpacing;
171
172
if (self->targetButtonMovePos < max)
173
self->targetButtonMovePos = max;
174
}
175
else {
176
self->targetButtonMovePos = ceilf(self->buttonMovePos / self->buttonSpacing) * self->buttonSpacing;
177
178
if (self->targetButtonMovePos < self->buttonSpacing + self->lastButtonMovePos)
179
self->targetButtonMovePos = self->buttonSpacing + self->lastButtonMovePos;
180
181
if (self->targetButtonMovePos > 0.0)
182
self->targetButtonMovePos = 0.0;
183
}
184
185
self->stateInput = MENUCONTROL_STATEINPUT_MOVE;
186
self->buttonMovePos += (self->targetButtonMovePos - self->buttonMovePos) / ((60.0 * Engine.deltaTime) * 8.0);
187
}
188
break;
189
}
190
191
case MENUCONTROL_STATEINPUT_MOVE: {
192
if (touches > 0) {
193
self->stateInput = MENUCONTROL_STATEINPUT_HANDLEDRAG;
194
self->lastDragTouchDistance = 0.0;
195
self->dragTouchX = touchXF[0];
196
}
197
else {
198
self->buttonMovePos += (self->targetButtonMovePos - self->buttonMovePos) / ((60.0 * Engine.deltaTime) * 6.0);
199
if (abs(self->targetButtonMovePos - self->buttonMovePos) < 0.00025) {
200
self->buttonMovePos = self->targetButtonMovePos;
201
self->stateInput = MENUCONTROL_STATEINPUT_CHECKTOUCH;
202
}
203
}
204
break;
205
}
206
207
case MENUCONTROL_STATEINPUT_HANDLERELEASE: {
208
if (touches > 0) {
209
if (CheckTouchRect(0.0, 16.0, 56.0, 56.0) < 0) {
210
self->buttons[self->buttonID]->g = 0xFF;
211
}
212
else {
213
self->buttons[self->buttonID]->g = 0xC0;
214
if (abs(self->releaseTouchX - touchXF[0]) > 8.0f) {
215
self->stateInput = MENUCONTROL_STATEINPUT_HANDLEDRAG;
216
self->dragTouchX = self->buttonID;
217
self->lastDragTouchDistance = 0.0;
218
self->lastButtonMovePos = self->buttonMovePos;
219
self->buttons[self->buttonID]->g = 0xFF;
220
}
221
}
222
}
223
else {
224
if (self->buttons[self->buttonID]->g == 0xC0) {
225
self->buttons[self->buttonID]->labelPtr->state = TEXTLABEL_STATE_BLINK_FAST;
226
self->timer = 0.0;
227
self->state = MENUCONTROL_STATE_ACTION;
228
PlaySfxByName("Menu Select", false);
229
}
230
self->buttons[self->buttonID]->g = 0xFF;
231
self->stateInput = MENUCONTROL_STATEINPUT_CHECKTOUCH;
232
}
233
break;
234
}
235
236
default: break;
237
}
238
}
239
else {
240
if (self->stateInput == MENUCONTROL_STATEINPUT_HANDLEDRAG) {
241
self->buttonMovePos +=
242
(((self->buttonMoveVelocity + self->targetButtonMovePos) - self->buttonMovePos) / ((60.0 * Engine.deltaTime) * 8.0));
243
244
if (abs(self->targetButtonMovePos - self->buttonMovePos) < 0.001) {
245
self->buttonMovePos = self->targetButtonMovePos;
246
self->stateInput = MENUCONTROL_STATEINPUT_CHECKTOUCH;
247
}
248
}
249
else {
250
if (touches <= 0) {
251
if (keyPress.right && self->buttonMovePos > -(self->menuEndPos - self->buttonSpacing)) {
252
self->stateInput = MENUCONTROL_STATEINPUT_HANDLEDRAG;
253
self->targetButtonMovePos -= self->buttonSpacing;
254
PlaySfxByName("Menu Move", false);
255
self->buttonMoveVelocity = -0.01;
256
self->buttonID++;
257
if (self->buttonID >= self->buttonCount)
258
self->buttonID = self->buttonCount - 1;
259
}
260
else if (keyPress.left && self->buttonMovePos < 0.0) {
261
self->stateInput = MENUCONTROL_STATEINPUT_HANDLEDRAG;
262
self->targetButtonMovePos += self->buttonSpacing;
263
PlaySfxByName("Menu Move", false);
264
self->buttonMoveVelocity = 0.01;
265
self->buttonID--;
266
if (self->buttonID > self->buttonCount)
267
self->buttonID = 0;
268
}
269
else if ((keyPress.start || keyPress.A) && !Engine.nativeMenuFadeIn) {
270
BackupNativeObjects();
271
self->buttons[self->buttonID]->labelPtr->state = TEXTLABEL_STATE_BLINK_FAST;
272
self->timer = 0.0;
273
self->state = MENUCONTROL_STATE_ACTION;
274
PlaySfxByName("Menu Select", false);
275
}
276
277
for (int i = 0; i < self->buttonCount; ++i) {
278
self->buttons[i]->g = 0xFF;
279
}
280
self->buttons[self->buttonID]->g = 0xC0;
281
}
282
else {
283
usePhysicalControls = false;
284
for (int i = 0; i < self->buttonCount; ++i) {
285
self->buttons[i]->g = 0xFF;
286
}
287
}
288
}
289
}
290
291
float offset = self->buttonMovePos;
292
for (int i = 0; i < self->buttonCount; ++i) {
293
NativeEntity_AchievementsButton *button = self->buttons[i];
294
button->x = 1024.0 * sinf(self->buttonMovePos + offset);
295
button->y = (sinf(self->buttonMovePos + offset) * 128.0) + 16.0;
296
button->z = (cosf(self->buttonMovePos + offset) * -512.0) + 672.0;
297
button->visible = button->z <= 288.0;
298
offset += self->buttonIncline;
299
}
300
301
if (!self->stateInput) {
302
if (self->dialogTimer) {
303
self->dialogTimer--;
304
}
305
else if (keyPress.B && !Engine.nativeMenuFadeIn) {
306
self->dialog = CREATE_ENTITY(DialogPanel);
307
SetStringToFont(self->dialog->text, strExitGame, FONT_TEXT);
308
self->state = MENUCONTROL_STATE_DIALOGWAIT;
309
PlaySfxByName("Resume", false);
310
}
311
}
312
break;
313
}
314
315
case MENUCONTROL_STATE_ACTION: {
316
self->timer += Engine.deltaTime;
317
if (self->timer > 0.5) {
318
self->timer = 0.0;
319
NativeEntity_AchievementsButton *button = self->buttons[self->buttonID];
320
switch (self->buttonFlags[self->buttonID]) {
321
case BUTTON_STARTGAME:
322
self->state = MENUCONTROL_STATE_ENTERSUBMENU;
323
self->autoButtonMoveVelocity = 0.0;
324
button->g = 0xFF;
325
self->buttons[self->buttonID]->labelPtr->state = TEXTLABEL_STATE_NONE;
326
self->backButton->visible = true;
327
SetGlobalVariableByName("options.vsMode", false);
328
CREATE_ENTITY(SaveSelect);
329
break;
330
331
case BUTTON_TIMEATTACK:
332
self->state = MENUCONTROL_STATE_ENTERSUBMENU;
333
self->autoButtonMoveVelocity = 0.0;
334
button->g = 0xFF;
335
button->labelPtr->state = TEXTLABEL_STATE_NONE;
336
self->backButton->visible = true;
337
CREATE_ENTITY(TimeAttack);
338
break;
339
340
case BUTTON_MULTIPLAYER:
341
self->state = MENUCONTROL_STATE_MAIN;
342
button->labelPtr->state = TEXTLABEL_STATE_IDLE;
343
SetGlobalVariableByName("options.saveSlot", 0);
344
SetGlobalVariableByName("options.gameMode", 0);
345
SetGlobalVariableByName("options.vsMode", 0);
346
SetGlobalVariableByName("player.lives", 3);
347
SetGlobalVariableByName("player.score", 0);
348
SetGlobalVariableByName("player.scoreBonus", 50000);
349
SetGlobalVariableByName("specialStage.listPos", 0);
350
SetGlobalVariableByName("specialStage.emeralds", 0);
351
SetGlobalVariableByName("specialStage.nextZone", 0);
352
SetGlobalVariableByName("timeAttack.result", 0);
353
SetGlobalVariableByName("lampPostID", 0);
354
SetGlobalVariableByName("starPostID", 0);
355
if (Engine.onlineActive) {
356
#if !RETRO_USE_ORIGINAL_CODE
357
BackupNativeObjects();
358
int id = GetSceneID(STAGELIST_PRESENTATION, "2P VS");
359
if (id == -1)
360
id = 3;
361
InitStartingStage(STAGELIST_PRESENTATION, id, 0);
362
#else
363
InitStartingStage(STAGELIST_PRESENTATION, 3, 0);
364
#endif
365
CREATE_ENTITY(FadeScreen);
366
}
367
else {
368
self->dialog = CREATE_ENTITY(DialogPanel);
369
self->dialog->buttonCount = DLGTYPE_OK;
370
SetStringToFont(self->dialog->text, strNetworkMessage, FONT_TEXT);
371
self->state = MENUCONTROL_STATE_DIALOGWAIT;
372
}
373
break;
374
375
case BUTTON_ACHIEVEMENTS:
376
if (Engine.onlineActive && false) {
377
ShowAchievementsScreen();
378
}
379
else {
380
self->state = MENUCONTROL_STATE_MAIN;
381
self->dialog = CREATE_ENTITY(DialogPanel);
382
self->dialog->buttonCount = DLGTYPE_OK;
383
SetStringToFont(self->dialog->text, strNetworkMessage, FONT_TEXT);
384
self->state = MENUCONTROL_STATE_DIALOGWAIT;
385
}
386
button->labelPtr->state = TEXTLABEL_STATE_IDLE;
387
break;
388
389
case BUTTON_LEADERBOARDS:
390
self->state = MENUCONTROL_STATE_MAIN;
391
if (Engine.onlineActive && false) {
392
ShowLeaderboardsScreen();
393
}
394
else {
395
self->dialog = CREATE_ENTITY(DialogPanel);
396
self->dialog->buttonCount = DLGTYPE_OK;
397
SetStringToFont(self->dialog->text, strNetworkMessage, FONT_TEXT);
398
self->state = MENUCONTROL_STATE_DIALOGWAIT;
399
}
400
button->labelPtr->state = TEXTLABEL_STATE_IDLE;
401
break;
402
403
case BUTTON_OPTIONS:
404
self->state = MENUCONTROL_STATE_ENTERSUBMENU;
405
self->autoButtonMoveVelocity = 0.0;
406
button->g = 0xFF;
407
button->labelPtr->state = TEXTLABEL_STATE_NONE;
408
self->backButton->visible = true;
409
CREATE_ENTITY(OptionsMenu);
410
break;
411
412
default:
413
self->state = MENUCONTROL_STATE_MAIN;
414
button->labelPtr->state = TEXTLABEL_STATE_IDLE;
415
break;
416
}
417
}
418
break;
419
}
420
421
case MENUCONTROL_STATE_NONE: break;
422
423
case MENUCONTROL_STATE_ENTERSUBMENU: {
424
if (segaIDButton->alpha > 0)
425
segaIDButton->alpha -= 8;
426
427
self->autoButtonMoveVelocity -= 0.125 * (60.0 * Engine.deltaTime);
428
429
for (int i = 0; i < self->buttonCount; ++i) {
430
if (self->buttonID != i) {
431
if (self->buttonID != i)
432
self->buttons[i]->z += ((60.0 * Engine.deltaTime) * self->autoButtonMoveVelocity);
433
}
434
}
435
436
self->timer += Engine.deltaTime;
437
self->autoButtonMoveVelocity -= 0.125 * (60.0 * Engine.deltaTime);
438
439
if (self->timer > 0.5) {
440
NativeEntity_AchievementsButton *button = self->buttons[self->buttonID];
441
float div = (60.0 * Engine.deltaTime) * 16.0;
442
443
button->x += ((112.0 - button->x) / div);
444
button->y += ((64.0 - button->y) / div);
445
button->z += ((200.0 - button->z) / div);
446
self->backButton->z += ((320.0 - self->backButton->z) / div);
447
}
448
449
if (self->timer > 1.5) {
450
self->timer = 0.0;
451
self->state = MENUCONTROL_STATE_SUBMENU;
452
453
for (int i = 0; i < self->buttonCount; ++i) {
454
if (self->buttonID != i) {
455
if (self->buttonID != i)
456
self->buttons[i]->visible = false;
457
}
458
}
459
}
460
break;
461
}
462
463
case MENUCONTROL_STATE_SUBMENU: {
464
CheckKeyDown(&keyDown);
465
CheckKeyPress(&keyPress);
466
if (touches <= 0) {
467
if (self->backButton->g == 0xC0) {
468
PlaySfxByName("Menu Back", false);
469
self->backButton->g = 0xFF;
470
self->state = MENUCONTROL_STATE_EXITSUBMENU;
471
}
472
}
473
else {
474
backButton = self->backButton;
475
if (CheckTouchRect(122.0, -80.0, 32.0, 32.0) < 0)
476
backButton->g = 0xFF;
477
else
478
backButton->g = 0xC0;
479
}
480
if (keyPress.B) {
481
PlaySfxByName("Menu Back", false);
482
self->backButton->g = 0xFF;
483
self->state = MENUCONTROL_STATE_EXITSUBMENU;
484
}
485
break;
486
}
487
488
case MENUCONTROL_STATE_EXITSUBMENU: {
489
self->backButton->z = ((0.0 - self->backButton->z) / (16.0 * (60.0 * Engine.deltaTime))) + self->backButton->z;
490
self->timer += Engine.deltaTime;
491
if (self->timer > 0.25) {
492
float offset = self->buttonMovePos;
493
float div = (60.0 * Engine.deltaTime) * 8.0;
494
495
for (int i = 0; i < self->buttonCount; ++i) {
496
if (self->buttonID != i) {
497
NativeEntity_AchievementsButton *button = self->buttons[i];
498
button->z = ((((cosf(offset + self->buttonMovePos) * -512.0) + 672.0) - button->z) / div) + button->z;
499
button->visible = true;
500
}
501
offset += self->buttonIncline;
502
}
503
504
NativeEntity_AchievementsButton *curButton = self->buttons[self->buttonID];
505
curButton->labelPtr->state = TEXTLABEL_STATE_IDLE;
506
curButton->x += ((0.0 - curButton->x) / div);
507
curButton->y += ((16.0 - curButton->y) / div);
508
curButton->z += ((160.0 - curButton->z) / div);
509
}
510
511
if (self->timer > 1.0) {
512
self->timer = 0.0;
513
self->autoButtonMoveVelocity = 0.0;
514
self->state = MENUCONTROL_STATE_MAIN;
515
}
516
break;
517
}
518
519
case MENUCONTROL_STATE_DIALOGWAIT: {
520
if (self->dialog->selection == DLG_NO || self->dialog->selection == DLG_OK) {
521
self->state = MENUCONTROL_STATE_MAIN;
522
self->dialogTimer = 50;
523
}
524
else if (self->dialog->selection == DLG_YES) {
525
ExitGame();
526
self->dialogTimer = 50;
527
self->state = MENUCONTROL_STATE_MAIN;
528
}
529
break;
530
}
531
532
default: break;
533
}
534
}
535
536