diff --git a/src/Components/Modules/Colors.cpp b/src/Components/Modules/Colors.cpp index 9e64f0fe..69c9bd74 100644 --- a/src/Components/Modules/Colors.cpp +++ b/src/Components/Modules/Colors.cpp @@ -1,8 +1,20 @@ #include "STDInclude.hpp" +// -- Additional colors -- +// +// Colors are resolved using ColorIndex(). +// It resolves the colorTable entry using the ASCII value. +// If we want to add colors, we have to use correct ASCII chars. +// As the last value is 0x39 (9), we have to go on with 0x3A (:) +// So the next chars would be: +// 0x3A (:), 0x3B (;), 0x3C (<), 0x3D (=), ... +// +// The problem though is that I_CleanString doesn't know we added colors, so we have to adapt that as well! + namespace Components { Dvar::Var Colors::NewColors; + std::vector Colors::ColorTable; void Colors::Strip(const char* in, char* out, int max) { @@ -12,16 +24,17 @@ namespace Components int current = 0; while (*in != 0 && current < max) { - if (!Q_IsColorString(in)) + char index = *(in + 1); + if (*in == '^' && (Colors::ColorIndex(index) != 7 || index == '7')) // Add 1 new color for now + { + in++; + } + else { *out = *in; out++; current++; } - else - { - in++; - } in++; } *out = '\0'; @@ -34,7 +47,7 @@ namespace Components return std::string(buffer); } - void __declspec(naked) Colors::ClientUserinfoChanged(int length) + void __declspec(naked) Colors::ClientUserinfoChanged() { __asm { @@ -62,34 +75,81 @@ namespace Components return buf; } - void Colors::UpdateColorTable() + void Colors::PatchColorLimit(char limit) { - static int LastState = 2; - static DWORD DefaultTable[8] = { 0 }; - DWORD* gColorTable = (DWORD*)0x78DC70; + Utils::Hook::Set(0x535629, limit); // DrawText2d + Utils::Hook::Set(0x4C1BE4, limit); // No idea :P + Utils::Hook::Set(0x4863DD, limit); // No idea :P + Utils::Hook::Set(0x486429, limit); // No idea :P + Utils::Hook::Set(0x49A5A8, limit); // No idea :P + Utils::Hook::Set(0x505721, limit); // R_TextWidth + Utils::Hook::Set(0x505801, limit); // No idea :P + Utils::Hook::Set(0x50597F, limit); // No idea :P + Utils::Hook::Set(0x5815DB, limit); // No idea :P + Utils::Hook::Set(0x592ED0, limit); // No idea :P + Utils::Hook::Set(0x5A2E2E, limit); // No idea :P - if (LastState == 2) + Utils::Hook::Set(0x5A2733, limit - '0'); // No idea :P + } + + char Colors::Add(uint8_t r, uint8_t g, uint8_t b) + { + char index = '0' + static_cast(Colors::ColorTable.size()); + Colors::ColorTable.push_back(RGB(r, g, b)); + Colors::PatchColorLimit(index); + return index; + } + + unsigned int Colors::ColorIndex(unsigned char index) + { + unsigned int result = index - '0'; + if (result >= Colors::ColorTable.size() || result < 0) result = 7; + return result; + } + + void Colors::LookupColor(DWORD* color, char index) + { + if (index == '8') // Color 8 { - memcpy(DefaultTable, gColorTable, sizeof(DefaultTable)); + *color = *reinterpret_cast(0x66E5F70); } - - if (Colors::NewColors.Get() && (0xF & static_cast(Colors::NewColors.Get())) != LastState) + else if (index == '9') // Color 9 { - // Apply NTA's W² colors :3 (slightly modified though^^) - gColorTable[1] = RGB(255, 49, 49); - gColorTable[2] = RGB(134, 192, 0); - gColorTable[3] = RGB(255, 173, 34); - gColorTable[4] = RGB(0, 135, 193); - gColorTable[5] = RGB(32, 197, 255); - gColorTable[6] = RGB(151, 80, 221); - - LastState = Colors::NewColors.Get(); + *color = *reinterpret_cast(0x66E5F74); } - else if (!Colors::NewColors.Get() && (0xF & static_cast(Colors::NewColors.Get())) != LastState) + else { - memcpy(gColorTable, DefaultTable, sizeof(DefaultTable)); + int clrIndex = Colors::ColorIndex(index); - LastState = Colors::NewColors.Get(); + // Use native colors + if (clrIndex <= 7 && !Colors::NewColors.Get()) + { + *color = reinterpret_cast(0x78DC70)[index - 48]; + } + else + { + *color = Colors::ColorTable[clrIndex]; + } + } + } + + char* Colors::CleanStrStub(char* string) + { + Colors::Strip(string, string, strlen(string)); + return string; + } + + void __declspec(naked) Colors::LookupColorStub() + { + __asm + { + push ebx + push [esp + 8h] // Index + push esi // Color ref + call Colors::LookupColor + add esp, 8h + pop ebx + retn } } @@ -101,10 +161,39 @@ namespace Components // Though, don't apply that to overhead names. Utils::Hook(0x581932, Colors::GetClientName, HOOK_CALL).Install()->Quick(); - // Set frame handler - Renderer::OnFrame(Colors::UpdateColorTable); + // Patch RB_LookupColor + Utils::Hook(0x534CD0, Colors::LookupColorStub, HOOK_JUMP).Install()->Quick(); + + // Patch ColorIndex + Utils::Hook(0x417770, Colors::ColorIndex, HOOK_JUMP).Install()->Quick(); + + // Patch I_CleanStr + Utils::Hook(0x4AD470, Colors::CleanStrStub, HOOK_JUMP).Install()->Quick(); // Register dvar Colors::NewColors = Dvar::Register("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare² color code style."); + + // Add our colors + Colors::Add(0, 0, 0); // 0 - Black + Colors::Add(255, 49, 49); // 1 - Red + Colors::Add(134, 192, 0); // 2 - Green + Colors::Add(255, 173, 34); // 3 - Yellow + Colors::Add(0, 135, 193); // 4 - Blue + Colors::Add(32, 197, 255); // 5 - Light Blue + Colors::Add(151, 80, 221); // 6 - Pink + + Colors::Add(255, 255, 255); // 7 - White + + Colors::Add(0, 0, 0); // 8 - Team color (axis?) + Colors::Add(0, 0, 0); // 9 - Team color (allies?) + + // Custom colors + Colors::Add(211, 84, 0); // 10 - Orange (:) + Colors::Add(0, 255, 200); // 11 - Turqoise (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character! + } + + Colors::~Colors() + { + Colors::ColorTable.clear(); } } diff --git a/src/Components/Modules/Colors.hpp b/src/Components/Modules/Colors.hpp index eb05859a..64baa0a9 100644 --- a/src/Components/Modules/Colors.hpp +++ b/src/Components/Modules/Colors.hpp @@ -1,22 +1,28 @@ -#define Q_IsColorString( p ) ( ( p ) && *( p ) == '^' && *( ( p ) + 1 ) && isdigit( *( ( p ) + 1 ) ) ) // ^[0-9] - namespace Components { class Colors : public Component { public: Colors(); + ~Colors(); const char* GetName() { return "Colors"; }; static void Strip(const char* in, char* out, int max); static std::string Strip(std::string in); + static char Add(uint8_t r, uint8_t g, uint8_t b); + private: static Dvar::Var NewColors; - static void ClientUserinfoChanged(int length); + static void ClientUserinfoChanged(); static char* GetClientName(int localClientNum, int index, char *buf, size_t size); + static void PatchColorLimit(char limit); - static void UpdateColorTable(); + static unsigned int ColorIndex(unsigned char); + static void LookupColor(DWORD* color, char index); + static void LookupColorStub(); + static char* CleanStrStub(char* string); + static std::vector ColorTable; }; } diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 35e512ce..4c5a8e3b 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -186,7 +186,7 @@ namespace Components // intro stuff Utils::Hook::Nop(0x60BEE9, 5); // Don't show legals Utils::Hook::Set(0x60BED2, "unskippablecinematic IW_logo\n"); - Utils::Hook::Nop(0x60BEF6, 5); // Don't reset intro dvar + //Utils::Hook::Nop(0x60BEF6, 5); // Don't reset intro dvar Utils::Hook(0x4D4007, QuickPatch::ShutdownStub, HOOK_CALL).Install()->Quick();