feat: Enhance intro splash screen with retail warning and dynamic slide management

Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
2026-03-20 12:18:34 +01:00
parent b23c02f716
commit 436f498778
5 changed files with 197 additions and 20 deletions
@@ -420,7 +420,7 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
final art = WolfClassicMenuArt(engine.data);
if (engine.menuManager.activeMenu == WolfMenuScreen.introSplash) {
_drawIntroSplash(engine, art);
_drawIntroSplash(engine, art, menuTypography);
return;
}
@@ -708,10 +708,16 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
}
}
void _drawIntroSplash(WolfEngine engine, WolfClassicMenuArt art) {
final image = engine.menuManager.isIntroPg13Slide
? art.mappedPic(WolfMenuPic.pg13)
: art.mappedPic(WolfMenuPic.title);
void _drawIntroSplash(
WolfEngine engine,
WolfClassicMenuArt art,
_AsciiMenuTypography menuTypography,
) {
final image = switch (engine.menuManager.currentIntroSlide) {
WolfIntroSlide.retailWarning => null,
WolfIntroSlide.pg13 => art.mappedPic(WolfMenuPic.pg13),
WolfIntroSlide.title => art.mappedPic(WolfMenuPic.title),
};
int splashBg = _rgbToPaletteColor(engine.menuManager.introBackgroundRgb);
if (engine.menuManager.isIntroPg13Slide &&
@@ -726,6 +732,10 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
_fillRect(0, 0, width, height, activeTheme.solid, splashBg);
}
if (engine.menuManager.isIntroRetailWarningSlide) {
_drawRetailWarningIntro(splashBg, menuTypography);
}
if (image != null) {
final int x = engine.menuManager.isIntroPg13Slide
? (320 - image.width).clamp(0, 319)
@@ -742,6 +752,58 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
);
}
void _drawRetailWarningIntro(
int backgroundColor,
_AsciiMenuTypography menuTypography,
) {
final int black = ColorPalette.vga32Bit[0];
final int yellow = ColorPalette.vga32Bit[14];
final int white = ColorPalette.vga32Bit[15];
final int lineColor = ColorPalette.vga32Bit[4];
_fillRect320(0, 0, 320, 22, black);
_drawMenuTextCentered(
'Attention',
6,
yellow,
scale: menuTypography.headingScale,
);
_fillRect320(0, 23, 320, 1, lineColor);
if (menuTypography.usesCompactRows) {
final int textLeft = _menuX320ToColumn(40);
final int textRight = _menuX320ToColumn(280);
final int textWidth = math.max(1, textRight - textLeft);
void writeCenteredLine(int y200, String text) {
final String clipped = _clipWithEllipsis(text, textWidth);
final int centeredLeft =
textLeft + math.max(0, ((textWidth - clipped.length) ~/ 2));
_writeLeftClipped(
_menuY200ToRow(y200),
clipped,
white,
backgroundColor,
clipped.length,
centeredLeft,
);
}
writeCenteredLine(62, 'THIS GAME IS NOT SHAREWARE.');
writeCenteredLine(74, 'PLEASE DO NOT DISTRIBUTE IT.');
writeCenteredLine(86, 'THANKS.');
writeCenteredLine(112, 'ID SOFTWARE');
} else {
_drawMenuText('This game is NOT shareware.', 40, 56, white, scale: 1);
_drawMenuText('Please do not distribute it.', 40, 68, white, scale: 1);
_drawMenuText('Thanks.', 40, 80, white, scale: 1);
_drawMenuTextCentered('Id Software', 106, white, scale: 1);
}
_fillRect320(0, 196, 320, 4, backgroundColor);
}
int _dominantPaletteIndex(VgaImage image) {
final List<int> histogram = List<int>.filled(256, 0);
for (final int colorIndex in image.pixels) {
@@ -767,6 +829,18 @@ class AsciiRenderer extends CliRendererBackend<dynamic> {
}
final int threshold = (alpha * 3).round().clamp(1, 3);
if (_usesTerminalLayout) {
for (int y = 0; y < _terminalPixelHeight; y++) {
for (int x = 0; x < _terminalSceneWidth; x++) {
if (((x + y) % 3) < threshold) {
_scenePixels[y][x] = fadeColor;
}
}
}
return;
}
for (int y = 0; y < _screen.length; y++) {
final row = _screen[y];
for (int x = 0; x < row.length; x++) {
@@ -561,9 +561,11 @@ class SixelRenderer extends CliRendererBackend<String> {
}
void _drawIntroSplash(WolfEngine engine, WolfClassicMenuArt art) {
final image = engine.menuManager.isIntroPg13Slide
? art.mappedPic(WolfMenuPic.pg13)
: art.mappedPic(WolfMenuPic.title);
final image = switch (engine.menuManager.currentIntroSlide) {
WolfIntroSlide.retailWarning => null,
WolfIntroSlide.pg13 => art.mappedPic(WolfMenuPic.pg13),
WolfIntroSlide.title => art.mappedPic(WolfMenuPic.title),
};
int splashBg = _rgbToPaletteIndex(engine.menuManager.introBackgroundRgb);
if (engine.menuManager.isIntroPg13Slide &&
@@ -576,6 +578,10 @@ class SixelRenderer extends CliRendererBackend<String> {
_screen[i] = splashBg;
}
if (engine.menuManager.isIntroRetailWarningSlide) {
_drawRetailWarningIntro(splashBg);
}
if (image != null) {
final int x = engine.menuManager.isIntroPg13Slide
? (320 - image.width).clamp(0, 319)
@@ -592,6 +598,24 @@ class SixelRenderer extends CliRendererBackend<String> {
);
}
void _drawRetailWarningIntro(int backgroundColor) {
const int black = 0;
const int yellow = 14;
const int white = 15;
const int lineColor = 4;
_fillRect320(0, 0, 320, 22, black);
_drawMenuTextCentered('Attention', 6, yellow, scale: 2);
_fillRect320(0, 23, 320, 1, lineColor);
_drawMenuText('This game is NOT shareware.', 40, 56, white, scale: 1);
_drawMenuText('Please do not distribute it.', 40, 68, white, scale: 1);
_drawMenuText('Thanks.', 40, 80, white, scale: 1);
_drawMenuTextCentered('Id Software', 106, white, scale: 1);
_fillRect320(0, 196, 320, 4, backgroundColor);
}
int _dominantPaletteIndex(VgaImage image) {
final List<int> histogram = List<int>.filled(256, 0);
for (final int colorIndex in image.pixels) {
@@ -209,9 +209,11 @@ class SoftwareRenderer extends RendererBackend<FrameBuffer> {
}
void _drawIntroSplash(WolfEngine engine, WolfClassicMenuArt art) {
final image = engine.menuManager.isIntroPg13Slide
? art.mappedPic(WolfMenuPic.pg13)
: art.mappedPic(WolfMenuPic.title);
final image = switch (engine.menuManager.currentIntroSlide) {
WolfIntroSlide.retailWarning => null,
WolfIntroSlide.pg13 => art.mappedPic(WolfMenuPic.pg13),
WolfIntroSlide.title => art.mappedPic(WolfMenuPic.title),
};
int splashBgColor = _rgbToFrameColor(engine.menuManager.introBackgroundRgb);
int? matteIndex;
@@ -227,6 +229,10 @@ class SoftwareRenderer extends RendererBackend<FrameBuffer> {
_buffer.pixels[i] = splashBgColor;
}
if (engine.menuManager.isIntroRetailWarningSlide) {
_drawRetailWarningIntro(splashBgColor);
}
if (image != null) {
final int x = engine.menuManager.isIntroPg13Slide
? (320 - image.width).clamp(0, 319)
@@ -247,6 +253,36 @@ class SoftwareRenderer extends RendererBackend<FrameBuffer> {
);
}
void _drawRetailWarningIntro(int backgroundColor) {
final int black = ColorPalette.vga32Bit[0];
final int yellow = ColorPalette.vga32Bit[14];
final int white = ColorPalette.vga32Bit[15];
final int lineColor = ColorPalette.vga32Bit[4];
_fillCanonicalRect(0, 0, 320, 22, black);
_drawCanonicalMenuTextCentered('Attention', 6, yellow, scale: 2);
_fillCanonicalRect(0, 23, 320, 1, lineColor);
_drawCanonicalMenuText(
'This game is NOT shareware.',
40,
56,
white,
scale: 1,
);
_drawCanonicalMenuText(
'Please do not distribute it.',
40,
68,
white,
scale: 1,
);
_drawCanonicalMenuText('Thanks.', 40, 80, white, scale: 1);
_drawCanonicalMenuTextCentered('Id Software', 106, white, scale: 1);
_fillCanonicalRect(0, 196, 320, 4, backgroundColor);
}
int _dominantPaletteIndex(VgaImage image) {
final List<int> histogram = List<int>.filled(256, 0);
for (final int colorIndex in image.pixels) {