Skip to content

Commit 31e3bfb

Browse files
committed
Port ESRB splash creation to DS Classic Menu
1 parent d9a0087 commit 31e3bfb

File tree

18 files changed

+2305
-2
lines changed

18 files changed

+2305
-2
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#include <nds.h>
2+
#include <stdio.h>
3+
4+
#include "common/twlmenusettings.h"
5+
#include "common/systemdetails.h"
6+
#include "common/flashcard.h"
7+
#include "common/tonccpy.h"
8+
#include "common/inifile.h"
9+
#include "common/logging.h"
10+
#include "graphics/fontHandler.h"
11+
#include "graphics/graphics.h"
12+
#include "common/lodepng.h"
13+
#include "ndsheaderbanner.h"
14+
#include "language.h"
15+
16+
#include "dsGameInfoMap.h"
17+
18+
extern u16 bmpImageBuffer[256*192];
19+
20+
void createEsrbSplash(void) {
21+
if (!ms().esrbRatingScreen || isHomebrew[ms().secondaryDevice] || (gameTid[ms().secondaryDevice][3] != 'E' && gameTid[ms().secondaryDevice][3] != 'O' && gameTid[ms().secondaryDevice][3] != 'T' && gameTid[ms().secondaryDevice][3] != 'W')) {
22+
remove(sys().isRunFromSD() ? "sd:/_nds/nds-bootstrap/esrb.bin" : "fat:/_nds/nds-bootstrap/esrb.bin");
23+
return;
24+
}
25+
26+
char gameTid3[4] = {0};
27+
for (int i = 0; i < 3; i++) {
28+
gameTid3[i] = gameTid[ms().secondaryDevice][i];
29+
}
30+
31+
CIniFile esrbInfo("nitro:/ESRB.ini");
32+
std::string rating = esrbInfo.GetString(gameTid3, "Rating", "");
33+
if (rating == "") {
34+
remove(sys().isRunFromSD() ? "sd:/_nds/nds-bootstrap/esrb.bin" : "fat:/_nds/nds-bootstrap/esrb.bin");
35+
return;
36+
}
37+
38+
std::string descriptors = esrbInfo.GetString(gameTid3, "Descriptors en", "");
39+
const bool onlineNotice = esrbInfo.GetInt(gameTid3, "Online", 0);
40+
41+
bool sideways = false;
42+
if ((rating == "E" || rating == "EC" || rating == "RP") && descriptors == "") {
43+
// Search for games starting sideways
44+
// TODO: If the list gets large enough, switch to bsearch().
45+
for (unsigned int i = 0; i < sizeof(sidewaysGameList)/sizeof(sidewaysGameList[0]); i++) {
46+
if (memcmp(gameTid[ms().secondaryDevice], sidewaysGameList[i], 3) == 0) {
47+
// Found match
48+
sideways = true;
49+
break;
50+
}
51+
}
52+
}
53+
54+
char esrbImagePath[64];
55+
if (rating == "E" && descriptors == "") {
56+
sprintf(esrbImagePath, "nitro:/graphics/ESRB/E-%s.png", sideways ? "side" : "nodesc");
57+
} else if (rating == "EC" || rating == "RP") {
58+
sprintf(esrbImagePath, "nitro:/graphics/ESRB/%s%s.png", rating.c_str(), sideways ? "-side" : "");
59+
} else {
60+
sprintf(esrbImagePath, "nitro:/graphics/ESRB/%s.png", rating.c_str());
61+
}
62+
logPrint("ESRB Rating: %s\n", rating.c_str());
63+
logPrint("ESRB Descriptors: %s\n", descriptors.c_str());
64+
65+
DC_FlushAll();
66+
67+
std::vector<unsigned char> image;
68+
uint imageWidth, imageHeight;
69+
lodepng::decode(image, imageWidth, imageHeight, esrbImagePath);
70+
if (imageWidth > 256 || imageHeight > 192) return;
71+
72+
for (uint i=0;i<image.size()/4;i++) {
73+
bmpImageBuffer[i] = image[i*4]>>3 | (image[(i*4)+1]>>3)<<5 | (image[(i*4)+2]>>3)<<10 | BIT(15);
74+
}
75+
76+
if (descriptors != "") {
77+
int descriptorLines = 1;
78+
int descriptorYpos = 80;
79+
char descriptorList[6][32] = {{0}};
80+
81+
int currentChar = 0;
82+
for (int i = 0; i < 256; i++) {
83+
if (descriptors[i] == 0) {
84+
break;
85+
} else if (descriptors[i] == ',') {
86+
descriptorLines++;
87+
currentChar = 0;
88+
if (descriptors[i+1] == ' ') {
89+
i++;
90+
}
91+
} else {
92+
descriptorList[descriptorLines-1][currentChar] = descriptors[i];
93+
currentChar++;
94+
}
95+
}
96+
97+
bool dsFont = false;
98+
for (int i = 0; i < descriptorLines; i++) {
99+
dsFont = strlen(descriptorList[i]) > 21;
100+
if (dsFont) {
101+
descriptorYpos += 2;
102+
break;
103+
}
104+
}
105+
106+
esrbDescFontInit(dsFont);
107+
108+
descriptorYpos -= ((descriptorLines > 4) ? 6 : 8)*(descriptorLines-1);
109+
110+
clearText();
111+
for (int i = 0; i < descriptorLines; i++) {
112+
printSmall(false, 100, descriptorYpos, descriptorList[i]);
113+
descriptorYpos += (descriptorLines > 4) ? 12 : 16;
114+
}
115+
updateTextImg(bmpImageBuffer, false);
116+
clearText();
117+
118+
esrbDescFontDeinit();
119+
}
120+
121+
mkdir(sys().isRunFromSD() ? "sd:/_nds/nds-bootstrap" : "fat:/_nds/nds-bootstrap", 0777);
122+
123+
FILE *file = fopen(sys().isRunFromSD() ? "sd:/_nds/nds-bootstrap/esrb.bin" : "fat:/_nds/nds-bootstrap/esrb.bin", "wb");
124+
if (onlineNotice) {
125+
toncset32(bmpImageBuffer, 0x494C4E4F, 1); // 'ONLI'
126+
}
127+
fwrite(bmpImageBuffer, sizeof(u16), 256*192, file);
128+
fclose(file);
129+
}

