Exemple #1
0
Render::Render(int screenWidth, int screenHeight, bool fullscreen, wchar_t* windowTitle)
{
	dimension2d<u32> screenRes;

	screenRes = GetDesktopRes();

	screenRes.Width = 800;
	screenRes.Height = 600;

	this->screenWidth = screenRes.Width;
	this->screenHeight = screenRes.Height;

	//this->screenWidth = screenWidth;
	//this->screenHeight = screenHeight;
	//screenRes = dimension2d<u32>(screenWidth, screenHeight);

	device = createDevice(video::EDT_DIRECT3D9, screenRes, 32, false, false, false, NULL);
	device->setResizable(true);
	if (!device)
		return;
	device->setWindowCaption(windowTitle);

	driver = device->getVideoDriver();
	smgr = device->getSceneManager();
	
	animationEndCallBack = new CAnimationEndCallBack();

	instance = this;
}
void Init()
{
    CIniReader iniReader("");
    int ResX = iniReader.ReadInteger("MAIN", "ResX", 0);
    int ResY = iniReader.ReadInteger("MAIN", "ResY", 0);

    if (!ResX || !ResY)
        std::tie(ResX, ResY) = GetDesktopRes();

    injector::WriteMemory(0x403DA2, ResX, true);
    injector::WriteMemory(0x403DAC, ResY, true);

    injector::WriteMemory(0x40949A, ResX, true);
    injector::WriteMemory(0x409495, ResY, true);

    injector::WriteMemory(0x432B8C, ResX, true);
    injector::WriteMemory(0x432B91, ResY, true);

    injector::WriteMemory(0x4553FC, ResX, true);
    injector::WriteMemory(0x455406, ResY, true);

    injector::WriteMemory(0x90B9DC, ResX, true);
    injector::WriteMemory(0x90B9E0, ResY, true);

    injector::WriteMemory(0xA0A930, ResX, true);
    injector::WriteMemory(0xA0A934, ResY, true);

    injector::WriteMemory<float>(0x552487 + 0x1, (float)ResX / (float)ResY, true);
    injector::WriteMemory<float>(0x55248E + 0x1, (float)ResX / (float)ResY, true);
}
void Init()
{
    CIniReader iniReader("");
    Screen.Width = iniReader.ReadInteger("MAIN", "ResX", 0);
    Screen.Height = iniReader.ReadInteger("MAIN", "ResY", 0);

    if (!Screen.Width || !Screen.Height)
        std::tie(Screen.Width, Screen.Height) = GetDesktopRes();

    Screen.fWidth = static_cast<float>(Screen.Width);
    Screen.fHeight = static_cast<float>(Screen.Height);
    Screen.fAspectRatio = (Screen.fWidth / Screen.fHeight);

    auto pattern = hook::pattern("68 58 02 00 00 68 20 03 00 00");
    injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(1), Screen.Width, true);
    injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(6), Screen.Height, true);

    pattern = hook::pattern("BE 20 03 00 00");
    for (size_t i = 0; i < pattern.size(); ++i)
    {
        injector::WriteMemory(pattern.get(i).get<uint32_t>(1), Screen.Width, true);
    }
    pattern = hook::pattern("BF 58 02 00 00");
    for (size_t i = 0; i < pattern.size(); ++i)
    {
        injector::WriteMemory(pattern.get(i).get<uint32_t>(1), Screen.Height, true);
    }

    pattern = hook::pattern("74 22 48 75 25 68");
    injector::WriteMemory<uint8_t>(pattern.count(1).get(0).get<uint32_t>(0), 0xEB, true);

    pattern = hook::pattern("83 7D F0 02 75 ? 8B 45 08");
    injector::WriteMemory<uint8_t>(pattern.count(1).get(0).get<uint32_t>(4), 0xEB, true);


    pattern = hook::pattern("C7 45 D0 20 03 00 00");
    for (size_t i = 0; i < pattern.size(); ++i)
    {
        injector::WriteMemory(pattern.get(i).get<uint32_t>(3), Screen.Width, true);
    }

    pattern = hook::pattern("C7 45 D4 58 02 00 00");
    for (size_t i = 0; i < pattern.size(); ++i)
    {
        injector::WriteMemory(pattern.get(i).get<uint32_t>(3), Screen.Height, true);
    }

    pattern = hook::pattern("C7 85 5C FF FF FF 20 03 00 00");
    injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(6), Screen.Width, true);
    pattern = hook::pattern("C7 85 60 FF FF FF 58 02 00 00");
    injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(6), Screen.Height, true);

    Screen.fAspectRatio = (Screen.fHeight / Screen.fWidth);
    pattern = hook::pattern("D9 05 ? ? ? ? 83 EC 10 D9 5C 24 0C");
    injector::WriteMemory<float>(*pattern.count(1).get(0).get<uint32_t*>(2), Screen.fAspectRatio, true);
}
void Init()
{
    CIniReader iniReader("");
    int ResX = iniReader.ReadInteger("MAIN", "ResX", 0);
    int ResY = iniReader.ReadInteger("MAIN", "ResY", 0);
    bool FixHud = iniReader.ReadInteger("MAIN", "FixHud", 1) != 0;

    if (!ResX || !ResY)
        std::tie(ResX, ResY) = GetDesktopRes();

    //game
    injector::WriteMemory(0x4028DE + 0x2, ResX, true);
    injector::WriteMemory(0x4028E4 + 0x2, ResY, true);

    injector::WriteMemory<uint8_t>(0x4028C2, 0xEB, true);

    injector::WriteMemory(0x40A7E2 + 0x6, ResX, true);
    injector::WriteMemory(0x40A7EC + 0x6, ResY, true);

    injector::WriteMemory(0x781394, ResX, true);
    injector::WriteMemory(0x781398, ResY, true);

    struct Hook1
    {
        void operator()(injector::reg_pack& regs)
        {
            regs.eax = *(DWORD*)0x0252CAC8;
            *(float*)(regs.edi + 0x60) = fWidthScale;
        }
    }; injector::MakeInline<Hook1>(0x6CDB8E);

    injector::WriteMemory<uint8_t>(0x6CDBB9, 0x70, true);

    fAspectRatio = (float)ResX / (float)ResY;
    fWidthScale = ((1.0f / fAspectRatio) * (4.0f / 3.0f));
    fHUDScaleX = ((1.0f / (480.0f * (fAspectRatio))) * 10.0f) / 8.0f;
    fTextScaleX = ((1.0f / (480.0f * (fAspectRatio))) * 10.0f) / 4.0f;
    fComboScale = 64.0f / ((fAspectRatio) / (4.0f / 3.0f));

    //HUD
    if (FixHud)
    {
        injector::WriteMemory<float>(0x7491DC, fHUDScaleX, true);
        injector::WriteMemory(0x406E40 - 0x6B + 0x2, &fTextScaleX, true);
        injector::WriteMemory(0x406E40 - 0x45 + 0x2, &fTextScaleX, true);

        injector::WriteMemory(0x65374C + 0x1, static_cast<int>(320.0f + (200.0f / (0.001953125 / fHUDScaleX))), true);
        injector::WriteMemory(0x6536F7 + 0x2, &fComboScale, true);
    }
}
void Init()
{
    CIniReader iniReader("");
    Screen.fCustomFieldOfView = iniReader.ReadFloat("MAIN", "FOVFactor", 1.0f);
    static float fDrawDistanceFactor = iniReader.ReadFloat("MAIN", "DrawDistanceFactor", 1.0f);
    int32_t nMinResX = iniReader.ReadInteger("MAIN", "MinResX", 0);
    int32_t nMinResY = iniReader.ReadInteger("MAIN", "MinResY", 0);

    std::tie(Screen.DesktopResW, Screen.DesktopResH) = GetDesktopRes();

    //uncapping resolutions
    auto pattern = hook::pattern("68 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? 57 8B DE E8 ? ? ? ? 85 C0"); //54A5A0
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 0), INT_MAX, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 5), INT_MAX, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 10), nMinResY, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 15), nMinResX, true);

    pattern = hook::pattern("68 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? 50 E8 ? ? ? ? 85"); //57F665
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 0), INT_MAX, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 5), INT_MAX, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 10), nMinResY, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 15), nMinResX, true);

    pattern = hook::pattern("68 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? 68 ? ? ? ? 50 33 DB E8"); //5C9288
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 0), INT_MAX, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 5), INT_MAX, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 10), nMinResY, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(1 + 15), nMinResX, true);

    //default to desktop res
    pattern = hook::pattern("EB ? C7 04 24 ? ? ? ? C7 44 24 04"); //54A7C7
    injector::MakeNOP(pattern.get_first(0), 2, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(5 + 0), Screen.DesktopResW, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(5 + 8), Screen.DesktopResH, true);
    pattern = hook::pattern("56 57 56 56 68 ? ? ? ? 68 ? ? ? ? 56 56"); //576C6B
    injector::WriteMemory(pattern.get_first<int32_t*>(5), Screen.DesktopResH, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(10), Screen.DesktopResW, true);

    //1024x768 black screen fix
    pattern = hook::pattern("C7 44 24 28 ? ? ? ? C7 44 24 2C ? ? ? ? C7 44 24 30 ? ? ? ? C7 44 24 34 ? ? ? ? 89 16 E8"); //0x57F6DF
    injector::WriteMemory(pattern.get_first<int32_t*>(4 + 0), Screen.DesktopResW, true);
    injector::WriteMemory(pattern.get_first<int32_t*>(4 + 8), Screen.DesktopResH, true);

    static auto pGameHwnd = *hook::get_pattern<HWND*>("A1 ? ? ? ? 85 C0 55 8B E9", 1); //0x7EC218
    static auto pAspectRatio = *hook::get_pattern<float*>("D9 05 ? ? ? ? EB ? D9 05 ? ? ? ? 8B 75 0C", 2); //78EA70
    static auto pFOV = *hook::get_pattern<float*>("D9 05 ? ? ? ? EB 06 D9 05 ? ? ? ? 33 C0", 2); //78EA78
    static auto dword_8D7DF0 = *hook::get_pattern<uintptr_t*>("8B 0D ? ? ? ? 8B 44 24 14 8D 54 24 2C", 2);
    static auto pGameResWidth = dword_8D7DF0 + 2;
    static auto pGameResHeight = dword_8D7DF0 + 3;
    //Screen.FMVStatus = *hook::get_pattern<int32_t*>("BE ? ? ? ? 33 C0 B9 20 01 00 00 8B FE F3 AB", 1) + 0x1D; // 0x70C8B8?

    static auto GetRes = []()
    {
        Screen.Width = *pGameResWidth;
        Screen.Height = *pGameResHeight;
        Screen.fWidth = static_cast<float>(Screen.Width);
        Screen.fHeight = static_cast<float>(Screen.Height);
        Screen.fAspectRatio = (Screen.fWidth / Screen.fHeight);
        Screen.Width43 = static_cast<uint32_t>(Screen.fHeight * (4.0f / 3.0f));
        Screen.fWidth43 = static_cast<float>(Screen.Width43);
        Screen.fCenterPos = ((480.0f * Screen.fAspectRatio) / 2.0f);
        Screen.fHudOffset = ((480.0f * Screen.fAspectRatio) - 640.0f) / 2.0f;
        Screen.fHudOffsetReal = (Screen.fWidth - Screen.fHeight * (4.0f / 3.0f)) / 2.0f;
        Screen.fCutOffArea = 1.0f; //?

        injector::WriteMemory<float>(pAspectRatio, Screen.fAspectRatio, true); //*pAspectRatio = Screen.fAspectRatio;
        injector::WriteMemory<float>(pFOV, AdjustFOV(1.04f, Screen.fAspectRatio) * (Screen.fCustomFieldOfView ? Screen.fCustomFieldOfView : 1.0f), true);

        Screen.fGameAspectRatio = (4.0f / 3.0f);

        static tagRECT REKT;
        REKT.left = (LONG)(((float)Screen.DesktopResW / 2.0f) - (Screen.fWidth / 2.0f));
        REKT.top = (LONG)(((float)Screen.DesktopResH / 2.0f) - (Screen.fHeight / 2.0f));
        REKT.right = (LONG)Screen.Width;
        REKT.bottom = (LONG)Screen.Height;
        SetWindowPos(*pGameHwnd, NULL, REKT.left, REKT.top, REKT.right, REKT.bottom, SWP_NOACTIVATE | SWP_NOZORDER);
    };

    pattern = hook::pattern("89 8B 80 01 00 00"); //0x5E4C73
    struct GetResHook2
    {
        void operator()(injector::reg_pack& regs)
        {
            *(uint32_t*)(regs.ebx + 0x180) = regs.ecx;
            if (Screen.Width && Screen.Height)
            {
                Screen.Width = *(uint32_t*)(regs.ebx + 0x160);
                Screen.Height = *(uint32_t*)(regs.ebx + 0x164);
            }
            GetRes();
        }
    };
    injector::MakeInline<GetResHook2>(pattern.count(2).get(0).get<void*>(0), pattern.count(2).get(0).get<void*>(6));
    injector::MakeInline<GetResHook2>(pattern.count(2).get(1).get<void*>(0), pattern.count(2).get(1).get<void*>(6));

    pattern = hook::pattern("8B 44 24 04 89 41 ? B0 01 C2 04 00"); //0x580C00
    struct MenuAspectRatioSwitchHook
    {
        void operator()(injector::reg_pack& regs)
        {
            *(uint32_t*)(regs.ecx + 0x14) = WIDE16BY9; //*(uint32_t*)(regs.esp + 0x04);
        }
    }; injector::MakeInline<MenuAspectRatioSwitchHook>(pattern.get_first(0), pattern.get_first(7));

    //2D
    pattern = hook::pattern("89 56 DC 83 C0 01 D9 5E D4 89 44 24 10"); //0x57E5BD
    static auto dword_53F06F = (uint32_t)hook::get_pattern("80 BE 40 02 00 00 00", 0);
    static auto dword_53F08A = (uint32_t)hook::get_pattern("8D 46 3C 53 E8 ? ? ? ? 5F", 9);
    static auto dword_540F2E = (uint32_t)hook::get_pattern("8D 86 9C 01 00 00 51 E8 ? ? ? ? C2", 12);
    struct HudHook
    {
        void operator()(injector::reg_pack& regs)
        {
            auto retAddr = *(uint32_t*)(regs.esp + 0x4C);
            *(uint32_t*)(regs.esi - 0x24) = regs.edx;
            regs.eax += 1;
            float temp = 0.0f;
            _asm {fstp dword ptr[temp]}
            *(float*)(regs.esi - 0x2C) = temp;

            auto x1 = *(float*)(*(DWORD*)(regs.edi + 8) + (regs.ebp - 0x30) + 0x10);
            auto x2 = *(float*)(*(DWORD *)(regs.edi + 8) + (regs.ebp - 0x30) + 24) + *(float *)((regs.ebp - 0x30) + *(DWORD *)(regs.edi + 8) + 16);
            auto x3 = *(float *)((regs.esi - 0x90) + 0x4C) + *(float *)((regs.esi - 0x90) + 0x4C);

            if (retAddr == dword_53F06F || retAddr == dword_53F08A) //radar border and overlay
            {
                //*(float*)((regs.esi - 0x90) - 0x14) /= (Screen.fAspectRatio / Screen.fGameAspectRatio) / 1.33333f;
                //*(float*)((regs.esi - 0x90) + 0x04) /= (Screen.fAspectRatio / Screen.fGameAspectRatio) / 1.33333f;
                //*(float*)((regs.esi - 0x90) + 0x1C) /= (Screen.fAspectRatio / Screen.fGameAspectRatio) / 1.33333f;
                //*(float*)((regs.esi - 0x90) + 0x34) /= (Screen.fAspectRatio / Screen.fGameAspectRatio) / 1.33333f;
                //*(float*)((regs.esi - 0x44) + 0x00) /= (Screen.fAspectRatio / Screen.fGameAspectRatio) / 1.33333f;
                //*(float*)((regs.esi - 0x2C) + 0x00) /= (Screen.fAspectRatio / Screen.fGameAspectRatio) / 1.33333f;
            }
            else
            {
                if (x1 == 0.0f && x2 == 1.0f && retAddr == dword_540F2E) //fading
                {
                    //
                }
                else
                {
                    *(float*)((regs.esi - 0x90) - 0x14) /= (Screen.fAspectRatio / Screen.fGameAspectRatio);
                    *(float*)((regs.esi - 0x90) + 0x04) /= (Screen.fAspectRatio / Screen.fGameAspectRatio);
                    *(float*)((regs.esi - 0x90) + 0x1C) /= (Screen.fAspectRatio / Screen.fGameAspectRatio);
                    *(float*)((regs.esi - 0x90) + 0x34) /= (Screen.fAspectRatio / Screen.fGameAspectRatio);
                    *(float*)((regs.esi - 0x44) + 0x00) /= (Screen.fAspectRatio / Screen.fGameAspectRatio);
                    *(float*)((regs.esi - 0x2C) + 0x00) /= (Screen.fAspectRatio / Screen.fGameAspectRatio);
                }
            }
        }
    }; injector::MakeInline<HudHook>(pattern.get_first(0), pattern.get_first(9));


    //Radar
    pattern = hook::pattern("89 9E EC 01 00 00 89 9E F0 01 00 00"); //0x53DE73
    struct RadarHook
    {
        void operator()(injector::reg_pack& regs)
        {
            *(uint32_t*)(regs.esi + 0x1EC) = regs.ebx;
            *(uint32_t*)(regs.esi + 0x1F0) = regs.ebx;

            auto t = Screen.fWidth - (128.0f * (Screen.fWidth / 640.0f)); //1596.0f;//Screen.fWidth * (1920.0 - ); //1596
            auto t2 = Screen.fWidth - t; //1920-1569=351
            auto t3 = t2 / (Screen.fAspectRatio / Screen.fGameAspectRatio); //131.625
            auto t4 = Screen.fWidth - 24.0f - 24.0f - t3;
            auto t5 = 1.0f / (Screen.fWidth / (24.0f + t3));
            auto t6 = 1.0f / (Screen.fWidth / t4);

            if (*(float*)(regs.esi + 0x0C) == 0.0f && *(float*)(regs.esi + 0x14) == 1.0f)
            {
                *(float*)(regs.esi + 0x0C) += 1.0f / (Screen.fWidth / Screen.fHudOffsetReal);
                *(float*)(regs.esi + 0x14) -= 1.0f / (Screen.fWidth / Screen.fHudOffsetReal);
                *(float*)(regs.esi + 0x14) -= 1.0f / (Screen.fWidth / Screen.fHudOffsetReal);
            }
            else
            {
                *(float*)(regs.esi + 0x0C) = t6;
                *(float*)(regs.esi + 0x14) = t5;
            }
        }
    }; injector::MakeInline<RadarHook>(pattern.get_first(0), pattern.get_first(12));

    //Object disappearance sorta fix
    pattern = hook::pattern("D9 83 80 01 00 00 ? ? ? 01 00 00");
    injector::WriteMemory<uint8_t>(pattern.count(2).get(0).get<void*>(2), 0x84i8, true); //0x57D4C2
    injector::WriteMemory<uint8_t>(pattern.count(2).get(1).get<void*>(2), 0x84i8, true); //0x57D505

    //Draw distance adjuster
    if (fDrawDistanceFactor)
    {
        pattern = hook::pattern("89 46 7C 89 4E 08 C3"); //0x4DDD68
        struct DrawDistHook
        {
            void operator()(injector::reg_pack& regs)
            {
                *(uint32_t*)(regs.esi + 0x7C) = regs.eax;
                *(uint32_t*)(regs.esi + 0x08) = regs.ecx;

                //*(float*)(regs.esi + 0x88) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0x84) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0x90) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0x94) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0xA0) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0x9C) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0xA8) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0xAC) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0xB4) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0xB8) *= fDrawDistanceFactor;
                //*(float*)(regs.esi + 0xC0) *= fDrawDistanceFactor;

                *(float*)(regs.esi + 0x44) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x48) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x4C) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x40) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x50) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x54) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x58) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x5C) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x60) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x64) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x68) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x6C) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x70) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x74) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x78) *= fDrawDistanceFactor;
                *(float*)(regs.esi + 0x7C) *= fDrawDistanceFactor;
            }
        };
        injector::MakeInline<DrawDistHook>(pattern.count(3).get(0).get<void*>(0), pattern.count(3).get(0).get<void*>(6));
        injector::MakeInline<DrawDistHook>(pattern.count(3).get(1).get<void*>(0), pattern.count(3).get(1).get<void*>(6));
        injector::MakeInline<DrawDistHook>(pattern.count(3).get(2).get<void*>(0), pattern.count(3).get(2).get<void*>(6));
    }

    //Sane default controls
    pattern = hook::pattern("89 0D ? ? ? ? 5B 83 C4 50 C3"); //0x6DEB7A
    static auto dword_7A4E5C = *hook::pattern("BE 00 40 00 00 A3").count(2).get(1).get<uint8_t*>(6);
    struct DefControlsHook
    {
        void operator()(injector::reg_pack& regs)
        {
            copyControlsData(dword_7A4E5C);
        }
    }; injector::MakeInline<DefControlsHook>(pattern.count(2).get(1).get<void*>(0), pattern.count(2).get(1).get<void*>(6));
}
void Init()
{
    CIniReader iniReader("");
    Screen.Width = iniReader.ReadInteger("MAIN", "ResX", 0);
    Screen.Height = iniReader.ReadInteger("MAIN", "ResY", 0);
    bool bFixHUD = iniReader.ReadInteger("MAIN", "FixHUD", 1) != 0;
    bool bFixFOV = iniReader.ReadInteger("MAIN", "FixFOV", 1) != 0;
    uint32_t nGameSpeed = iniReader.ReadInteger("MISC", "GameSpeed", 30);

    if (!Screen.Width || !Screen.Height)
        std::tie(Screen.Width, Screen.Height) = GetDesktopRes();

    Screen.fWidth = static_cast<float>(Screen.Width);
    Screen.fHeight = static_cast<float>(Screen.Height);
    Screen.fAspectRatio = (Screen.fWidth / Screen.fHeight);
    Screen.fHudOffset = (0.5f / ((4.0f / 3.0f) / (Screen.fAspectRatio)));
    Screen.Width43 = static_cast<uint32_t>(Screen.fHeight * (4.0f / 3.0f));

    auto pattern = hook::pattern("A3 ? ? ? ? E8 ? ? ? ? 84 C0 74 38 8B 0D");
    static auto dword_6B75A0_Y = *pattern.count(1).get(0).get<uint32_t*>(1);
    static auto dword_6B759C_X = dword_6B75A0_Y - 1;
    struct ResHook1
    {
        void operator()(injector::reg_pack& regs)
        {
            *dword_6B759C_X = Screen.Width;
            *dword_6B75A0_Y = Screen.Height;
        }
    }; injector::MakeInline<ResHook1>(pattern.get_first());

    pattern = hook::pattern("A3 ? ? ? ? E8 ? ? ? ? 6A 00 68 ? ? ? ? 8D 4C 24 14");
    struct ResHook2
    {
        void operator()(injector::reg_pack& regs)
        {
            *dword_6B759C_X = Screen.Width;
            *dword_6B75A0_Y = Screen.Height;
        }
    }; injector::MakeInline<ResHook2>(pattern.get_first());

    auto pSetAR = injector::GetBranchDestination(hook::pattern("E8 ? ? ? ? D8 1D ? ? ? ? D9 44 24").count(1).get(0).get<uintptr_t>(0), true).as_int(); //0x4BA680
    Screen.DefaultAR = *(float**)(pSetAR + 2);
    injector::MakeJMP(pSetAR, SetAspect, true);

    if (bFixHUD)
    {
        Screen.fHudScaleX = 1.0f / Screen.fWidth * (Screen.fHeight / 480.0f);
        Screen.fHudOffset = (Screen.fWidth - Screen.fHeight * (4.0f / 3.0f)) / 2.0f;

        pattern = hook::pattern("D8 0D ? ? ? ? 8B 35 ? ? ? ? 85 F6 D9 1D");
        injector::WriteMemory<float>(*pattern.count(1).get(0).get<float*>(2), Screen.fHudScaleX, true); //0x6814CC

        struct TextHudHook
        {
            void operator()(injector::reg_pack& regs)
            {
                float fCurOffset = 0.0f;
                _asm
                {
                    fadd    st, st(1)
                    fstp    dword ptr[fCurOffset]
                }
                *(float*)(regs.esp + 0x28) = fCurOffset + Screen.fHudOffset;

            }
        };
        pattern = hook::pattern("D8 C1 D9 5C 24 28 DB 05 ? ? ? ? D9 47 2C");  //0x4DC226
        injector::MakeInline<TextHudHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.get(0).get<uint32_t>(6));

        pattern = hook::pattern("D8 C1 D9 5C 24 28 D9 05 ? ? ? ? D8");  //0x4F12DB
        injector::MakeInline<TextHudHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.get(0).get<uint32_t>(6));

        pattern = hook::pattern("D8 C1 D9 5C 24 18 DD D8 DD D8 DD D8");  //0x4F12E9
        struct HudHook2
        {
            void operator()(injector::reg_pack& regs)
            {
                float fCurOffset = 0.0f;
                _asm
                {
                    fadd    st, st(1)
                    fstp    dword ptr[fCurOffset]
                }
                *(float*)(regs.esp + 0x18) = fCurOffset + Screen.fHudOffset;
            }
        }; injector::MakeInline<HudHook2>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(6));

        pattern = hook::pattern("D8 44 24 20 D9 5C 24 60 0F 84 7A 03 00 00");  //0x4F1BD7
        struct HudHook3
        {
            void operator()(injector::reg_pack& regs)
            {
                float temp1 = *(float*)(regs.esp + 0x20);
                float temp2 = 0.0f;
                _asm
                {
                    fadd    dword ptr[temp1]
                    fstp    dword ptr[temp2]
                }
                *(float*)(regs.esp + 0x60) = temp2;
                *(float*)(regs.esp + 0x5C) += Screen.fHudOffset;
                *(float*)(regs.esp + 0x6C) += Screen.fHudOffset;
                *(float*)(regs.esp + 0x7C) += Screen.fHudOffset;
                *(float*)(regs.esp + 0x8C) += Screen.fHudOffset;
            }
        }; injector::MakeInline<HudHook3>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(8));
        injector::WriteMemory<uint16_t>(pattern.count(1).get(0).get<uint32_t>(6), 0xC084, true); //test    al, al

        pattern = hook::pattern("D8 C1 D9 5C 24 14 DD D8");  //0x4F0D06
        struct HudHook4
        {
            void operator()(injector::reg_pack& regs)
            {
                float temp1 = 0.0f;
                _asm
                {
                    fadd    st, st(1)
                    fstp    dword ptr[temp1]
                }
                *(float*)(regs.esp + 0x14) = temp1 + Screen.fHudOffset;
                *(float*)(regs.esp + 0x18) += Screen.fHudOffset;
            }
        }; injector::MakeInline<HudHook4>(pattern.count(2).get(1).get<uint32_t>(0), pattern.count(2).get(1).get<uint32_t>(6));

        pattern = hook::pattern("D8 C2 8B F0 D8 05 ? ? ? ? D8 0D ? ? ? ? D8"); //main menu cursor fix
        injector::WriteMemory<uint8_t>(pattern.count(1).get(0).get<uintptr_t>(2), 0xC0, true); //0x4FC837
        injector::WriteMemory<uint8_t>(pattern.count(1).get(0).get<uintptr_t>(17), 0xC0, true); //0x4FC847
    }

    if (bFixFOV)
    {
        pattern = hook::pattern("D9 9E C4 00 00 00 E8 ? ? ? ? D9 86 C4 00 00 00 5E 59 C3"); //0x498BA9
        struct FovHook
        {
            void operator()(injector::reg_pack& regs)
            {
                float fov = 0.0f;
                _asm {fstp dword ptr[fov]}
                *(float*)(regs.esi + 0xC4) = AdjustFOV(fov, Screen.fAspectRatio);
            }
        }; injector::MakeInline<FovHook>(pattern.get_first(), pattern.get_first(6));
    }

    if (nGameSpeed)
    {
        pattern = hook::pattern("C7 05 ? ? ? ? 1E 00 00 00"); //0x52E7CA
        injector::WriteMemory(pattern.count(1).get(0).get<uintptr_t>(6), nGameSpeed, true);
    }
    //43F8B8 - fps
}
void Init()
{
    CIniReader iniReader("");
    Screen.Width = iniReader.ReadInteger("MAIN", "ResX", 0);
    Screen.Height = iniReader.ReadInteger("MAIN", "ResY", 0);
    bool bFixHUD = iniReader.ReadInteger("MAIN", "FixHUD", 1) != 0;
    bool bFixFOV = iniReader.ReadInteger("MAIN", "FixFOV", 1) != 0;
    bool bRandomSongOrderFix = iniReader.ReadInteger("MAIN", "RandomSongOrderFix", 1) != 0;

    if (!Screen.Width || !Screen.Height)
        std::tie(Screen.Width, Screen.Height) = GetDesktopRes();

    Screen.fWidth = static_cast<float>(Screen.Width);
    Screen.fHeight = static_cast<float>(Screen.Height);
    Screen.Width43 = static_cast<int32_t>(Screen.fHeight * (4.0f / 3.0f));
    Screen.fAspectRatio = (Screen.fWidth / Screen.fHeight);
    Screen.fAspectRatioDiff = 1.0f / (Screen.fAspectRatio / (4.0f / 3.0f));
    Screen.fHUDScaleX = 1.0f / Screen.fWidth * (Screen.fHeight / 480.0f);
    Screen.fHudOffset = ((480.0f * Screen.fAspectRatio) - 640.0f) / 2.0f;
    Screen.fHudOffsetReal = (Screen.fWidth - Screen.fHeight * (4.0f / 3.0f)) / 2.0f;

    //Resolution
    auto pattern = hook::pattern("89 0D ? ? ? ? 89 15 ? ? ? ? 89 0D ? ? ? ? 89 15 ? ? ? ? 74");
    static int32_t* dword_67FBCC = *pattern.get_first<int32_t*>(2);
    static int32_t* dword_67FBD0 = *pattern.get_first<int32_t*>(8);
    static int32_t* dword_787A7C = *pattern.get_first<int32_t*>(12 + 2);
    static int32_t* dword_787A80 = *pattern.get_first<int32_t*>(12 + 8);
    struct SetResHook
    {
        void operator()(injector::reg_pack& regs)
        {
            *dword_67FBCC = Screen.Width;
            *dword_67FBD0 = Screen.Height;
            *dword_787A7C = Screen.Width;
            *dword_787A80 = Screen.Height;
        }
    };

    pattern = hook::pattern(pattern_str(0x89, '?', to_bytes(dword_67FBCC)));
    injector::MakeInline<SetResHook>(pattern.get_first(0), pattern.get_first(6));
    pattern = hook::pattern(pattern_str(0xA3, to_bytes(dword_67FBCC)));
    injector::MakeInline<SetResHook>(pattern.get_first(0));
    pattern = hook::pattern(pattern_str(0x89, '?', to_bytes(dword_67FBD0)));
    injector::MakeInline<SetResHook>(pattern.count(2).get(0).get<void*>(0), pattern.count(2).get(0).get<void*>(6));
    injector::MakeInline<SetResHook>(pattern.count(2).get(1).get<void*>(0), pattern.count(2).get(1).get<void*>(6));

    pattern = hook::pattern(pattern_str(0x89, '?', to_bytes(dword_787A7C)));
    injector::MakeNOP(pattern.count(2).get(0).get<void*>(0), 6, true); //injector::MakeInline<SetResHook>(pattern.count(2).get(0).get<void*>(0), pattern.count(2).get(0).get<void*>(6));
    injector::MakeNOP(pattern.count(2).get(1).get<void*>(0), 6, true); //injector::MakeInline<SetResHook>(pattern.count(2).get(1).get<void*>(0), pattern.count(2).get(1).get<void*>(6));

    pattern = hook::pattern(pattern_str(0x89, '?', to_bytes(dword_787A80)));
    injector::MakeNOP(pattern.count(2).get(0).get<void*>(0), 6, true); //injector::MakeInline<SetResHook>(pattern.count(2).get(0).get<void*>(0), pattern.count(2).get(0).get<void*>(6));
    injector::MakeNOP(pattern.count(2).get(1).get<void*>(0), 6, true); //injector::MakeInline<SetResHook>(pattern.count(2).get(1).get<void*>(0), pattern.count(2).get(1).get<void*>(6));

    //Aspect Ratio
    pattern = hook::pattern("68 ? ? ? ? E8 ? ? ? ? 6A 00 68 ? ? ? ? E8 ? ? ? ? D9");
    injector::WriteMemory<float>(pattern.get_first(1), Screen.fAspectRatio, true);
    pattern = hook::pattern("E8 ? ? ? ? D9 04 24 D8 74 24 04 DE C9");
    injector::WriteMemory(injector::GetBranchDestination(pattern.get_first()).as_int() + 2, &Screen.fAspectRatio, true);

    //FOV
    if (bFixFOV)
    {
        pattern = hook::pattern("D9 96 B0 00 00 00 D8 0D ? ? ? ? D9 F2 DD D8"); //0x485B57
        struct FovHook
        {
            void operator()(injector::reg_pack& regs)
            {
                float fov = 0.0f;
                _asm {fst dword ptr[fov]}
                *(float*)(regs.esi + 0xB0) = AdjustFOV(fov, Screen.fAspectRatio);
            }
        }; injector::MakeInline<FovHook>(pattern.get_first(), pattern.get_first(6));
    }

    //HUD
    if (bFixHUD)
    {
        static int32_t nHudOffset = static_cast<int32_t>(Screen.fHudOffsetReal);
        static int32_t* dword_787D88;
        struct SetOffsetHook
        {
            void operator()(injector::reg_pack& regs)
            {
                *dword_787D88 = nHudOffset;
            }
        };

        pattern = hook::pattern("D8 0D ? ? ? ? 89 0D ? ? ? ? 89 15 ? ? ? ? 0F B6 C8");
        injector::WriteMemory<float>(*pattern.get_first<float*>(2), Screen.fHUDScaleX, true);
        dword_787D88 = *hook::get_pattern<int32_t*>("DB 05 ? ? ? ? 57 D9 05 ? ? ? ? 8B F9", 2);

        pattern = hook::pattern(pattern_str(0x89, '?', to_bytes(dword_787D88)));
        for (size_t i = 0; i < pattern.size(); ++i)
            injector::MakeInline<SetOffsetHook>(pattern.get(i).get<uint32_t>(0), pattern.get(i).get<uint32_t>(6));
    }

    if (bRandomSongOrderFix)
    {
        pattern = hook::pattern("83 C4 08 ? D0 07 00 00");
        auto rpattern = hook::range_pattern((uintptr_t)pattern.get_first(3), (uintptr_t)pattern.get_first(110), "75 ? A1");
        static auto dword_69B718 = *rpattern.get_first<int32_t*>(3);
        static auto dword_681D14 = *hook::range_pattern((uintptr_t)pattern.get_first(3), (uintptr_t)pattern.get_first(60), "A1 ? ? ? ?").get_first<int32_t*>(1);
        struct RandomHook
        {
            void operator()(injector::reg_pack& regs)
            {
                auto num_songs = *dword_681D14;
                int32_t* sp_xbox_randomized_songs = dword_69B718;

                std::vector<int32_t> songs;
                songs.assign(std::addressof(sp_xbox_randomized_songs[0]), std::addressof(sp_xbox_randomized_songs[num_songs]));
                std::mt19937 r{ std::random_device{}() };
                std::shuffle(std::begin(songs), std::end(songs), r);

                std::copy(songs.begin(), songs.end(), sp_xbox_randomized_songs);
            }
        }; injector::MakeInline<RandomHook>(pattern.get_first(3), rpattern.get_first(2));
    }
}
void Init()
{
    CIniReader iniReader("");
    Screen.Width = iniReader.ReadInteger("MAIN", "ResX", 0);
    Screen.Height = iniReader.ReadInteger("MAIN", "ResY", 0);
    bool bFixHUD = iniReader.ReadInteger("MAIN", "FixHUD", 1) != 0;

    if (!Screen.Width || !Screen.Height)
        std::tie(Screen.Width, Screen.Height) = GetDesktopRes();

    Screen.fWidth = static_cast<float>(Screen.Width);
    Screen.fHeight = static_cast<float>(Screen.Height);
    Screen.Width43 = static_cast<int32_t>(Screen.fHeight * (4.0f / 3.0f));
    Screen.fAspectRatio = (Screen.fWidth / Screen.fHeight);
    Screen.fHudOffset = ((480.0f * Screen.fAspectRatio) - 640.0f) / 2.0f;
    Screen.fHudOffsetReal = (Screen.fWidth - Screen.fHeight * (4.0f / 3.0f)) / 2.0f;

    auto pattern = hook::pattern("A3 ? ? ? ? E8 ? ? ? ? 8B 15 ? ? ? ? A1 ? ? ? ? 6A 10"); //4F3FEE
    static int32_t* dword_29D6FE8 = *pattern.get_first<int32_t*>(1);
    static int32_t* dword_29D6FE4 = *pattern.get_first<int32_t*>(17);

    struct SetResHook1
    {
        void operator()(injector::reg_pack& regs)
        {
            *dword_29D6FE4 = Screen.Width;
            *dword_29D6FE8 = Screen.Height;
        }
    }; injector::MakeInline<SetResHook1>(pattern.get_first(0));

    pattern = hook::pattern("A3 ? ? ? ? 8B 0D ? ? ? ? 6A 10 51 50"); //4F54A4
    struct SetResHook2
    {
        void operator()(injector::reg_pack& regs)
        {
            *dword_29D6FE4 = Screen.Width;
            *dword_29D6FE8 = Screen.Height;
        }
    }; injector::MakeInline<SetResHook2>(pattern.get_first(0));

    pattern = hook::pattern("89 0D ? ? ? ? 8D 34 49"); //46463F
    static int32_t* dword_55ED00 = *pattern.get_first<int32_t*>(2);
    pattern = hook::pattern("A3 ? ? ? ? ? ? 8D 04 49 33 D2");
    static int32_t* dword_55ED18 = *pattern.get_first<int32_t*>(1);
    pattern = hook::pattern("C7 05 ? ? ? ? 00 10 00 00 5E A3");
    static int32_t* dword_5606CC = *pattern.get_first<int32_t*>(2);
    static int32_t* dword_5606D0 = *pattern.get_first<int32_t*>(12);
    struct AspectRatioHook
    {
        void operator()(injector::reg_pack& regs)
        {
            *dword_55ED00 = Screen.Width;
            *dword_55ED18 = Screen.Height;
            *dword_5606D0 = 4096;
            *dword_5606CC = 4096;
        }
    };
    pattern = hook::pattern("E8 ? ? ? ? 83 C4 08 E8 ? ? ? ? 5E 5B 83 C4 08 C3"); //0x430466
    injector::MakeInline<AspectRatioHook>(pattern.get_first(0));
    pattern = hook::pattern("E8 ? ? ? ? 83 C4 08 53 56"); //0x4645B8
    injector::MakeInline<AspectRatioHook>(pattern.get_first(0));

    //FOV
    Screen.FOV = static_cast<int32_t>(4096.0f / (Screen.fAspectRatio / (4.0f / 3.0f)));
    pattern = hook::pattern("F7 3D ? ? ? ? 33 C9 66 8B 4E"); //45E9E9
    injector::WriteMemory(pattern.get_first(2), &Screen.FOV, true);

    //Main menu wheel fix
    auto sub_4F0A70 = [](int16_t a1) -> int32_t
    {
        return (int32_t)(cos((float)(a1 & 0xFFF) * 0.00024414062f * 6.2831855f) * (4096.0f / (Screen.fHeight / 480.0f)));
    };
    pattern = hook::pattern("E8 ? ? ? ? 53 89 44 24 1C 89");
    injector::MakeCALL(pattern.get_first(0), static_cast<int32_t(*)(int16_t)>(sub_4F0A70), true); //0x457939
    pattern = hook::pattern("E8 ? ? ? ? 0F AF 44 24 20 C1");
    injector::MakeCALL(pattern.get_first(0), static_cast<int32_t(*)(int16_t)>(sub_4F0A70), true); //0x457992

    auto sub_4F0AA0 = [](int16_t a1) -> int32_t
    {
        return (int32_t)(sin((float)(a1 & 0xFFF) * 0.00024414062f * 6.2831855f) * (4096.0f / (Screen.fHeight / 480.0f)));
    };
    pattern = hook::pattern("E8 ? ? ? ? 8B F0 53 0F AF");
    injector::MakeCALL(pattern.get_first(0), static_cast<int32_t(*)(int16_t)>(sub_4F0AA0), true); //0x457947
    pattern = hook::pattern("E8 ? ? ? ? 8B 5D 0C 89 44");
    injector::MakeCALL(pattern.get_first(0), static_cast<int32_t(*)(int16_t)>(sub_4F0AA0), true); //0x45795D

    if (bFixHUD)
    {
        //menu backgrounds
        pattern = hook::pattern("A1 ? ? ? ? 81 EC 98"); //4D4BA0
        auto sub_4D4BA0 = pattern.get_first(0);
        static auto dword_29D6FF0 = *pattern.get_first<uint32_t*>(1);
        struct MenuHook1
        {
            void operator()(injector::reg_pack& regs)
            {
                regs.eax = *dword_29D6FF0;
                *(float*)(regs.esp + 0x8) += Screen.fHudOffset;
            }
        }; injector::MakeInline<MenuHook1>(sub_4D4BA0);

        auto rpattern = hook::range_pattern((uintptr_t)sub_4D4BA0, (uintptr_t)sub_4D4BA0 + 0x414, pattern_str(0xA1, to_bytes(dword_29D6FE4))); //mov     eax, dword_29D6FE4
        for (size_t i = 0; i < rpattern.size(); ++i)
        {
            //0x4D4CEF, 0x4D4D51, 0x4D4D8A, 0x4D4DBD, 0x4D4E4F, 0x4D4E82, 0x4D4EBB
            injector::WriteMemory(rpattern.get(i).get<uint32_t>(1), &Screen.Width43, true);
        }

        //some menu things
        pattern = hook::pattern("C7 41 28 00 00 80 BF"); //457C0E
        struct MenuHook2
        {
            void operator()(injector::reg_pack& regs)
            {
                *(int16_t*)(regs.ecx + 0x08) += (int16_t)Screen.fHudOffsetReal;
                *(int16_t*)(regs.ecx + 0x10) += (int16_t)Screen.fHudOffsetReal;
                *(int16_t*)(regs.ecx + 0x18) += (int16_t)Screen.fHudOffsetReal;
                *(int16_t*)(regs.ecx + 0x20) += (int16_t)Screen.fHudOffsetReal;
                *(float*)(regs.ecx + 0x28) = -1.0f;
            }
        };

        for (size_t i = 0; i < pattern.size(); ++i)
        {
            injector::MakeInline<MenuHook2>(pattern.get(i).get<uint32_t>(0), pattern.get(i).get<uint32_t>(7));

            rpattern = hook::range_pattern((uintptr_t)pattern.get(i).get<uint32_t>(-0x170), (uintptr_t)pattern.get(i).get<uint32_t>(0), pattern_str(0x0F, 0xAF, '?', to_bytes(dword_29D6FE4))); //imul    e?x, dword_29D6FE4
            for (size_t i = 0; i < rpattern.size(); ++i)
            {
                injector::WriteMemory(rpattern.get(i).get<uint32_t>(3), &Screen.Width43, true);
            }
        }
    }
}
void Init()
{
    if (PatchRegistryFuncs())
        return;

    CIniReader iniReader("");
    Screen.Width = iniReader.ReadInteger("MAIN", "ResX", 0);
    Screen.Height = iniReader.ReadInteger("MAIN", "ResY", 0);
    static int32_t RenderResX = iniReader.ReadInteger("MAIN", "RenderResX", -1);
    static int32_t RenderResY = iniReader.ReadInteger("MAIN", "RenderResY", -1);
    bool bFixMenu = iniReader.ReadInteger("MAIN", "FixMenu", 1) != 0;
    bool bFixFMV = iniReader.ReadInteger("MAIN", "FixFMV", 1) != 0;
    static int32_t nFMVWidescreenMode = iniReader.ReadInteger("MISC", "FMVWidescreenMode", 1);
    bool bDisableCutsceneBorders = iniReader.ReadInteger("MISC", "DisableCutsceneBorders", 1) != 0;
    bool bDisableSafeMode = iniReader.ReadInteger("MISC", "DisableSafeMode", 1) != 0;
    bool bPixelationFix = iniReader.ReadInteger("MISC", "PixelationFix", 1) != 0;
    uint32_t nStatusScreenRes = iniReader.ReadInteger("MISC", "StatusScreenRes", 512);
    uint32_t nShadowsRes = iniReader.ReadInteger("MISC", "ShadowsRes", 1024);
    uint32_t nDOFRes = iniReader.ReadInteger("MISC", "DOFRes", 1024);
    bool bFrameRateFluctuationFix = iniReader.ReadInteger("MISC", "FrameRateFluctuationFix", 1) != 0;
    bool bSingleCoreAffinity = iniReader.ReadInteger("MISC", "SingleCoreAffinity", 0) != 0;
    static bool bReduceCutsceneFOV = iniReader.ReadInteger("MISC", "ReduceCutsceneFOV", 1) != 0;
    bool bSH2Reference = iniReader.ReadInteger("MISC", "SH2Reference", 1) != 0;
    static float fFogComplexity = static_cast<float>(iniReader.ReadInteger("MISC", "FogComplexity", 25));

    if (!Screen.Width || !Screen.Height)
        std::tie(Screen.Width, Screen.Height) = GetDesktopRes();

    Screen.fWidth = static_cast<float>(Screen.Width);
    Screen.fHeight = static_cast<float>(Screen.Height);
    Screen.fAspectRatio = (Screen.fWidth / Screen.fHeight);
    Screen.fHudScale = (4.0f / 3.0f) / (Screen.fAspectRatio);

    if (RenderResX >= 0 && RenderResY >= 0)
    {
        auto pattern = hook::pattern("51 A1 ? ? ? ? 53 8B 5C 24 0C"); //00402E00 
        injector::WriteMemory<uint8_t>(pattern.count(1).get(0).get<uint32_t>(0), 0xC3, true);
        pattern = hook::pattern("8B 44 24 04 8B 4C 24 08 A3 ? ? ? ? 89 0D ? ? ? ? 33 C0 C3"); //00402B60
        injector::WriteMemory<uint8_t>(pattern.count(1).get(0).get<uint32_t>(0), 0xC3, true);
        pattern = hook::pattern("8B 07 83 EC 0C 53 33 DB 3B C3 56"); //005E26D0
        injector::MakeRET(pattern.get_first(0));

        if (RenderResX == 0 && RenderResY == 0)
        {
            RenderResX = Screen.Width;
            RenderResY = Screen.Height;
        }
    }

    //Resolution
    static int32_t* ResXAddr1;
    static int32_t* ResXAddr2;
    static int32_t* ResXAddr3;
    static int32_t* ResXAddr4;
    static int32_t* ResYAddr1;
    static int32_t* ResYAddr2;
    static int32_t* ResYAddr3;
    static int32_t* ResYAddr4;
    static float FMVOffset1;
    static float FMVOffset2;
    static float FMVOffset3;

    struct SetResHook
    {
        void operator()(injector::reg_pack&)
        {
            if (RenderResX > 0 && RenderResY > 0)
            {
                *ResXAddr1 = RenderResX;
                *ResYAddr1 = RenderResY;
            }
            *ResXAddr2 = Screen.Width;
            *ResYAddr2 = Screen.Height;
            *ResXAddr3 = Screen.Width;
            *ResYAddr3 = Screen.Height;
            *ResXAddr4 = Screen.Width;
            *ResYAddr4 = Screen.Height;

            if (!nFMVWidescreenMode)
                FMVOffset1 = (float)*ResXAddr1 / (Screen.fWidth / ((Screen.fWidth - Screen.fHeight * (4.0f / 3.0f)) / 2.0f));
            else
                FMVOffset1 = (float)*ResXAddr1 / (Screen.fWidth / ((Screen.fWidth - Screen.fHeight * (nFMVWidescreenMode != 2 ? (964.0f / 622.0f) : (16.0f / 9.0f))) / 2.0f));
            FMVOffset2 = *ResXAddr1 - FMVOffset1;
            FMVOffset3 = (float)*ResYAddr1;
        }
    };

    ResXAddr1 = *hook::pattern("A1 ? ? ? ? 53 8B 5C 24 0C 3B C3 55 8B 6C 24 14").count(1).get(0).get<int32_t*>(1); //72BFD0 rendering res
    ResYAddr1 = ResXAddr1 + 1; //72BFD4
    ResXAddr2 = *hook::pattern("BF ? ? ? ? F3 AB 52").count(1).get(0).get<int32_t*>(1); //0072C664 
    ResYAddr2 = ResXAddr2 + 1; //0072C668
    ResXAddr3 = *hook::pattern("8B 0D ? ? ? ? 8B 44 24 04 3B C8 8B 4C 24 08 75 08 39 0D").count(1).get(0).get<int32_t*>(2); //0072C780 
    ResYAddr3 = ResXAddr3 + 1; //0072C784
    ResXAddr4 = ResYAddr3 + 1; //0072C788 
    ResYAddr4 = ResXAddr4 + 1; //0072C78C

    //pattern = hook::pattern("A3 ? ? ? ? 89 0D ? ? ? ? 33 C0 C3");
    //injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(11)); //402B68
    //pattern = hook::pattern("89 1D ? ? ? ? 89 2D ? ? ? ? E8 ? ? ? ? 8B");
    //injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(12)); //402E3A
    //pattern = hook::pattern("89 35 ? ? ? ? 89 3D ? ? ? ? E8 ? ? ? ? 8B");
    //injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(12)); //402E61
    //pattern = hook::pattern("A3 ? ? ? ? A3 ? ? ? ? E8 ? ? ? ? 83 C4 04");
    //injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(10)); //402E93


    auto pattern = hook::pattern("89 15 ? ? ? ? 8B 10 50 FF 52 3C 85 C0");
    injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(6)); //419622
    pattern = hook::pattern("89 0D ? ? ? ? 89 15 ? ? ? ? E8");
    injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(12)); //4197DE
    pattern = hook::pattern("89 35 ? ? ? ? 5E 33 C0 5B 83 C4 10");
    injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(6)); //419804


    pattern = hook::pattern("A3 ? ? ? ? 89 0D ? ? ? ? A3 ? ? ? ? 89 0D ? ? ? ? C6 05 ? ? ? ? 01");
    injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(22)); //416AFA
    pattern = hook::pattern("89 0D ? ? ? ? 89 0D ? ? ? ? C6 05 ? ? ? ? 01 33 C0 C3");
    injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(12)); //416B4D
    pattern = hook::pattern("A3 ? ? ? ? 89 0D ? ? ? ? A3 ? ? ? ? C7 05 ? ? ? ? 3C 00");
    injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uint32_t>(0), pattern.count(1).get(0).get<uint32_t>(5 + 11)); //418C57


    pattern = hook::pattern("A3 ? ? ? ? 89 0D ? ? ? ? 33 C0 C3");
    injector::MakeInline<SetResHook>(pattern.count(2).get(1).get<uint32_t>(0), pattern.count(2).get(1).get<uint32_t>(11)); //416B78

    //FOV
    Screen.fFieldOfView = (((4.0f / 3.0f) / (Screen.fAspectRatio)));
    static auto byte_81FAB5 = *hook::get_pattern<uint8_t*>("A2 ? ? ? ? A2 ? ? ? ? 74 4D 49", 1);
    pattern = hook::pattern("6A 02 E8 ? ? ? ? 83 C4 04 85 C0 ? ? D9 05 ? ? ? ? C3"); //43AB80 43ABC0
    struct FOVHook1
    {
        void operator()(injector::reg_pack& regs)
        {
            float hor = Screen.fFieldOfView * 0.88f;

            if (bReduceCutsceneFOV && *byte_81FAB5)
                hor /= Screen.fFieldOfView;

            _asm fld dword ptr[hor]
        }
void Init()
{
    CIniReader iniReader("");
    Screen.Width = iniReader.ReadInteger("MAIN", "ResX", 0);
    Screen.Height = iniReader.ReadInteger("MAIN", "ResY", 0);
    bool bFix2D = iniReader.ReadInteger("MAIN", "Fix2D", 1) != 0;
    bool bFixFOV = iniReader.ReadInteger("MAIN", "FixFOV", 1) != 0;
    bool bDisableCutsceneBorders = iniReader.ReadInteger("MAIN", "DisableCutsceneBorders", 1) != 0;
    bool bIncreaseBackgroundRes = iniReader.ReadInteger("MAIN", "IncreaseBackgroundRes", 1) != 0;
    bool bCutsceneFrameRateFix = iniReader.ReadInteger("MAIN", "CutsceneFrameRateFix", 1) != 0;
    bool bDisableCheckSpec = iniReader.ReadInteger("MAIN", "DisableCheckSpec", 1) != 0;
    bool bDisableRegistryDependency = iniReader.ReadInteger("MISC", "DisableRegistryDependency", 1) != 0;
    bool bDisableSafeMode = iniReader.ReadInteger("MISC", "DisableSafeMode", 1) != 0;
    bool bSkipIntro = iniReader.ReadInteger("MISC", "SkipIntro", 1) != 0;
    bool bBrightnessFix = iniReader.ReadInteger("MISC", "BrightnessFix", 1) != 0;

    if (!Screen.Width || !Screen.Height)
        std::tie(Screen.Width, Screen.Height) = GetDesktopRes();

    Screen.fWidth = static_cast<float>(Screen.Width);
    Screen.fHeight = static_cast<float>(Screen.Height);
    Screen.fAspectRatio = (Screen.fWidth / Screen.fHeight);
    Screen.fFieldOfView = ((1.0f / Screen.fAspectRatio) * (4.0f / 3.0f));
    Screen.fHudScale = ((1.0f / Screen.fAspectRatio) * (4.0f / 3.0f));
    Screen.fHudOffset = ((480.0f * Screen.fAspectRatio) - 640.0f) / 2.0f;
    Screen.fHudOffsetReal = (Screen.fWidth - Screen.fHeight * (4.0f / 3.0f)) / 2.0f;

    //Resolution
    static auto nWidthPtr = *hook::pattern("8B 0D ? ? ? ? 6A 00 50 51").count(1).get(0).get<uint32_t*>(2);
    auto pattern = hook::pattern(pattern_str(0xC7, 0x05, to_bytes(nWidthPtr))); //0x4141E3

    for (size_t i = 0; i < pattern.size(); i++)
    {
        injector::WriteMemory(pattern.get(i).get<uint32_t>(6), Screen.Width, true);
    }

    static auto nHeightPtr = *hook::pattern("8B 0D ? ? ? ? 89 44 24 1C 39").count(1).get(0).get<uint32_t*>(2);
    pattern = hook::pattern(pattern_str(0xC7, 0x05, to_bytes(nHeightPtr))); //0x4141ED

    for (size_t i = 0; i < pattern.size(); i++)
    {
        injector::WriteMemory(pattern.get(i).get<uint32_t>(6), Screen.Height, true);
    }

    pattern = hook::pattern("89 35 ? ? ? ? 33 C0 5E C3"); //0x414A38
    struct SetResHook
    {
        void operator()(injector::reg_pack&)
        {
            *nWidthPtr = Screen.Width;
            *nHeightPtr = Screen.Height;
        }
    }; injector::MakeInline<SetResHook>(pattern.count(1).get(0).get<uintptr_t>(0), pattern.count(1).get(0).get<uintptr_t>(6));

    if (bFixFOV)
    {
        pattern = hook::pattern("83 C4 14 68 ? ? ? ? E8 ? ? ? ? 68"); //0x55BC74 
        injector::MakeNOP(pattern.count(1).get(0).get<uint32_t>(8), 5, true);
        injector::WriteMemory<float>(pattern.count(1).get(0).get<uint32_t>(14), Screen.fFieldOfView, true);

        pattern = hook::pattern("C7 46 48 ? ? ? ? C7 46 44"); //0x41D295
        injector::WriteMemory<float>(pattern.count(1).get(0).get<uint32_t>(3), 0.78125f * Screen.fHudScale, true);
    }

    if (bFix2D)
    {
        //Menu scale and disabling of some overlays
        static float fMenuScale = 0.00390625f * Screen.fHudScale;
        pattern = hook::pattern("D8 0D ? ? ? ? 6A 01 8D 54 24 1C 52 D9 5C 24 10 6A 5E"); //0x404E4C + 2
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(2), &fMenuScale, true); // Menu Width

        //in game overlay
        auto ret_512 = []() -> int32_t
        {
            return static_cast<int32_t>(512.0f * Screen.fHudScale);
        };
        pattern = hook::pattern("E8 ? ? ? ? 8B 4C 24 1C 99 2B C2 8B 51 10 D1 F8"); //433C4D
        injector::MakeCALL(pattern.get_first(0), static_cast<int32_t(*)()>(ret_512), true);
        pattern = hook::pattern("E8 ? ? ? ? 8B 7C 24 50 99 2B C2 8B 57 10 D1 F8"); //433CCF
        injector::MakeCALL(pattern.get_first(0), static_cast<int32_t(*)()>(ret_512), true);
        pattern = hook::pattern("DB 44 24 20 D9 5C 24 20 E8 ? ? ? ? 8B 4C 24 1C 99 2B C2 8B 51 14 D1 F8"); //433C69
        struct OverlayWidthHook1
        {
            void operator()(injector::reg_pack& regs)
            {
                float f = 0.0f;
                int32_t n = *(int32_t*)(regs.esp + 0x20);
                _asm {fild dword ptr[n]}
                _asm {fdiv dword ptr[Screen.fHudScale]}
                _asm {fstp dword ptr[f]}
                *(float*)(regs.esp + 0x20) = f;
            }
        }; injector::MakeInline<OverlayWidthHook1>(pattern.get_first(0), pattern.get_first(8));

        pattern = hook::pattern("DB 44 24 50 D9 5C 24 38 E8 ? ? ? ? 8B 4F 14 99 2B C2 D1 F8"); //433CEB
        struct OverlayWidthHook2
        {
            void operator()(injector::reg_pack& regs)
            {
                float f = 0.0f;
                int32_t n = *(int32_t*)(regs.esp + 0x50);
                _asm {fild dword ptr[n]}
                _asm {fdiv dword ptr[Screen.fHudScale]}
                _asm {fstp dword ptr[f]}
                *(float*)(regs.esp + 0x38) = f;
            }
        }; injector::MakeInline<OverlayWidthHook2>(pattern.get_first(0), pattern.get_first(8));

        pattern = hook::pattern("55 8B EC 83 E4 F0 83 EC 64 D9 45 18"); //0x42EAC0
        injector::MakeRET(pattern.get_first());

        pattern = hook::pattern("E8 ? ? ? ? 83 C4 5C C6 05 ? ? ? ? 00 B8"); //0x42E719
        injector::MakeNOP(pattern.get_first(), 5, true); // Cutscene Wall Darkness Effect

        pattern = hook::pattern("E8 ? ? ? ? 83 C4 5C C6 05 ? ? ? ? 00 A1"); //0x45EBD2
        injector::MakeNOP(pattern.get_first(), 5, true); //Cutscene Wall Grunge Effect

        // Text fix
        pattern = hook::pattern("C7 44 24 34 00 00 80 BF D9 5C"); //0x404EBB
        injector::WriteMemory<float>(pattern.count(1).get(0).get<uint32_t>(4), -1.0f * Screen.fHudScale, true); // Text X Pos
        pattern = hook::pattern("C7 44 24 24 CD CC 4C 3B D9 44 24 14"); //0x404E91
        injector::WriteMemory<float>(pattern.count(1).get(0).get<uint32_t>(4), 0.003125f * Screen.fHudScale, true); // Text Width

        //FMV
        pattern = hook::pattern("E8 ? ? ? ? 8B 14 B5 ? ? ? ? A1"); //0x412EAF
        hb_563BF0.fun = injector::MakeCALL(pattern.count(1).get(0).get<uint32_t>(0), FMVHook, true).get();

        //Width
        //sub_563BF0
        auto sub_563BF0 = (uint32_t)hook::pattern("8B 44 24 04 53 8B 5C 24 18 55 8B").count(1).get(0).get<uint32_t>(0);
        pattern = hook::pattern("E8 ? ? ? ?");
        for (size_t i = 0, j = 1; i < pattern.size(); ++i)
        {
            auto addr = pattern.get(i).get<uint32_t>(0);
            auto dest = injector::GetBranchDestination(addr, true).as_int();
            if (dest == sub_563BF0)
            {
                j++;

                if (j == 33 || j == 71 || j == 66 || j == 70) //menu and save menu backgrounds, 1 -> 0x4053C8... http://pastebin.com/Hv6TdTLh
                    continue;

                if (
                    (j >= 44 && j <= 49) || //intro overlay
                    (j >= 56 && j <= 65 && j != 64) //DOF/blur overlay
                    )
                {
                    hb_563BF0.fun = injector::MakeCALL(pattern.get(i).get<uint32_t>(0), sub_563BF0_hook, true).get();
                    continue;
                }

                if (j >= 64) //blur
                {
                    hb_563BF0.fun = injector::MakeCALL(pattern.get(i).get<uint32_t>(0), sub_563BF0_hook2, true).get();
                    continue;
                }

                hbOverlays.fun = injector::MakeCALL(pattern.get(i).get<uint32_t>(0), OverlaysHook, true).get();
            }
        }

        //Cutscene Borders
        static float fBorderWidth = 4096.0f;
        pattern = hook::pattern("DB 05 ? ? ? ? D9 5C 24 08 DB 05 ? ? ? ? D9 5C 24 04 DB 05 ? ? ? ? D9 1C 24"); //0x4F4926
        injector::WriteMemory(pattern.count(2).get(0).get<uint32_t>(2), &fBorderWidth, true);
        injector::WriteMemory(pattern.count(2).get(1).get<uint32_t>(2), &fBorderWidth, true);
        static float fBorderPosX = -2048.0f;
        injector::WriteMemory(pattern.count(2).get(0).get<uint32_t>(22), &fBorderPosX, true);
        injector::WriteMemory(pattern.count(2).get(1).get<uint32_t>(22), &fBorderPosX, true);

        //Map Zoom
        static float fMapZoom = (0.5f / ((4.0f / 3.0f) / (Screen.fAspectRatio)));
        pattern = hook::pattern("D8 0D ? ? ? ? 51 52 6A 00 D9 5C"); //0x0051D6DB
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(2), &fMapZoom, true);

        //Film Effect (loading animation & bathroom hole)
        static float fFilmEffectWidth = 0.1f * ((4.0f / 3.0f) / (Screen.fAspectRatio));
        pattern = hook::pattern("D8 0D ? ? ? ? D8 44 24 14 D9 1C 24 E8 ? ? ? ? 89 44 24 30"); //0x0056807F
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(2), &fFilmEffectWidth, true);
        pattern = hook::pattern("D8 0D ? ? ? ? 8B 44 24 38 89 44 24 34 83 C4 28"); //0x005680F3 
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(2), &fFilmEffectWidth, true);
        pattern = hook::pattern("D8 0D ? ? ? ? D8 44 24 14 D9 1C 24 E8 ? ? ? ? 89 44 24 38"); //0x00568193 
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(2), &fFilmEffectWidth, true);
        pattern = hook::pattern("D8 0D ? ? ? ? 8B 4C 24 38 83 C4 28 89 4C 24 0C D8 44 24 04"); //0x00568207 
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(2), &fFilmEffectWidth, true);

        static float fFilmEffectPos = 0.0f - ((480.0f * Screen.fAspectRatio) - 640.0f) / 2.0f;
        pattern = hook::pattern("C7 44 24 0C 00 00 00 00 C7 44 24 04 00 00 00 00 DF E0"); //0x00567FF8 
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(4), &fFilmEffectPos, true);
        //injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(12), &fFilmEffectPos, true);

        //blood stains
        pattern = hook::pattern("50 51 52 C6 05 ? ? ? ? 01 E8"); //0x565AEC
        injector::MakeNOP(pattern.get_first(10), 5, true);

        //Blur Restoration
        static int32_t n640 = static_cast<int32_t>(round(((640.0f - (640.0f / Screen.fHudScale)) * 8.0f) + (640.0f / Screen.fHudScale)));
        pattern = hook::pattern("B8 80 02 00 00 DB 44 24 34 99 F7 FE"); //0x566A79
        injector::WriteMemory(pattern.get_first(1), n640, true);
    }

    if (bDisableCutsceneBorders)
    {
        static uint32_t nOff = 0;
        pattern = hook::pattern("A1 ? ? ? ? 85 C0 74 ? 6A 02 68"); //0x4F4A0A
        injector::WriteMemory(pattern.count(2).get(0).get<uint32_t>(1), &nOff, true);
        injector::WriteMemory(pattern.count(2).get(1).get<uint32_t>(1), &nOff, true);
        //injector::WriteMemory(0x565053+1, 2048 - 48, true); //borders pos
    }

    if (bIncreaseBackgroundRes)
    {
        pattern = hook::pattern("B8 ? ? ? ? 89 4C 24 28 8B 0D ? ? ? ? 89 44 24 2C"); //0x403320
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(1), Screen.Width, true);
        pattern = hook::pattern("68 ? ? ? ? 68 ? ? ? ? 51 E8 ? ? ? ? 8B 15 ? ? ? ? 83 C4 50"); //0x40362E
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(1), Screen.Width, true);
        injector::WriteMemory(pattern.count(1).get(0).get<uint32_t>(6), Screen.Width, true);

        pattern = hook::pattern("C7 05 ? ? ? ? ? ? ? ? C7 05 ? ? ? ? ? ? ? ? C7 05 ? ? ? ? ? ? ? ? C7 05 ? ? ? ? ? ? ? ? 89 35"); //0055A699
        injector::WriteMemory<float>(pattern.count(6).get(3).get<uint32_t>(0x06), Screen.fWidth - 0.5f, true);
        injector::WriteMemory<float>(pattern.count(6).get(3).get<uint32_t>(0x52), Screen.fWidth - 0.5f, true);
        injector::WriteMemory<float>(pattern.count(6).get(3).get<uint32_t>(0x8A), Screen.fWidth - 0.5f, true);
        injector::WriteMemory<float>(pattern.count(6).get(3).get<uint32_t>(0x94), Screen.fWidth - 0.5f, true);
    }

    if (bCutsceneFrameRateFix)
    {
        pattern = hook::pattern("0F 94 C0 A3 ? ? ? ? EB ? C3"); //0x004EFA85
        injector::WriteMemory<uint8_t>(pattern.count(1).get(0).get<uint32_t>(1), 0x95, true);
    }

    if (bDisableCheckSpec)
    {
        pattern = hook::pattern("8B 15 ? ? ? ? A1 ? ? ? ? 8B 0D ? ? ? ? 89 17 66"); //0x00414688 
        injector::MakeNOP(pattern.count(1).get(0).get<uint32_t>(0), 6, true);
    }

    if (bDisableRegistryDependency)
    {
        auto RegIATpat = hook::pattern("FF 15 ? ? ? ? 8B 44 24 00 50");
        if (RegIATpat.size() > 0)
        {
            RegistryWrapper("KONAMI", "");
            RegistryWrapper::AddPathWriter("Install Path", "Movie Install");
            uintptr_t* RegIAT = *RegIATpat.count(1).get(0).get<uintptr_t*>(2); //0x413D67
            injector::WriteMemory(&RegIAT[0], RegQueryValueExA, true);
            injector::WriteMemory(&RegIAT[1], RegOpenKeyA, true);
            injector::WriteMemory(&RegIAT[2], RegSetValueExA, true);
            injector::WriteMemory(&RegIAT[3], RegDeleteValueA, true);
            injector::WriteMemory(&RegIAT[4], RegCloseKey, true);
        }
    }

    if (bDisableSafeMode)
    {
        pattern = hook::pattern("83 C8 FF 83 C4 10 C3"); //00413E53
        injector::MakeNOP(pattern.get_first(-2), 2, true);
    }

    if (bSkipIntro)
    {
        pattern = hook::pattern("A1 ? ? ? ? 3B C6 0F 84 ? ? ? ? 83 F8 01"); //415180
        static auto dword_107BFE0 = *pattern.get_first<uint32_t*>(1);
        struct GameStateHook
        {
            void operator()(injector::reg_pack& regs)
            {
                static bool once = false;
                if (!once)
                    *dword_107BFE0 = 3;
                regs.eax = *dword_107BFE0;
                once = true;
            }
        }; injector::MakeInline<GameStateHook>(pattern.get_first(0));
    }

    if (bBrightnessFix)
    {
        static constexpr auto fContrastScale = 0.0075f;
        static constexpr auto fBrightnessScale = 0.003875f;
        static constexpr auto gamma = 0x000A0A0A;

        pattern = hook::pattern("D8 0D ? ? ? ? DB 05 ? ? ? ? D8 0D ? ? ? ? 74 10 DD D8 DD D8");
        injector::WriteMemory(pattern.get_first(2), &fContrastScale, true);    // 55A17E
        injector::WriteMemory(pattern.get_first(14), &fBrightnessScale, true); // 55A18A

        pattern = hook::pattern("68 ? ? ? ? C7 05 ? ? ? ? ? ? ? ? E8 ? ? ? ? 8B 44 24 1C");
        injector::WriteMemory(pattern.get_first(1), gamma, true);  // 5226A9
        injector::WriteMemory(pattern.get_first(11), gamma, true); // 5226AE

        pattern = hook::pattern("BE ? ? ? ? 8D 7C 24 0C F3 A5");
        injector::WriteMemory(*pattern.get_first<uint32_t>(1) + 0x1C, gamma, true); // 5C5B10

        pattern = hook::pattern("83 FF 08 7D 2A 47 EB 1A");
        injector::WriteMemory<uint8_t>(pattern.get_first<uint32_t>(2), 0x05, true); // 5222D2
    }
}