From 4d28f7be23881fecae58d4873459a4ae93847db2 Mon Sep 17 00:00:00 2001 From: khbsd Date: Fri, 7 Nov 2025 22:11:17 +0000 Subject: [PATCH] feat: adds stevebeller's instant text and MandL27's faster text printing (#8063) --- include/config/general.h | 2 - include/config/text.h | 19 ++++ include/constants/global.h | 23 ++--- include/menu.h | 2 - include/text.h | 21 ++++- src/berry_crush.c | 17 +--- src/braille.c | 15 ++-- src/menu.c | 28 +----- src/text.c | 172 ++++++++++++++++++++++++++++--------- 9 files changed, 190 insertions(+), 109 deletions(-) create mode 100644 include/config/text.h diff --git a/include/config/general.h b/include/config/general.h index 5ce5c68040..68ac0ec462 100644 --- a/include/config/general.h +++ b/include/config/general.h @@ -74,8 +74,6 @@ // General settings #define EXPANSION_INTRO TRUE // If TRUE, a custom RHH intro will play after the vanilla copyright screen. #define HQ_RANDOM TRUE // If TRUE, replaces the default RNG with an implementation of SFC32 RNG. May break code that relies on RNG. -#define AUTO_SCROLL_TEXT FALSE // If TRUE, text will automatically scroll to the next line after NUM_FRAMES_AUTO_SCROLL_DELAY. Players can still press A_BUTTON or B_BUTTON to scroll on their own. -#define NUM_FRAMES_AUTO_SCROLL_DELAY 49 #define PHONEMES_SHARED FALSE // If TRUE, bard phonemes all reference the same sound (sound/direct_sound_samples/phonemes/shared.bin) to save ROM space. // Measurement system constants to be used for UNITS diff --git a/include/config/text.h b/include/config/text.h new file mode 100644 index 0000000000..17f7056eb6 --- /dev/null +++ b/include/config/text.h @@ -0,0 +1,19 @@ +#ifndef GUARD_CONFIG_TEXT_H +#define GUARD_CONFIG_TEXT_H + +// Text settings: +#define AUTO_SCROLL_TEXT FALSE // If TRUE, text will automatically scroll to the next line after NUM_FRAMES_AUTO_SCROLL_DELAY. Players can still press A_BUTTON or B_BUTTON to scroll on their own. +#define NUM_FRAMES_AUTO_SCROLL_DELAY 49 + +// A note on the modifiers: they are roughly multiplicative, so having them set at 1 is vanilla speed. They also are used to calculate frame delays for the speed of the scroll effect and the animated down arrow, so to that end, they are capped at 31 to prevent the text printing from desyncing with A/B button inputs. +// From testing, a value of 18 to 20 is essentially equivalent to instant text. +#define TEXT_SPEED_SLOW_MODIFIER 1 // How fast the SLOW text speed option prints +#define TEXT_SPEED_MEDIUM_MODIFIER 1 // How fast the MID text speed option prints +#define TEXT_SPEED_FAST_MODIFIER 1 // How fast the FAST text speed option prints +#define TEXT_SPEED_INSTANT_MODIFIER 12 // Needed only for the animation delays +#define TEXT_SPEED_INSTANT TRUE // Renders all text as fast as it can, basically instant. Overrides FLAG_TEXT_SPEED_INSTANT and in-game player options menu setting. + +// Text speed flag: +#define FLAG_TEXT_SPEED_INSTANT 0 // Use this if you want to toggle instant text speed + +#endif // GUARD_CONFIG_TEXT_H diff --git a/include/constants/global.h b/include/constants/global.h index a783475f2e..0d2490b2b7 100644 --- a/include/constants/global.h +++ b/include/constants/global.h @@ -3,10 +3,10 @@ // You can use the ENABLED_ON_RELEASE and DISABLED_ON_RELEASE macros to // control whether a feature is enabled or disabled when making a release build. -// +// // For example, the overworld debug menu is enabled by default, but when using // `make release`, it will be automatically disabled. -// +// // #define DEBUG_OVERWORLD_MENU DISABLED_ON_RELEASE #ifdef RELEASE #define ENABLED_ON_RELEASE TRUE @@ -16,17 +16,17 @@ #define DISABLED_ON_RELEASE TRUE #endif -#include "config/general.h" -#include "config/battle.h" -#include "config/debug.h" -#include "config/item.h" -#include "config/caps.h" -#include "config/pokemon.h" -#include "config/overworld.h" -#include "config/dexnav.h" -#include "config/summary_screen.h" #include "config/ai.h" +#include "config/battle.h" +#include "config/caps.h" +#include "config/debug.h" +#include "config/dexnav.h" #include "config/follower_npc.h" +#include "config/general.h" +#include "config/item.h" +#include "config/overworld.h" +#include "config/pokemon.h" +#include "config/summary_screen.h" // Invalid Versions show as "----------" in Gen 4 and Gen 5's summary screen. // In Gens 6 and 7, invalid versions instead show "a distant land" in the summary screen. @@ -163,6 +163,7 @@ #define OPTIONS_TEXT_SPEED_SLOW 0 #define OPTIONS_TEXT_SPEED_MID 1 #define OPTIONS_TEXT_SPEED_FAST 2 +#define OPTIONS_TEXT_SPEED_INSTANT 3 #define OPTIONS_SOUND_MONO 0 #define OPTIONS_SOUND_STEREO 1 diff --git a/include/menu.h b/include/menu.h index 8f5b73ba41..6702552331 100644 --- a/include/menu.h +++ b/include/menu.h @@ -61,8 +61,6 @@ void PrintPlayerNameOnWindow(u8 windowId, const u8 *src, u16 x, u16 y); void ClearDialogWindowAndFrame(u8 windowId, bool8 copyToVram); void SetStandardWindowBorderStyle(u8 windowId, bool8 copyToVram); void DisplayYesNoMenuDefaultYes(void); -u32 GetPlayerTextSpeed(void); -u8 GetPlayerTextSpeedDelay(void); void Menu_LoadStdPalAt(u16 offset); void AddTextPrinterWithCallbackForMessage(bool8 canSpeedUp, void (*callback)(struct TextPrinterTemplate *, u16)); void BgDmaFill(u32 bg, u8 value, int offset, int size); diff --git a/include/text.h b/include/text.h index 040fe49f13..294bff94c7 100644 --- a/include/text.h +++ b/include/text.h @@ -1,8 +1,15 @@ #ifndef GUARD_TEXT_H #define GUARD_TEXT_H +#include "config/text.h" #include "constants/characters.h" +// This is to prevent the user from having a higher text speed modifier than the printing system can handle. +STATIC_ASSERT( TEXT_SPEED_SLOW_MODIFIER <= 31 + && TEXT_SPEED_MEDIUM_MODIFIER <= 31 + && TEXT_SPEED_FAST_MODIFIER <= 31 + && TEXT_SPEED_INSTANT_MODIFIER <= 31, TextSpeedModifiersCantGoPast31) + // Given as a text speed when all the text should be // loaded at once but not copied to vram yet. #define TEXT_SKIP_DRAW 0xFF @@ -59,9 +66,9 @@ struct TextPrinterSubStruct u8 fontId:4; // 0x14 bool8 hasPrintBeenSpedUp:1; u8 unk:3; - u8 downArrowDelay:5; - u8 downArrowYPosIdx:2; - bool8 hasFontIdBeenSet:1; + u16 utilityCounter:13; + u16 downArrowYPosIdx:2; + bool16 hasFontIdBeenSet:1; u8 autoScrollDelay; }; @@ -135,7 +142,6 @@ struct TextGlyph }; extern TextFlags gTextFlags; - extern u8 gDisableTextPrinters; extern struct TextGlyph gCurGlyph; @@ -178,4 +184,11 @@ u32 GetFontIdToFit(const u8 *string, u32 widestFontId, u32 letterSpacing, u32 wi u8 *PrependFontIdToFit(u8 *start, u8 *end, u32 fontId, u32 width); u8 *WrapFontIdToFit(u8 *start, u8 *end, u32 fontId, u32 width); +// player text speed +u32 GetPlayerTextSpeed(void); +u32 GetPlayerTextSpeedDelay(void); +u32 GetPlayerTextSpeedModifier(void); +u32 GetPlayerTextScrollSpeed(void); +bool32 IsPlayerTextSpeedInstant(void); + #endif // GUARD_TEXT_H diff --git a/src/berry_crush.c b/src/berry_crush.c index a571511ee2..e3927d8780 100644 --- a/src/berry_crush.c +++ b/src/berry_crush.c @@ -4,6 +4,7 @@ #include "berry_powder.h" #include "bg.h" #include "decompress.h" +#include "digit_obj_util.h" #include "dynamic_placeholder_text_util.h" #include "event_data.h" #include "gpu_regs.h" @@ -17,11 +18,10 @@ #include "malloc.h" #include "math_util.h" #include "menu.h" +#include "minigame_countdown.h" #include "overworld.h" #include "palette.h" -#include "minigame_countdown.h" #include "random.h" -#include "digit_obj_util.h" #include "save.h" #include "scanline_effect.h" #include "script.h" @@ -1157,18 +1157,7 @@ static void SetNamesAndTextSpeed(struct BerryCrushGame *game) game->players[i].name[PLAYER_NAME_LENGTH] = EOS; } - switch (gSaveBlock2Ptr->optionsTextSpeed) - { - case OPTIONS_TEXT_SPEED_SLOW: - game->textSpeed = 8; - break; - case OPTIONS_TEXT_SPEED_MID: - game->textSpeed = 4; - break; - case OPTIONS_TEXT_SPEED_FAST: - game->textSpeed = 1; - break; - } + game->textSpeed = GetPlayerTextSpeedDelay(); } static s32 ShowGameDisplay(void) diff --git a/src/braille.c b/src/braille.c index 91872b88a0..310384ba32 100644 --- a/src/braille.c +++ b/src/braille.c @@ -1,18 +1,12 @@ #include "global.h" #include "main.h" -#include "window.h" #include "text.h" #include "sound.h" +#include "window.h" // This file handles the braille font. // For printing braille messages, see ScrCmd_braillemessage -ALIGNED(4) -static const u8 sScrollDistances[] = { - [OPTIONS_TEXT_SPEED_SLOW] = 1, - [OPTIONS_TEXT_SPEED_MID] = 2, - [OPTIONS_TEXT_SPEED_FAST] = 4, -}; static const u16 sFont_Braille[] = INCBIN_U16("graphics/fonts/braille.fwjpnfont"); static void DecompressGlyph_Braille(u16); @@ -22,6 +16,7 @@ u16 FontFunc_Braille(struct TextPrinter *textPrinter) u16 char_; struct TextPrinterSubStruct *subStruct; subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + u32 scrollSpeed = GetPlayerTextScrollSpeed(); switch (textPrinter->state) { @@ -164,15 +159,15 @@ u16 FontFunc_Braille(struct TextPrinter *textPrinter) case RENDER_STATE_SCROLL: if (textPrinter->scrollDistance) { - if (textPrinter->scrollDistance < sScrollDistances[gSaveBlock2Ptr->optionsTextSpeed]) + if (textPrinter->scrollDistance < scrollSpeed) { ScrollWindow(textPrinter->printerTemplate.windowId, 0, textPrinter->scrollDistance, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); textPrinter->scrollDistance = 0; } else { - ScrollWindow(textPrinter->printerTemplate.windowId, 0, sScrollDistances[gSaveBlock2Ptr->optionsTextSpeed], PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->scrollDistance -= sScrollDistances[gSaveBlock2Ptr->optionsTextSpeed]; + ScrollWindow(textPrinter->printerTemplate.windowId, 0, scrollSpeed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->scrollDistance -= scrollSpeed; } CopyWindowToVram(textPrinter->printerTemplate.windowId, COPYWIN_GFX); } diff --git a/src/menu.c b/src/menu.c index 01a1babcee..4e7d5920a3 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1,5 +1,4 @@ #include "global.h" -#include "malloc.h" #include "bg.h" #include "blit.h" #include "decompress.h" @@ -9,7 +8,9 @@ #include "field_weather.h" #include "graphics.h" #include "main.h" +#include "malloc.h" #include "map_name_popup.h" +#include "match_call.h" #include "menu.h" #include "menu_helpers.h" #include "palette.h" @@ -23,8 +24,6 @@ #include "task.h" #include "text_window.h" #include "window.h" -#include "match_call.h" -#include "config/overworld.h" #include "constants/songs.h" struct MenuInfoIcon @@ -77,13 +76,6 @@ static EWRAM_DATA void *sTempTileDataBuffer[0x20] = {NULL}; const u16 gStandardMenuPalette[] = INCBIN_U16("graphics/interface/std_menu.gbapal"); -static const u8 sTextSpeedFrameDelays[] = -{ - [OPTIONS_TEXT_SPEED_SLOW] = 8, - [OPTIONS_TEXT_SPEED_MID] = 4, - [OPTIONS_TEXT_SPEED_FAST] = 1 -}; - static const struct WindowTemplate sStandardTextBox_WindowTemplates[] = { { @@ -626,22 +618,6 @@ void DisplayYesNoMenuWithDefault(u8 initialCursorPos) CreateYesNoMenu(&sYesNo_WindowTemplates, STD_WINDOW_BASE_TILE_NUM, STD_WINDOW_PALETTE_NUM, initialCursorPos); } -u32 GetPlayerTextSpeed(void) -{ - if (gTextFlags.forceMidTextSpeed) - return OPTIONS_TEXT_SPEED_MID; - return gSaveBlock2Ptr->optionsTextSpeed; -} - -u8 GetPlayerTextSpeedDelay(void) -{ - u32 speed; - if (gSaveBlock2Ptr->optionsTextSpeed > OPTIONS_TEXT_SPEED_FAST) - gSaveBlock2Ptr->optionsTextSpeed = OPTIONS_TEXT_SPEED_MID; - speed = GetPlayerTextSpeed(); - return sTextSpeedFrameDelays[speed]; -} - u8 AddStartMenuWindow(u8 numActions) { if (sStartMenuWindowId == WINDOW_NONE) diff --git a/src/text.c b/src/text.c index 7d24700068..a08d304e34 100644 --- a/src/text.c +++ b/src/text.c @@ -1,18 +1,19 @@ #include "global.h" #include "battle.h" -#include "main.h" +#include "blit.h" +#include "dynamic_placeholder_text_util.h" +#include "event_data.h" +#include "field_name_box.h" +#include "fonts.h" #include "m4a.h" +#include "main.h" +#include "menu.h" #include "palette.h" #include "sound.h" -#include "constants/songs.h" #include "string_util.h" -#include "window.h" #include "text.h" -#include "blit.h" -#include "menu.h" -#include "dynamic_placeholder_text_util.h" -#include "fonts.h" -#include "field_name_box.h" +#include "window.h" +#include "constants/songs.h" #include "constants/speaker_names.h" static u16 RenderText(struct TextPrinter *); @@ -87,11 +88,6 @@ static const u8 sDarkDownArrowTiles[] = INCBIN_U8("graphics/fonts/down_arrow_alt static const u8 sUnusedFRLGBlankedDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_blanked_down_arrow.4bpp"); static const u8 sUnusedFRLGDownArrow[] = INCBIN_U8("graphics/fonts/unused_frlg_down_arrow.4bpp"); static const u8 sDownArrowYCoords[] = { 0, 1, 2, 1 }; -static const u8 sWindowVerticalScrollSpeeds[] = { - [OPTIONS_TEXT_SPEED_SLOW] = 1, - [OPTIONS_TEXT_SPEED_MID] = 2, - [OPTIONS_TEXT_SPEED_FAST] = 4, -}; static const struct GlyphWidthFunc sGlyphWidthFuncs[] = { @@ -296,6 +292,31 @@ static const u8 sMenuCursorDimensions[][2] = [FONT_SHORT_NARROWER] = { 8, 14 }, }; +// these three arrays are most for readability, ie instead of returning a magic number 8 +static const u8 sTextSpeedFrameDelays[] = +{ + [OPTIONS_TEXT_SPEED_SLOW] = 8, + [OPTIONS_TEXT_SPEED_MID] = 4, + [OPTIONS_TEXT_SPEED_FAST] = 1, + [OPTIONS_TEXT_SPEED_INSTANT] = 1, +}; + +static const u8 sTextSpeedModifiers[] = +{ + [OPTIONS_TEXT_SPEED_SLOW] = TEXT_SPEED_SLOW_MODIFIER, + [OPTIONS_TEXT_SPEED_MID] = TEXT_SPEED_MEDIUM_MODIFIER, + [OPTIONS_TEXT_SPEED_FAST] = TEXT_SPEED_FAST_MODIFIER, + [OPTIONS_TEXT_SPEED_INSTANT] = TEXT_SPEED_INSTANT_MODIFIER, +}; + +static const u8 sTextScrollSpeeds[] = +{ + [OPTIONS_TEXT_SPEED_SLOW] = 1, + [OPTIONS_TEXT_SPEED_MID] = 2, + [OPTIONS_TEXT_SPEED_FAST] = 4, + [OPTIONS_TEXT_SPEED_INSTANT] = 6, +}; + static const u16 sFontBoldJapaneseGlyphs[] = INCBIN_U16("graphics/fonts/bold.hwjpnfont"); static void SetFontsPointer(const struct FontInfo *fonts) @@ -303,6 +324,40 @@ static void SetFontsPointer(const struct FontInfo *fonts) gFonts = fonts; } +u32 GetPlayerTextSpeed(void) +{ + if (gTextFlags.forceMidTextSpeed) + return OPTIONS_TEXT_SPEED_MID; + + if (gSaveBlock2Ptr->optionsTextSpeed > OPTIONS_TEXT_SPEED_INSTANT) + gSaveBlock2Ptr->optionsTextSpeed = OPTIONS_TEXT_SPEED_FAST; + + if (FlagGet(FLAG_TEXT_SPEED_INSTANT) || TEXT_SPEED_INSTANT) + return OPTIONS_TEXT_SPEED_INSTANT; + + return gSaveBlock2Ptr->optionsTextSpeed; +} + +u32 GetPlayerTextSpeedDelay(void) +{ + return sTextSpeedFrameDelays[GetPlayerTextSpeed()]; +} + +u32 GetPlayerTextSpeedModifier(void) +{ + return sTextSpeedModifiers[GetPlayerTextSpeed()]; +} + +u32 GetPlayerTextScrollSpeed(void) +{ + return sTextScrollSpeeds[GetPlayerTextSpeed()]; +} + +bool32 IsPlayerTextSpeedInstant(void) +{ + return GetPlayerTextSpeed() == OPTIONS_TEXT_SPEED_INSTANT; +} + void DeactivateAllTextPrinters(void) { int printer; @@ -380,30 +435,53 @@ bool32 AddTextPrinter(struct TextPrinterTemplate *printerTemplate, u8 speed, voi void RunTextPrinters(void) { - int i; + bool32 isInstantText = IsPlayerTextSpeedInstant(); + u32 textRepeats = GetPlayerTextSpeedModifier(); - if (!gDisableTextPrinters) + if (gDisableTextPrinters) + return; + + do { - for (i = 0; i < WINDOWS_MAX; ++i) + u32 numEmpty = 0; + for (u32 windowId = 0; windowId < WINDOWS_MAX; windowId++) { - if (sTextPrinters[i].active) + if (sTextPrinters[windowId].active) { - u16 renderCmd = RenderFont(&sTextPrinters[i]); - switch (renderCmd) + for (u32 repeat = 0; repeat < textRepeats; repeat++) { - case RENDER_PRINT: - CopyWindowToVram(sTextPrinters[i].printerTemplate.windowId, COPYWIN_GFX); - case RENDER_UPDATE: - if (sTextPrinters[i].callback != NULL) - sTextPrinters[i].callback(&sTextPrinters[i].printerTemplate, renderCmd); - break; - case RENDER_FINISH: - sTextPrinters[i].active = FALSE; - break; + u32 renderState = RenderFont(&sTextPrinters[windowId]); + switch (renderState) + { + case RENDER_PRINT: + CopyWindowToVram(sTextPrinters[windowId].printerTemplate.windowId, COPYWIN_GFX); + if (sTextPrinters[windowId].callback != NULL) + sTextPrinters[windowId].callback(&sTextPrinters[windowId].printerTemplate, renderState); + break; + case RENDER_UPDATE: + if (sTextPrinters[windowId].callback != NULL) + sTextPrinters[windowId].callback(&sTextPrinters[windowId].printerTemplate, renderState); + isInstantText = FALSE; + break; + case RENDER_FINISH: + sTextPrinters[windowId].active = FALSE; + isInstantText = FALSE; + break; + } + + if (!sTextPrinters[windowId].active) + break; } } + else + { + numEmpty++; + } } - } + + if (numEmpty == WINDOWS_MAX) + return; + } while (isInstantText); } bool32 IsTextPrinterActive(u8 id) @@ -905,7 +983,7 @@ void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter) else { subStruct->downArrowYPosIdx = 0; - subStruct->downArrowDelay = 0; + subStruct->utilityCounter = 0; } } @@ -916,9 +994,9 @@ void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) if (gTextFlags.autoScroll == 0) { - if (subStruct->downArrowDelay != 0) + if (subStruct->utilityCounter != 0) { - subStruct->downArrowDelay--; + subStruct->utilityCounter--; } else { @@ -954,7 +1032,7 @@ void TextPrinterDrawDownArrow(struct TextPrinter *textPrinter) 16); CopyWindowToVram(textPrinter->printerTemplate.windowId, COPYWIN_GFX); - subStruct->downArrowDelay = 8; + subStruct->utilityCounter = 8 * GetPlayerTextSpeedModifier(); subStruct->downArrowYPosIdx++; } } @@ -1058,7 +1136,7 @@ void DrawDownArrow(u8 windowId, u16 x, u16 y, u8 bgColor, bool32 drawArrow, u8 * BlitBitmapRectToWindow(windowId, arrowTiles, 0, sDownArrowYCoords[*yCoordIndex & 3], 8, 16, x, y - 2, 8, 16); CopyWindowToVram(windowId, COPYWIN_GFX); - *counter = 8; + *counter = 8 * GetPlayerTextSpeedModifier(); ++*yCoordIndex; } } @@ -1074,7 +1152,7 @@ static u16 RenderText(struct TextPrinter *textPrinter) switch (textPrinter->state) { case RENDER_STATE_HANDLE_CHAR: - if (JOY_HELD(A_BUTTON | B_BUTTON) && subStruct->hasPrintBeenSpedUp) + if ((JOY_HELD(A_BUTTON | B_BUTTON) && subStruct->hasPrintBeenSpedUp) || IsPlayerTextSpeedInstant()) textPrinter->delayCounter = 0; if (textPrinter->delayCounter && textPrinter->textSpeed) @@ -1332,6 +1410,7 @@ static u16 RenderText(struct TextPrinter *textPrinter) case RENDER_STATE_SCROLL_START: if (TextPrinterWaitWithDownArrow(textPrinter)) { + subStruct->utilityCounter = 0; TextPrinterClearDownArrow(textPrinter); textPrinter->scrollDistance = gFonts[textPrinter->printerTemplate.fontId].maxLetterHeight + textPrinter->printerTemplate.lineSpacing; textPrinter->printerTemplate.currentX = textPrinter->printerTemplate.x; @@ -1341,18 +1420,31 @@ static u16 RenderText(struct TextPrinter *textPrinter) case RENDER_STATE_SCROLL: if (textPrinter->scrollDistance) { - int scrollSpeed = GetPlayerTextSpeed(); - int speed = sWindowVerticalScrollSpeeds[scrollSpeed]; - if (textPrinter->scrollDistance < speed) + u32 scrollSpeed = GetPlayerTextScrollSpeed(); + u32 speedModifier = GetPlayerTextSpeedModifier(); + + if (subStruct->utilityCounter != 0) + { + subStruct->utilityCounter--; + return RENDER_UPDATE; + } + + if (textPrinter->scrollDistance < scrollSpeed) { ScrollWindow(textPrinter->printerTemplate.windowId, 0, textPrinter->scrollDistance, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); textPrinter->scrollDistance = 0; } else { - ScrollWindow(textPrinter->printerTemplate.windowId, 0, speed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); - textPrinter->scrollDistance -= speed; + ScrollWindow(textPrinter->printerTemplate.windowId, 0, scrollSpeed, PIXEL_FILL(textPrinter->printerTemplate.bgColor)); + textPrinter->scrollDistance -= scrollSpeed; } + + if (speedModifier > 1) + subStruct->utilityCounter = speedModifier; + else + subStruct->utilityCounter = 0; + CopyWindowToVram(textPrinter->printerTemplate.windowId, COPYWIN_GFX); } else