Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rubberduckycooly
GitHub Repository: rubberduckycooly/Sonic-1-2-2013-Decompilation
Path: blob/main/RSDKv4/String.cpp
817 views
1
#include "RetroEngine.hpp"
2
3
ushort *strPressStart = NULL;
4
ushort *strTouchToStart = NULL;
5
ushort *strStartGame = NULL;
6
ushort *strTimeAttack = NULL;
7
ushort *strAchievements = NULL;
8
ushort *strLeaderboards = NULL;
9
ushort *strHelpAndOptions = NULL;
10
ushort *strSoundTest = NULL;
11
ushort *str2PlayerVS = NULL;
12
ushort *strSaveSelect = NULL;
13
ushort *strPlayerSelect = NULL;
14
ushort *strNoSave = NULL;
15
ushort *strNewGame = NULL;
16
ushort *strDelete = NULL;
17
ushort *strDeleteMessage = NULL;
18
ushort *strYes = NULL;
19
ushort *strNo = NULL;
20
ushort *strSonic = NULL;
21
ushort *strTails = NULL;
22
ushort *strKnuckles = NULL;
23
ushort *strPause = NULL;
24
ushort *strContinue = NULL;
25
ushort *strRestart = NULL;
26
ushort *strExit = NULL;
27
ushort *strDevMenu = NULL;
28
ushort *strRestartMessage = NULL;
29
ushort *strExitMessage = NULL;
30
ushort *strNSRestartMessage = NULL;
31
ushort *strNSExitMessage = NULL;
32
ushort *strExitGame = NULL;
33
ushort *strNetworkMessage = NULL;
34
ushort *strStageList[16];
35
ushort *strSaveStageList[32];
36
ushort *strNewBestTime = NULL;
37
ushort *strRecords = NULL;
38
ushort *strNextAct = NULL;
39
ushort *strPlay = NULL;
40
ushort *strTotalTime = NULL;
41
ushort *strInstructions = NULL;
42
ushort *strSettings = NULL;
43
ushort *strStaffCredits = NULL;
44
ushort *strAbout = NULL;
45
ushort *strMusic = NULL;
46
ushort *strSoundFX = NULL;
47
ushort *strSpindash = NULL;
48
ushort *strBoxArt = NULL;
49
ushort *strControls = NULL;
50
ushort *strOn = NULL;
51
ushort *strOff = NULL;
52
ushort *strCustomizeDPad = NULL;
53
ushort *strDPadSize = NULL;
54
ushort *strDPadOpacity = NULL;
55
ushort *strHelpText1 = NULL;
56
ushort *strHelpText2 = NULL;
57
ushort *strHelpText3 = NULL;
58
ushort *strHelpText4 = NULL;
59
ushort *strHelpText5 = NULL;
60
ushort *strVersionName = NULL;
61
ushort *strPrivacy = NULL;
62
ushort *strTerms = NULL;
63
64
int stageStrCount = 0;
65
66
ushort stringStorage[STRSTORAGE_SIZE * STRING_SIZE];
67
int stringStorePos = 0;
68
69
int creditsListSize = 0;
70
ushort *strCreditsList[CREDITS_LIST_COUNT];
71
byte creditsType[CREDITS_LIST_COUNT];
72
float creditsAdvanceY[CREDITS_LIST_COUNT];
73
74
#include <string.h>
75
76
int FindStringToken(const char *string, const char *token, char stopID)
77
{
78
int tokenCharID = 0;
79
bool tokenMatch = true;
80
int stringCharID = 0;
81
int foundTokenID = 0;
82
83
while (string[stringCharID]) {
84
tokenCharID = 0;
85
tokenMatch = true;
86
while (token[tokenCharID]) {
87
if (!string[tokenCharID + stringCharID])
88
return -1;
89
90
if (string[tokenCharID + stringCharID] != token[tokenCharID])
91
tokenMatch = false;
92
93
++tokenCharID;
94
}
95
if (tokenMatch && ++foundTokenID == stopID)
96
return stringCharID;
97
98
++stringCharID;
99
}
100
return -1;
101
}
102
103
int FindLastStringToken(const char *string, const char *token)
104
{
105
int tokenCharID = 0;
106
bool tokenMatch = true;
107
int stringCharID = 0;
108
int foundTokenID = 0;
109
int lastResult = -1;
110
111
while (string[stringCharID]) {
112
tokenCharID = 0;
113
tokenMatch = true;
114
while (token[tokenCharID]) {
115
if (!string[tokenCharID + stringCharID])
116
return lastResult;
117
118
if (string[tokenCharID + stringCharID] != token[tokenCharID])
119
tokenMatch = false;
120
121
++tokenCharID;
122
}
123
if (tokenMatch)
124
lastResult = stringCharID;
125
126
++stringCharID;
127
}
128
return lastResult;
129
}
130
131
int FindStringTokenUnicode(const ushort *string, const ushort *token, char stopID)
132
{
133
int tokenCharID = 0;
134
bool tokenMatch = true;
135
int stringCharID = 0;
136
int foundTokenID = 0;
137
138
while (string[stringCharID]) {
139
tokenCharID = 0;
140
tokenMatch = true;
141
while (token[tokenCharID]) {
142
if (!string[tokenCharID + stringCharID])
143
return -1;
144
145
if (string[tokenCharID + stringCharID] != token[tokenCharID])
146
tokenMatch = false;
147
148
++tokenCharID;
149
}
150
if (tokenMatch && ++foundTokenID == stopID)
151
return stringCharID;
152
153
++stringCharID;
154
}
155
return -1;
156
}
157
158
void ConvertIntegerToString(char *text, int value) { sprintf(text, "%d", value); }
159
160
void GenerateMD5FromString(const char *string, int len, uint *hash0, uint *hash1, uint *hash2, uint *hash3)
161
{
162
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
163
164
static const uint K[64] = {
165
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
166
0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
167
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
168
0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
169
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
170
0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
171
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
172
0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
173
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
174
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
175
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
176
177
static const uint S[64] = {
178
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
179
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
180
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
181
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
182
183
static byte hashStream[0x400];
184
185
*hash0 = 0x67452301;
186
*hash1 = 0xefcdab89;
187
*hash2 = 0x98badcfe;
188
*hash3 = 0x10325476;
189
memset(hashStream, 0, 0x400);
190
191
uint length_bits = len * 8;
192
int padded_length = length_bits + 1;
193
while (padded_length % 512 != 448) {
194
padded_length++;
195
}
196
197
memcpy(hashStream, string, len);
198
199
padded_length /= 8;
200
// Padding (only 0x80 is needed since memset(0) has been called on hashStream)
201
hashStream[len] = 0x80;
202
// Write length in little endian order
203
for (int p = 0; p < 4; ++p) hashStream[padded_length + p] = (length_bits >> (8 * p));
204
205
// Process blocks
206
for (int block = 0; block < padded_length; block += 64) {
207
uint A = *hash0;
208
uint B = *hash1;
209
uint C = *hash2;
210
uint D = *hash3;
211
for (int i = 0; i < 64; ++i) {
212
uint res, idx;
213
if (i < 0x10) {
214
res = (B & C) | ((~B) & D);
215
idx = i;
216
} else if (i < 0x20) {
217
res = (D & B) | ((~D) & C);
218
idx = ((5 * i) + 1) % 16;
219
} else if (i < 0x30) {
220
res = B ^ C ^ D;
221
idx = ((3 * i) + 5) % 16;
222
} else {
223
res = C ^ (B | (~D));
224
idx = (7 * i) % 16;
225
}
226
uint streamVal = 0;
227
// Convert to little endian
228
for (int p = 0; p < 4; ++p) streamVal |= (hashStream[block + (idx * 4) + p] & 0xFF) << (8 * p);
229
uint temp = D;
230
D = C;
231
C = B;
232
B = B + ROTATE_LEFT((A + res + K[i] + streamVal), S[i]);
233
A = temp;
234
}
235
*hash0 += A;
236
*hash1 += B;
237
*hash2 += C;
238
*hash3 += D;
239
}
240
}
241
242
void InitLocalizedStrings()
243
{
244
memset(stringStorage, 0, STRING_SIZE * STRSTORAGE_SIZE * sizeof(ushort));
245
stringStorePos = 0;
246
247
char langStr[0x4];
248
switch (Engine.language) {
249
case RETRO_EN: StrCopy(langStr, "en"); break;
250
case RETRO_FR: StrCopy(langStr, "fr"); break;
251
case RETRO_IT: StrCopy(langStr, "it"); break;
252
case RETRO_DE: StrCopy(langStr, "de"); break;
253
case RETRO_ES: StrCopy(langStr, "es"); break;
254
case RETRO_JP: StrCopy(langStr, "ja"); break;
255
case RETRO_PT: StrCopy(langStr, "pt"); break;
256
case RETRO_RU: StrCopy(langStr, "ru"); break;
257
case RETRO_KO: StrCopy(langStr, "ko"); break;
258
case RETRO_ZH: StrCopy(langStr, "zh"); break;
259
case RETRO_ZS: StrCopy(langStr, "zs"); break;
260
default: break;
261
}
262
strPressStart = ReadLocalizedString("PressStart", langStr, "Data/Game/StringList.txt");
263
strTouchToStart = ReadLocalizedString("TouchToStart", langStr, "Data/Game/StringList.txt");
264
strStartGame = ReadLocalizedString("StartGame", langStr, "Data/Game/StringList.txt");
265
strTimeAttack = ReadLocalizedString("TimeAttack", langStr, "Data/Game/StringList.txt");
266
strAchievements = ReadLocalizedString("Achievements", langStr, "Data/Game/StringList.txt");
267
strLeaderboards = ReadLocalizedString("Leaderboards", langStr, "Data/Game/StringList.txt");
268
strHelpAndOptions = ReadLocalizedString("HelpAndOptions", langStr, "Data/Game/StringList.txt");
269
270
// SoundTest & StageTest, both unused
271
strSoundTest = ReadLocalizedString("SoundTest", langStr, "Data/Game/StringList.txt");
272
// strStageTest = ReadLocalizedString("StageTest", langStr, "Data/Game/StringList.txt");
273
274
str2PlayerVS = ReadLocalizedString("TwoPlayerVS", langStr, "Data/Game/StringList.txt");
275
strSaveSelect = ReadLocalizedString("SaveSelect", langStr, "Data/Game/StringList.txt");
276
strPlayerSelect = ReadLocalizedString("PlayerSelect", langStr, "Data/Game/StringList.txt");
277
strNoSave = ReadLocalizedString("NoSave", langStr, "Data/Game/StringList.txt");
278
strNewGame = ReadLocalizedString("NewGame", langStr, "Data/Game/StringList.txt");
279
strDelete = ReadLocalizedString("Delete", langStr, "Data/Game/StringList.txt");
280
strDeleteMessage = ReadLocalizedString("DeleteSavedGame", langStr, "Data/Game/StringList.txt");
281
strYes = ReadLocalizedString("Yes", langStr, "Data/Game/StringList.txt");
282
strNo = ReadLocalizedString("No", langStr, "Data/Game/StringList.txt");
283
strSonic = ReadLocalizedString("Sonic", langStr, "Data/Game/StringList.txt");
284
strTails = ReadLocalizedString("Tails", langStr, "Data/Game/StringList.txt");
285
strKnuckles = ReadLocalizedString("Knuckles", langStr, "Data/Game/StringList.txt");
286
strPause = ReadLocalizedString("Pause", langStr, "Data/Game/StringList.txt");
287
strContinue = ReadLocalizedString("Continue", langStr, "Data/Game/StringList.txt");
288
strRestart = ReadLocalizedString("Restart", langStr, "Data/Game/StringList.txt");
289
strExit = ReadLocalizedString("Exit", langStr, "Data/Game/StringList.txt");
290
strDevMenu = ReadLocalizedString("DevMenu", "en", "Data/Game/StringList.txt");
291
strRestartMessage = ReadLocalizedString("RestartMessage", langStr, "Data/Game/StringList.txt");
292
strExitMessage = ReadLocalizedString("ExitMessage", langStr, "Data/Game/StringList.txt");
293
if (Engine.language == RETRO_JP) {
294
strNSRestartMessage = ReadLocalizedString("NSRestartMessage", "ja", "Data/Game/StringList.txt");
295
strNSExitMessage = ReadLocalizedString("NSExitMessage", "ja", "Data/Game/StringList.txt");
296
}
297
else {
298
strNSRestartMessage = ReadLocalizedString("RestartMessage", langStr, "Data/Game/StringList.txt");
299
strNSExitMessage = ReadLocalizedString("ExitMessage", langStr, "Data/Game/StringList.txt");
300
}
301
strExitGame = ReadLocalizedString("ExitGame", langStr, "Data/Game/StringList.txt");
302
strNetworkMessage = ReadLocalizedString("NetworkMessage", langStr, "Data/Game/StringList.txt");
303
for (int i = 0; i < 16; ++i) {
304
char buffer[0x10];
305
sprintf(buffer, "StageName%d", i + 1);
306
307
strStageList[i] = ReadLocalizedString(buffer, "en", "Data/Game/StringList.txt");
308
}
309
310
stageStrCount = 0;
311
for (int i = 0; i < 32; ++i) {
312
char buffer[0x20];
313
sprintf(buffer, "SaveStageName%d", i + 1);
314
315
strSaveStageList[i] = ReadLocalizedString(buffer, "en", "Data/Game/StringList.txt");
316
if (!strSaveStageList[i])
317
break;
318
stageStrCount++;
319
}
320
strNewBestTime = ReadLocalizedString("NewBestTime", langStr, "Data/Game/StringList.txt");
321
strRecords = ReadLocalizedString("Records", langStr, "Data/Game/StringList.txt");
322
strNextAct = ReadLocalizedString("NextAct", langStr, "Data/Game/StringList.txt");
323
strPlay = ReadLocalizedString("Play", langStr, "Data/Game/StringList.txt");
324
strTotalTime = ReadLocalizedString("TotalTime", langStr, "Data/Game/StringList.txt");
325
strInstructions = ReadLocalizedString("Instructions", langStr, "Data/Game/StringList.txt");
326
strSettings = ReadLocalizedString("Settings", langStr, "Data/Game/StringList.txt");
327
strStaffCredits = ReadLocalizedString("StaffCredits", langStr, "Data/Game/StringList.txt");
328
strAbout = ReadLocalizedString("About", langStr, "Data/Game/StringList.txt");
329
strMusic = ReadLocalizedString("Music", langStr, "Data/Game/StringList.txt");
330
strSoundFX = ReadLocalizedString("SoundFX", langStr, "Data/Game/StringList.txt");
331
strSpindash = ReadLocalizedString("SpinDash", langStr, "Data/Game/StringList.txt");
332
strBoxArt = ReadLocalizedString("BoxArt", langStr, "Data/Game/StringList.txt");
333
strControls = ReadLocalizedString("Controls", langStr, "Data/Game/StringList.txt");
334
strOn = ReadLocalizedString("On", langStr, "Data/Game/StringList.txt");
335
strOff = ReadLocalizedString("Off", langStr, "Data/Game/StringList.txt");
336
strCustomizeDPad = ReadLocalizedString("CustomizeDPad", langStr, "Data/Game/StringList.txt");
337
strDPadSize = ReadLocalizedString("DPadSize", langStr, "Data/Game/StringList.txt");
338
strDPadOpacity = ReadLocalizedString("DPadOpacity", langStr, "Data/Game/StringList.txt");
339
strHelpText1 = ReadLocalizedString("HelpText1", langStr, "Data/Game/StringList.txt");
340
strHelpText2 = ReadLocalizedString("HelpText2", langStr, "Data/Game/StringList.txt");
341
strHelpText3 = ReadLocalizedString("HelpText3", langStr, "Data/Game/StringList.txt");
342
strHelpText4 = ReadLocalizedString("HelpText4", langStr, "Data/Game/StringList.txt");
343
strHelpText5 = ReadLocalizedString("HelpText5", langStr, "Data/Game/StringList.txt");
344
strVersionName = ReadLocalizedString("Version", langStr, "Data/Game/StringList.txt");
345
strPrivacy = ReadLocalizedString("Privacy", langStr, "Data/Game/StringList.txt");
346
strTerms = ReadLocalizedString("Terms", langStr, "Data/Game/StringList.txt");
347
// strMoreGames = ReadLocalizedString("MoreGames", langStr, "Data/Game/StringList.txt");
348
349
// Video Filter options
350
// strVideoFilter = ReadLocalizedString("VideoFilter", langStr, "Data/Game/StringList.txt");
351
// strSharp = ReadLocalizedString("Sharp", langStr, "Data/Game/StringList.txt");
352
// strSmooth = ReadLocalizedString("Smooth", langStr, "Data/Game/StringList.txt");
353
// strNostalgic = ReadLocalizedString("Nostalgic", langStr, "Data/Game/StringList.txt");
354
355
// Login With Facebook
356
// strFBLogin = ReadLocalizedString("LoginWithFacebook", langStr, "Data/Game/StringList.txt");
357
358
// Unused Control Modes
359
// strControlMethod = ReadLocalizedString("ControlMethod", langStr, "Data/Game/StringList.txt");
360
// strSwipeAndTap = ReadLocalizedString("SwipeAndTap", langStr, "Data/Game/StringList.txt");
361
// strVirtualDPad = ReadLocalizedString("VirtualDPad", langStr, "Data/Game/StringList.txt");
362
363
ReadCreditsList("Data/Game/CreditsMobile.txt");
364
}
365
ushort *ReadLocalizedString(const char *stringName, const char *language, const char *filePath)
366
{
367
FileInfo info;
368
ushort strName[0x40];
369
ushort langName[0x8];
370
ushort lineBuffer[0x200];
371
372
memset(strName, 0, 0x40 * sizeof(ushort));
373
memset(langName, 0, 0x8 * sizeof(ushort));
374
memset(lineBuffer, 0, 0x200 * sizeof(ushort));
375
376
int strNamePos = 0;
377
while (stringName[strNamePos]) {
378
strName[strNamePos] = stringName[strNamePos];
379
strNamePos++;
380
}
381
strName[strNamePos++] = ':';
382
strName[strNamePos] = 0;
383
384
int langNamePos = 0;
385
for (langNamePos = 0; langNamePos < 4; ++langNamePos) {
386
if (!language[langNamePos])
387
break;
388
else
389
langName[langNamePos] = language[langNamePos];
390
}
391
392
langName[langNamePos++] = ':';
393
langName[langNamePos] = 0;
394
395
if (LoadFile(filePath, &info)) {
396
int readMode = 0;
397
ushort curChar = 0;
398
int charID = 0;
399
byte flag = 0;
400
while (!ReachedEndOfFile()) {
401
switch (readMode) {
402
case 0:
403
ReadStringLineUnicode(lineBuffer);
404
if (!FindStringTokenUnicode(lineBuffer, langName, 1)) {
405
int tPos = FindStringTokenUnicode(lineBuffer, strName, 1);
406
if (tPos == 3)
407
flag = true;
408
readMode = tPos == 3;
409
}
410
break;
411
case 1:
412
FileRead(fileBuffer, sizeof(ushort));
413
curChar = fileBuffer[0] + (fileBuffer[1] << 8);
414
if (curChar > '\n' && curChar != '\r') {
415
stringStorage[stringStorePos + charID++] = 0;
416
CloseFile();
417
418
int pos = stringStorePos;
419
stringStorePos += charID;
420
return &stringStorage[pos];
421
}
422
else if (curChar == '\t') {
423
if (flag) {
424
flag = true;
425
readMode = 2;
426
}
427
else {
428
readMode = 2;
429
stringStorage[stringStorePos + charID++] = '\n';
430
}
431
}
432
break;
433
case 2:
434
FileRead(fileBuffer, sizeof(ushort));
435
curChar = fileBuffer[0] + (fileBuffer[1] << 8);
436
if (curChar != '\t') {
437
stringStorage[stringStorePos + charID++] = curChar;
438
if (curChar == '\r' || curChar == '\n') {
439
flag = false;
440
readMode = 1;
441
}
442
}
443
break;
444
}
445
}
446
CloseFile();
447
}
448
449
PrintLog("Failed to load string... (%s, %s)", language, stringName);
450
return NULL;
451
}
452
453
void ReadCreditsList(const char *filePath)
454
{
455
FileInfo info;
456
if (LoadFile(filePath, &info)) {
457
creditsListSize = 0;
458
459
char dest[0x100];
460
float advance = 24.0;
461
if (!ReachedEndOfFile()) {
462
while (creditsListSize < CREDITS_LIST_COUNT) {
463
ReadCreditsLine(dest);
464
465
if (dest[0] != '[' || dest[2] != ']') {
466
advance += 24.0;
467
}
468
else {
469
int strPos = 0;
470
char curChar = dest[strPos + 3];
471
while (curChar) {
472
stringStorage[stringStorePos + strPos] = curChar;
473
strPos++;
474
curChar = dest[strPos + 3];
475
}
476
stringStorage[stringStorePos + strPos++] = 0;
477
478
switch (dest[1]) {
479
default:
480
case '0': creditsType[creditsListSize] = 0; break;
481
case '1': creditsType[creditsListSize] = 1; break;
482
case '2': creditsType[creditsListSize] = 2; break;
483
case '3': creditsType[creditsListSize] = 3; break;
484
}
485
486
creditsAdvanceY[creditsListSize] = advance;
487
488
strCreditsList[creditsListSize++] = &stringStorage[stringStorePos];
489
stringStorePos += strPos;
490
advance = 24.0;
491
}
492
493
if (ReachedEndOfFile())
494
break;
495
}
496
}
497
498
CloseFile();
499
}
500
}
501
502