quickmenu/arm9/source/esrbSplash.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef ESRBSPLASH_H
2+
#define ESRBSPLASH_H
3+
4+
void createEsrbSplash(void);
5+
6+
#endif //ESRBSPLASH_H

quickmenu/arm9/source/graphics/fontHandler.cpp

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ extern u16* colorTable;
1717

1818
FontGraphic *smallFont;
1919
FontGraphic *tinyFont;
20+
FontGraphic *esrbDescFont;
2021

2122
std::list<TextEntry> topText, bottomText;
2223

@@ -61,9 +62,9 @@ void fontInit() {
6162
if (ms().dsClassicCustomFont) {
6263
std::string fontPath = std::string(sys().isRunFromSD() ? "sd:" : "fat:") + "/_nds/TWiLightMenu/extras/fonts/" + ms().font;
6364
std::string defaultPath = std::string(sys().isRunFromSD() ? "sd:" : "fat:") + "/_nds/TWiLightMenu/extras/fonts/Default";
64-
smallFont = new FontGraphic({fontPath + "/small-dsi.nftr", fontPath + "/small.nftr", defaultPath + "/small-dsi.nftr", "nitro:/graphics/font/small.nftr"}, useTileCache);
65+
smallFont = new FontGraphic({fontPath + "/small-dsi.nftr", fontPath + "/small.nftr", defaultPath + "/small-dsi.nftr", "nitro:/graphics/font/ds.nftr"}, useTileCache);
6566
} else {
66-
smallFont = new FontGraphic({"nitro:/graphics/font/small.nftr"}, false);
67+
smallFont = new FontGraphic({"nitro:/graphics/font/ds.nftr"}, false);
6768
palette[3] = 0x94A5;
6869
}
6970
tinyFont = new FontGraphic({"nitro:/graphics/font/tiny.nftr"}, false);
@@ -80,6 +81,15 @@ void fontInit() {
8081
logPrint("Font inited\n");
8182
}
8283

84+
void esrbDescFontInit(bool dsFont) {
85+
esrbDescFont = new FontGraphic({dsFont ? "nitro:/graphics/font/ds.nftr" : "nitro:/graphics/font/small.nftr"}, false);
86+
}
87+
88+
void esrbDescFontDeinit() {
89+
if (esrbDescFont)
90+
delete esrbDescFont;
91+
}
92+
8393
static std::list<TextEntry> &getTextQueue(bool top) {
8494
return top ? topText : bottomText;
8595
}
@@ -123,6 +133,39 @@ void updateTopTextArea(int x, int y, int width, int height, u16 *restoreBuf) {
123133
}
124134
}
125135

