From 082f3893215797268d7ac8c1000ebe371f276af7 Mon Sep 17 00:00:00 2001 From: BobTheBob9 Date: Tue, 16 Aug 2022 01:12:59 +0100 Subject: lots of stuff idk --- NorthstarDLL/localchatwriter.cpp | 906 +++++++++++++++++++-------------------- 1 file changed, 453 insertions(+), 453 deletions(-) (limited to 'NorthstarDLL/localchatwriter.cpp') diff --git a/NorthstarDLL/localchatwriter.cpp b/NorthstarDLL/localchatwriter.cpp index ed90acb2..14f36999 100644 --- a/NorthstarDLL/localchatwriter.cpp +++ b/NorthstarDLL/localchatwriter.cpp @@ -1,453 +1,453 @@ -#include "pch.h" -#include "localchatwriter.h" - -class vgui_BaseRichText_vtable; - -class vgui_BaseRichText -{ - public: - vgui_BaseRichText_vtable* vtable; -}; - -class vgui_BaseRichText_vtable -{ - public: - char unknown1[1880]; - - void(__fastcall* InsertChar)(vgui_BaseRichText* self, wchar_t ch); - - // yes these are swapped from the Source 2013 code, who knows why - void(__fastcall* InsertStringWide)(vgui_BaseRichText* self, const wchar_t* wszText); - void(__fastcall* InsertStringAnsi)(vgui_BaseRichText* self, const char* text); - - void(__fastcall* SelectNone)(vgui_BaseRichText* self); - void(__fastcall* SelectAllText)(vgui_BaseRichText* self); - void(__fastcall* SelectNoText)(vgui_BaseRichText* self); - void(__fastcall* CutSelected)(vgui_BaseRichText* self); - void(__fastcall* CopySelected)(vgui_BaseRichText* self); - void(__fastcall* SetPanelInteractive)(vgui_BaseRichText* self, bool bInteractive); - void(__fastcall* SetUnusedScrollbarInvisible)(vgui_BaseRichText* self, bool bInvis); - - void* unknown2; - - void(__fastcall* GotoTextStart)(vgui_BaseRichText* self); - void(__fastcall* GotoTextEnd)(vgui_BaseRichText* self); - - void* unknown3[3]; - - void(__fastcall* SetVerticalScrollbar)(vgui_BaseRichText* self, bool state); - void(__fastcall* SetMaximumCharCount)(vgui_BaseRichText* self, int maxChars); - void(__fastcall* InsertColorChange)(vgui_BaseRichText* self, Color col); - void(__fastcall* InsertIndentChange)(vgui_BaseRichText* self, int pixelsIndent); - void(__fastcall* InsertClickableTextStart)(vgui_BaseRichText* self, const char* pchClickAction); - void(__fastcall* InsertClickableTextEnd)(vgui_BaseRichText* self); - void(__fastcall* InsertPossibleURLString)( - vgui_BaseRichText* self, const char* text, Color URLTextColor, Color normalTextColor); - void(__fastcall* InsertFade)(vgui_BaseRichText* self, float flSustain, float flLength); - void(__fastcall* ResetAllFades)(vgui_BaseRichText* self, bool bHold, bool bOnlyExpired, float flNewSustain); - void(__fastcall* SetToFullHeight)(vgui_BaseRichText* self); - int(__fastcall* GetNumLines)(vgui_BaseRichText* self); -}; - -class CGameSettings -{ - public: - char unknown1[92]; - int isChatEnabled; -}; - -// Not sure what this actually refers to but chatFadeLength and chatFadeSustain -// have their value at the same offset -class CGameFloatVar -{ - public: - char unknown1[88]; - float value; -}; - -CGameSettings** gGameSettings; -CGameFloatVar** gChatFadeLength; -CGameFloatVar** gChatFadeSustain; - -CHudChat** CHudChat::allHuds; - -typedef void(__fastcall* ConvertANSIToUnicodeType)(LPCSTR ansi, int ansiCharLength, LPWSTR unicode, int unicodeCharLength); -ConvertANSIToUnicodeType ConvertANSIToUnicode; - -LocalChatWriter::SwatchColor swatchColors[4] = { - LocalChatWriter::MainTextColor, - LocalChatWriter::SameTeamNameColor, - LocalChatWriter::EnemyTeamNameColor, - LocalChatWriter::NetworkNameColor, -}; - -Color darkColors[8] = { - Color {0, 0, 0, 255}, - Color {205, 49, 49, 255}, - Color {13, 188, 121, 255}, - Color {229, 229, 16, 255}, - Color {36, 114, 200, 255}, - Color {188, 63, 188, 255}, - Color {17, 168, 205, 255}, - Color {229, 229, 229, 255}}; - -Color lightColors[8] = { - Color {102, 102, 102, 255}, - Color {241, 76, 76, 255}, - Color {35, 209, 139, 255}, - Color {245, 245, 67, 255}, - Color {59, 142, 234, 255}, - Color {214, 112, 214, 255}, - Color {41, 184, 219, 255}, - Color {255, 255, 255, 255}}; - -class AnsiEscapeParser -{ - public: - explicit AnsiEscapeParser(LocalChatWriter* writer) : m_writer(writer) {} - - void HandleVal(unsigned long val) - { - switch (m_next) - { - case Next::ControlType: - m_next = HandleControlType(val); - break; - case Next::ForegroundType: - m_next = HandleForegroundType(val); - break; - case Next::Foreground8Bit: - m_next = HandleForeground8Bit(val); - break; - case Next::ForegroundR: - m_next = HandleForegroundR(val); - break; - case Next::ForegroundG: - m_next = HandleForegroundG(val); - break; - case Next::ForegroundB: - m_next = HandleForegroundB(val); - break; - } - } - - private: - enum class Next - { - ControlType, - ForegroundType, - Foreground8Bit, - ForegroundR, - ForegroundG, - ForegroundB - }; - - LocalChatWriter* m_writer; - Next m_next = Next::ControlType; - Color m_expandedColor {0, 0, 0, 0}; - - Next HandleControlType(unsigned long val) - { - // Reset - if (val == 0 || val == 39) - { - m_writer->InsertSwatchColorChange(LocalChatWriter::MainTextColor); - return Next::ControlType; - } - - // Dark foreground color - if (val >= 30 && val < 38) - { - m_writer->InsertColorChange(darkColors[val - 30]); - return Next::ControlType; - } - - // Light foreground color - if (val >= 90 && val < 98) - { - m_writer->InsertColorChange(lightColors[val - 90]); - return Next::ControlType; - } - - // Game swatch color - if (val >= 110 && val < 114) - { - m_writer->InsertSwatchColorChange(swatchColors[val - 110]); - return Next::ControlType; - } - - // Expanded foreground color - if (val == 38) - { - return Next::ForegroundType; - } - - return Next::ControlType; - } - - Next HandleForegroundType(unsigned long val) - { - // Next values are r,g,b - if (val == 2) - { - m_expandedColor.SetColor(0, 0, 0, 255); - return Next::ForegroundR; - } - // Next value is 8-bit swatch color - if (val == 5) - { - return Next::Foreground8Bit; - } - - // Invalid - return Next::ControlType; - } - - Next HandleForeground8Bit(unsigned long val) - { - if (val < 8) - { - m_writer->InsertColorChange(darkColors[val]); - } - else if (val < 16) - { - m_writer->InsertColorChange(lightColors[val - 8]); - } - else if (val < 232) - { - unsigned char code = val - 16; - unsigned char blue = code % 6; - unsigned char green = ((code - blue) / 6) % 6; - unsigned char red = (code - blue - (green * 6)) / 36; - m_writer->InsertColorChange( - Color {(unsigned char)(red * 51), (unsigned char)(green * 51), (unsigned char)(blue * 51), 255}); - } - else if (val < UCHAR_MAX) - { - unsigned char brightness = (val - 232) * 10 + 8; - m_writer->InsertColorChange(Color {brightness, brightness, brightness, 255}); - } - - return Next::ControlType; - } - - Next HandleForegroundR(unsigned long val) - { - if (val >= UCHAR_MAX) - return Next::ControlType; - - m_expandedColor[0] = (unsigned char)val; - return Next::ForegroundG; - } - - Next HandleForegroundG(unsigned long val) - { - if (val >= UCHAR_MAX) - return Next::ControlType; - - m_expandedColor[1] = (unsigned char)val; - return Next::ForegroundB; - } - - Next HandleForegroundB(unsigned long val) - { - if (val >= UCHAR_MAX) - return Next::ControlType; - - m_expandedColor[2] = (unsigned char)val; - m_writer->InsertColorChange(m_expandedColor); - return Next::ControlType; - } -}; - -LocalChatWriter::LocalChatWriter(Context context) : m_context(context) {} - -void LocalChatWriter::Write(const char* str) -{ - char writeBuffer[256]; - - while (true) - { - const char* startOfEscape = strstr(str, "\033["); - - if (startOfEscape == NULL) - { - // No more escape sequences, write the remaining text and exit - InsertText(str); - break; - } - - if (startOfEscape != str) - { - // There is some text before the escape sequence, just print that - size_t copyChars = startOfEscape - str; - if (copyChars > 255) - copyChars = 255; - - strncpy_s(writeBuffer, copyChars + 1, str, copyChars); - - InsertText(writeBuffer); - } - - const char* escape = startOfEscape + 2; - str = ApplyAnsiEscape(escape); - } -} - -void LocalChatWriter::WriteLine(const char* str) -{ - InsertChar(L'\n'); - InsertSwatchColorChange(MainTextColor); - Write(str); -} - -void LocalChatWriter::InsertChar(wchar_t ch) -{ - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - - hud->m_richText->vtable->InsertChar(hud->m_richText, ch); - } - - if (ch != L'\n') - { - InsertDefaultFade(); - } -} - -void LocalChatWriter::InsertText(const char* str) -{ - spdlog::info(str); - - WCHAR messageUnicode[288]; - ConvertANSIToUnicode(str, -1, messageUnicode, 274); - - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - - hud->m_richText->vtable->InsertStringWide(hud->m_richText, messageUnicode); - } - - InsertDefaultFade(); -} - -void LocalChatWriter::InsertText(const wchar_t* str) -{ - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - - hud->m_richText->vtable->InsertStringWide(hud->m_richText, str); - } - - InsertDefaultFade(); -} - -void LocalChatWriter::InsertColorChange(Color color) -{ - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - - hud->m_richText->vtable->InsertColorChange(hud->m_richText, color); - } -} - -static Color GetHudSwatchColor(CHudChat* hud, LocalChatWriter::SwatchColor swatchColor) -{ - switch (swatchColor) - { - case LocalChatWriter::MainTextColor: - return hud->m_mainTextColor; - - case LocalChatWriter::SameTeamNameColor: - return hud->m_sameTeamColor; - - case LocalChatWriter::EnemyTeamNameColor: - return hud->m_enemyTeamColor; - - case LocalChatWriter::NetworkNameColor: - return hud->m_networkNameColor; - - } - - return Color(0, 0, 0, 0); -} - -void LocalChatWriter::InsertSwatchColorChange(SwatchColor swatchColor) -{ - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - hud->m_richText->vtable->InsertColorChange(hud->m_richText, GetHudSwatchColor(hud, swatchColor)); - } -} - -const char* LocalChatWriter::ApplyAnsiEscape(const char* escape) -{ - AnsiEscapeParser decoder(this); - while (true) - { - char* afterControlType = NULL; - unsigned long controlType = strtoul(escape, &afterControlType, 10); - - // Malformed cases: - // afterControlType = NULL: strtoul errored - // controlType = 0 and escape doesn't actually start with 0: wasn't a number - if (afterControlType == NULL || (controlType == 0 && escape[0] != '0')) - { - return escape; - } - - decoder.HandleVal(controlType); - - // m indicates the end of the sequence - if (afterControlType[0] == 'm') - { - return afterControlType + 1; - } - - // : or ; indicates more values remain, anything else is malformed - if (afterControlType[0] != ':' && afterControlType[0] != ';') - { - return afterControlType; - } - - escape = afterControlType + 1; - } -} - -void LocalChatWriter::InsertDefaultFade() -{ - float fadeLength = 0.f; - float fadeSustain = 0.f; - if ((*gGameSettings)->isChatEnabled) - { - fadeLength = (*gChatFadeLength)->value; - fadeSustain = (*gChatFadeSustain)->value; - } - - for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) - { - if (hud->m_unknownContext != (int)m_context) - continue; - hud->m_richText->vtable->InsertFade(hud->m_richText, fadeSustain, fadeLength); - } -} - -ON_DLL_LOAD_CLIENT("client.dll", LocalChatWriter, (CModule module)) -{ - gGameSettings = module.Offset(0x11BAA48).As(); - gChatFadeLength = module.Offset(0x11BAB78).As(); - gChatFadeSustain = module.Offset(0x11BAC08).As(); - CHudChat::allHuds = module.Offset(0x11BA9E8).As(); - - ConvertANSIToUnicode = module.Offset(0x7339A0).As(); -} +#include "pch.h" +#include "localchatwriter.h" + +class vgui_BaseRichText_vtable; + +class vgui_BaseRichText +{ + public: + vgui_BaseRichText_vtable* vtable; +}; + +class vgui_BaseRichText_vtable +{ + public: + char unknown1[1880]; + + void(__fastcall* InsertChar)(vgui_BaseRichText* self, wchar_t ch); + + // yes these are swapped from the Source 2013 code, who knows why + void(__fastcall* InsertStringWide)(vgui_BaseRichText* self, const wchar_t* wszText); + void(__fastcall* InsertStringAnsi)(vgui_BaseRichText* self, const char* text); + + void(__fastcall* SelectNone)(vgui_BaseRichText* self); + void(__fastcall* SelectAllText)(vgui_BaseRichText* self); + void(__fastcall* SelectNoText)(vgui_BaseRichText* self); + void(__fastcall* CutSelected)(vgui_BaseRichText* self); + void(__fastcall* CopySelected)(vgui_BaseRichText* self); + void(__fastcall* SetPanelInteractive)(vgui_BaseRichText* self, bool bInteractive); + void(__fastcall* SetUnusedScrollbarInvisible)(vgui_BaseRichText* self, bool bInvis); + + void* unknown2; + + void(__fastcall* GotoTextStart)(vgui_BaseRichText* self); + void(__fastcall* GotoTextEnd)(vgui_BaseRichText* self); + + void* unknown3[3]; + + void(__fastcall* SetVerticalScrollbar)(vgui_BaseRichText* self, bool state); + void(__fastcall* SetMaximumCharCount)(vgui_BaseRichText* self, int maxChars); + void(__fastcall* InsertColorChange)(vgui_BaseRichText* self, Color col); + void(__fastcall* InsertIndentChange)(vgui_BaseRichText* self, int pixelsIndent); + void(__fastcall* InsertClickableTextStart)(vgui_BaseRichText* self, const char* pchClickAction); + void(__fastcall* InsertClickableTextEnd)(vgui_BaseRichText* self); + void(__fastcall* InsertPossibleURLString)( + vgui_BaseRichText* self, const char* text, Color URLTextColor, Color normalTextColor); + void(__fastcall* InsertFade)(vgui_BaseRichText* self, float flSustain, float flLength); + void(__fastcall* ResetAllFades)(vgui_BaseRichText* self, bool bHold, bool bOnlyExpired, float flNewSustain); + void(__fastcall* SetToFullHeight)(vgui_BaseRichText* self); + int(__fastcall* GetNumLines)(vgui_BaseRichText* self); +}; + +class CGameSettings +{ + public: + char unknown1[92]; + int isChatEnabled; +}; + +// Not sure what this actually refers to but chatFadeLength and chatFadeSustain +// have their value at the same offset +class CGameFloatVar +{ + public: + char unknown1[88]; + float value; +}; + +CGameSettings** gGameSettings; +CGameFloatVar** gChatFadeLength; +CGameFloatVar** gChatFadeSustain; + +CHudChat** CHudChat::allHuds; + +typedef void(__fastcall* ConvertANSIToUnicodeType)(LPCSTR ansi, int ansiCharLength, LPWSTR unicode, int unicodeCharLength); +ConvertANSIToUnicodeType ConvertANSIToUnicode; + +LocalChatWriter::SwatchColor swatchColors[4] = { + LocalChatWriter::MainTextColor, + LocalChatWriter::SameTeamNameColor, + LocalChatWriter::EnemyTeamNameColor, + LocalChatWriter::NetworkNameColor, +}; + +Color darkColors[8] = { + Color {0, 0, 0, 255}, + Color {205, 49, 49, 255}, + Color {13, 188, 121, 255}, + Color {229, 229, 16, 255}, + Color {36, 114, 200, 255}, + Color {188, 63, 188, 255}, + Color {17, 168, 205, 255}, + Color {229, 229, 229, 255}}; + +Color lightColors[8] = { + Color {102, 102, 102, 255}, + Color {241, 76, 76, 255}, + Color {35, 209, 139, 255}, + Color {245, 245, 67, 255}, + Color {59, 142, 234, 255}, + Color {214, 112, 214, 255}, + Color {41, 184, 219, 255}, + Color {255, 255, 255, 255}}; + +class AnsiEscapeParser +{ + public: + explicit AnsiEscapeParser(LocalChatWriter* writer) : m_writer(writer) {} + + void HandleVal(unsigned long val) + { + switch (m_next) + { + case Next::ControlType: + m_next = HandleControlType(val); + break; + case Next::ForegroundType: + m_next = HandleForegroundType(val); + break; + case Next::Foreground8Bit: + m_next = HandleForeground8Bit(val); + break; + case Next::ForegroundR: + m_next = HandleForegroundR(val); + break; + case Next::ForegroundG: + m_next = HandleForegroundG(val); + break; + case Next::ForegroundB: + m_next = HandleForegroundB(val); + break; + } + } + + private: + enum class Next + { + ControlType, + ForegroundType, + Foreground8Bit, + ForegroundR, + ForegroundG, + ForegroundB + }; + + LocalChatWriter* m_writer; + Next m_next = Next::ControlType; + Color m_expandedColor {0, 0, 0, 0}; + + Next HandleControlType(unsigned long val) + { + // Reset + if (val == 0 || val == 39) + { + m_writer->InsertSwatchColorChange(LocalChatWriter::MainTextColor); + return Next::ControlType; + } + + // Dark foreground color + if (val >= 30 && val < 38) + { + m_writer->InsertColorChange(darkColors[val - 30]); + return Next::ControlType; + } + + // Light foreground color + if (val >= 90 && val < 98) + { + m_writer->InsertColorChange(lightColors[val - 90]); + return Next::ControlType; + } + + // Game swatch color + if (val >= 110 && val < 114) + { + m_writer->InsertSwatchColorChange(swatchColors[val - 110]); + return Next::ControlType; + } + + // Expanded foreground color + if (val == 38) + { + return Next::ForegroundType; + } + + return Next::ControlType; + } + + Next HandleForegroundType(unsigned long val) + { + // Next values are r,g,b + if (val == 2) + { + m_expandedColor.SetColor(0, 0, 0, 255); + return Next::ForegroundR; + } + // Next value is 8-bit swatch color + if (val == 5) + { + return Next::Foreground8Bit; + } + + // Invalid + return Next::ControlType; + } + + Next HandleForeground8Bit(unsigned long val) + { + if (val < 8) + { + m_writer->InsertColorChange(darkColors[val]); + } + else if (val < 16) + { + m_writer->InsertColorChange(lightColors[val - 8]); + } + else if (val < 232) + { + unsigned char code = val - 16; + unsigned char blue = code % 6; + unsigned char green = ((code - blue) / 6) % 6; + unsigned char red = (code - blue - (green * 6)) / 36; + m_writer->InsertColorChange( + Color {(unsigned char)(red * 51), (unsigned char)(green * 51), (unsigned char)(blue * 51), 255}); + } + else if (val < UCHAR_MAX) + { + unsigned char brightness = (val - 232) * 10 + 8; + m_writer->InsertColorChange(Color {brightness, brightness, brightness, 255}); + } + + return Next::ControlType; + } + + Next HandleForegroundR(unsigned long val) + { + if (val >= UCHAR_MAX) + return Next::ControlType; + + m_expandedColor[0] = (unsigned char)val; + return Next::ForegroundG; + } + + Next HandleForegroundG(unsigned long val) + { + if (val >= UCHAR_MAX) + return Next::ControlType; + + m_expandedColor[1] = (unsigned char)val; + return Next::ForegroundB; + } + + Next HandleForegroundB(unsigned long val) + { + if (val >= UCHAR_MAX) + return Next::ControlType; + + m_expandedColor[2] = (unsigned char)val; + m_writer->InsertColorChange(m_expandedColor); + return Next::ControlType; + } +}; + +LocalChatWriter::LocalChatWriter(Context context) : m_context(context) {} + +void LocalChatWriter::Write(const char* str) +{ + char writeBuffer[256]; + + while (true) + { + const char* startOfEscape = strstr(str, "\033["); + + if (startOfEscape == NULL) + { + // No more escape sequences, write the remaining text and exit + InsertText(str); + break; + } + + if (startOfEscape != str) + { + // There is some text before the escape sequence, just print that + size_t copyChars = startOfEscape - str; + if (copyChars > 255) + copyChars = 255; + + strncpy_s(writeBuffer, copyChars + 1, str, copyChars); + + InsertText(writeBuffer); + } + + const char* escape = startOfEscape + 2; + str = ApplyAnsiEscape(escape); + } +} + +void LocalChatWriter::WriteLine(const char* str) +{ + InsertChar(L'\n'); + InsertSwatchColorChange(MainTextColor); + Write(str); +} + +void LocalChatWriter::InsertChar(wchar_t ch) +{ + for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) + { + if (hud->m_unknownContext != (int)m_context) + continue; + + hud->m_richText->vtable->InsertChar(hud->m_richText, ch); + } + + if (ch != L'\n') + { + InsertDefaultFade(); + } +} + +void LocalChatWriter::InsertText(const char* str) +{ + spdlog::info(str); + + WCHAR messageUnicode[288]; + ConvertANSIToUnicode(str, -1, messageUnicode, 274); + + for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) + { + if (hud->m_unknownContext != (int)m_context) + continue; + + hud->m_richText->vtable->InsertStringWide(hud->m_richText, messageUnicode); + } + + InsertDefaultFade(); +} + +void LocalChatWriter::InsertText(const wchar_t* str) +{ + for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) + { + if (hud->m_unknownContext != (int)m_context) + continue; + + hud->m_richText->vtable->InsertStringWide(hud->m_richText, str); + } + + InsertDefaultFade(); +} + +void LocalChatWriter::InsertColorChange(Color color) +{ + for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) + { + if (hud->m_unknownContext != (int)m_context) + continue; + + hud->m_richText->vtable->InsertColorChange(hud->m_richText, color); + } +} + +static Color GetHudSwatchColor(CHudChat* hud, LocalChatWriter::SwatchColor swatchColor) +{ + switch (swatchColor) + { + case LocalChatWriter::MainTextColor: + return hud->m_mainTextColor; + + case LocalChatWriter::SameTeamNameColor: + return hud->m_sameTeamColor; + + case LocalChatWriter::EnemyTeamNameColor: + return hud->m_enemyTeamColor; + + case LocalChatWriter::NetworkNameColor: + return hud->m_networkNameColor; + + } + + return Color(0, 0, 0, 0); +} + +void LocalChatWriter::InsertSwatchColorChange(SwatchColor swatchColor) +{ + for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) + { + if (hud->m_unknownContext != (int)m_context) + continue; + hud->m_richText->vtable->InsertColorChange(hud->m_richText, GetHudSwatchColor(hud, swatchColor)); + } +} + +const char* LocalChatWriter::ApplyAnsiEscape(const char* escape) +{ + AnsiEscapeParser decoder(this); + while (true) + { + char* afterControlType = NULL; + unsigned long controlType = strtoul(escape, &afterControlType, 10); + + // Malformed cases: + // afterControlType = NULL: strtoul errored + // controlType = 0 and escape doesn't actually start with 0: wasn't a number + if (afterControlType == NULL || (controlType == 0 && escape[0] != '0')) + { + return escape; + } + + decoder.HandleVal(controlType); + + // m indicates the end of the sequence + if (afterControlType[0] == 'm') + { + return afterControlType + 1; + } + + // : or ; indicates more values remain, anything else is malformed + if (afterControlType[0] != ':' && afterControlType[0] != ';') + { + return afterControlType; + } + + escape = afterControlType + 1; + } +} + +void LocalChatWriter::InsertDefaultFade() +{ + float fadeLength = 0.f; + float fadeSustain = 0.f; + if ((*gGameSettings)->isChatEnabled) + { + fadeLength = (*gChatFadeLength)->value; + fadeSustain = (*gChatFadeSustain)->value; + } + + for (CHudChat* hud = *CHudChat::allHuds; hud != NULL; hud = hud->next) + { + if (hud->m_unknownContext != (int)m_context) + continue; + hud->m_richText->vtable->InsertFade(hud->m_richText, fadeSustain, fadeLength); + } +} + +ON_DLL_LOAD_CLIENT("client.dll", LocalChatWriter, (CModule module)) +{ + gGameSettings = module.Offset(0x11BAA48).As(); + gChatFadeLength = module.Offset(0x11BAB78).As(); + gChatFadeSustain = module.Offset(0x11BAC08).As(); + CHudChat::allHuds = module.Offset(0x11BA9E8).As(); + + ConvertANSIToUnicode = module.Offset(0x7339A0).As(); +} -- cgit v1.2.3