136+
void updateTextImg(u16* img, bool top) {
137+
if (top) return;
138+
139+
// Clear before redrawing
140+
if (shouldClear[top]) {
141+
dmaFillWords(0, FontGraphic::textBuf[top], 256 * 192);
142+
shouldClear[top] = false;
143+
}
144+
145+
// Draw text
146+
auto &text = getTextQueue(top);
147+
for (auto it = text.begin(); it != text.end(); ++it) {
148+
if (esrbDescFont)
149+
esrbDescFont->print(it->x, it->y, top, it->message, it->align, it->palette);
150+
}
151+
text.clear();
152+
153+
u16 palette[] = {
154+
0x0000,
155+
0x6718,
156+
0x4A32,
157+
0x1064,
158+
};
159+
160+
// Copy buffer to the image
161+
for (int i = 0; i < 256 * 192; i++) {
162+
if (FontGraphic::textBuf[top][i] != 0) {
163+
//img[i] = top ? BG_PALETTE[FontGraphic::textBuf[true][i]] : BG_PALETTE_SUB[FontGraphic::textBuf[false][i]];
164+
img[i] = palette[FontGraphic::textBuf[top][i]];
165+
}
166+
}
167+
}
168+
126169
void clearText(bool top) {
127170
shouldClear[top] = true;
128171
}

quickmenu/arm9/source/graphics/fontHandler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
#include "FontGraphic.h"
44

55
void fontInit();
6+
void esrbDescFontInit(bool dsFont);
7+
void esrbDescFontDeinit();
68

79
void updateText(bool top);
810
void updateTopTextArea(int x, int y, int width, int height, u16 *restoreBuf = NULL);
11+
void updateTextImg(u16* img, bool top);
912
void clearText(bool top);
1013
void clearText();
1114

quickmenu/arm9/source/main.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "gbaswitch.h"
4343
#include "perGameSettings.h"
4444
#include "errorScreen.h"
45+
#include "esrbSplash.h"
4546

4647
#include "iconTitle.h"
4748
#include "graphics/fontHandler.h"
@@ -2189,6 +2190,8 @@ int dsClassicMenu(void) {
21892190

21902191
// Launch DSiWare .nds via Unlaunch
21912192
if (isDSiWare[ms().secondaryDevice]) {
2193+
remove(sys().isRunFromSD() ? "sd:/_nds/nds-bootstrap/esrb.bin" : "fat:/_nds/nds-bootstrap/esrb.bin");
2194+
21922195
std::string typeToReplace = filename[ms().secondaryDevice].substr(filename[ms().secondaryDevice].rfind('.'));
21932196

21942197
char *name = argarray.at(0);
@@ -2696,6 +2699,12 @@ int dsClassicMenu(void) {
26962699
ms().previousUsedDevice = ms().secondaryDevice;
26972700
ms().saveSettings();
26982701

2702+
createEsrbSplash();
2703+
2704+
if (sdFound() && ms().homebrewBootstrap && (access("sd:/moonshl2/logbuf.txt", F_OK) == 0)) {
2705+
remove("sd:/moonshl2/logbuf.txt"); // Delete file for Moonshell 2 to boot properly
2706+
}
2707+
26992708
const bool useNightly = (perGameSettings_bootstrapFile == -1 ? ms().bootstrapFile : perGameSettings_bootstrapFile);
27002709

27012710
char ndsToBoot[256];

0 commit comments

Comments
 (0)