From 2df1dfbadc056d6d26b6098e6a1513e7b8b949c5 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 23 Apr 2019 07:35:18 +0800 Subject: [PATCH] Fixed and improved Use32BitHeadGraphics option: * Fixed the position of the talking head texture when the game res is larger than 640x480. * Added the support to use textures without the need of patching talking head FRM files. --- artifacts/ddraw.ini | 4 +- sfall/Graphics.cpp | 198 +++++++++++++++++++++---------- sfall/Graphics.h | 14 +++ sfall/LoadGameHook.cpp | 13 +- sfall/TalkingHeads.cpp | 261 ++++++++++++++++++++++++++--------------- sfall/TalkingHeads.h | 6 +- sfall/main.cpp | 51 ++------ 7 files changed, 340 insertions(+), 207 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 28960061..a32b4ac7 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -70,7 +70,9 @@ GraphicsHeight=0 ;GPU is faster, but requires v2.0 pixel shader support GPUBlt=0 -;Set to 1 to allow using 32 bit graphics for talking heads +;Set to 1 to allow using 32-bit .png textures for talking heads +;The texture files should be placed in art/heads// (w/o extension) +;The files in the folder should be numbered according to the number of frames in the talking head FRM file (e.g. 0.png - 10.png) ;Requires DX9 graphics mode and v2.0 pixel shader support (see GPUBlt option) Use32BitHeadGraphics=0 diff --git a/sfall/Graphics.cpp b/sfall/Graphics.cpp index 453b4f6c..04984de7 100644 --- a/sfall/Graphics.cpp +++ b/sfall/Graphics.cpp @@ -27,9 +27,6 @@ #endif #endif -#include -#include -#include #include #include #include @@ -51,7 +48,9 @@ typedef IDirect3D9* (_stdcall *D3DCreateProc)(UINT version); static DWORD ResWidth; static DWORD ResHeight; -static DWORD GPUBlt; + +DWORD GPUBlt; +DWORD GraphicsMode; static BYTE* titlesBuffer = nullptr; static DWORD movieHeight = 0; @@ -91,40 +90,42 @@ static IDirect3DTexture9* movieTex = 0; static ID3DXEffect* gpuBltEffect; static const char* gpuEffect= -"texture image;\n" -"texture palette;\n" -"texture head;\n" -"sampler s0 = sampler_state { texture=; MAGFILTER=POINT; MINFILTER=POINT; };\n" -"sampler s1 = sampler_state { texture=; MAGFILTER=POINT; MINFILTER=POINT; };\n" -"sampler s2 = sampler_state { texture=; MAGFILTER=POINT; MINFILTER=POINT; };\n" -"float2 size;\n" -"float2 corner;\n" -"float4 P0( in float2 Tex : TEXCOORD0 ) : COLOR0 {\n" -" float3 result = tex1D(s1, tex2D(s0, Tex).a);\n" -" return float4(result.b, result.g, result.r, 1);\n" -"}\n" -"float4 P1( in float2 Tex : TEXCOORD0 ) : COLOR0 {\n" -" float backdrop = tex2D(s0, Tex).a;\n" -" float3 result;\n" -" if(abs(backdrop-(48.0/255.0))<0.001) {\n" -//" float2 size = float2(388.0/640.0, 200.0/480.0);\n" -//" float2 corner = float2(126.0/640.0, 14.0/480.0);\n" -" result = tex2D(s2, saturate((Tex-corner)/size));\n" -" } else {\n" -" result = tex1D(s1, backdrop);\n" -" result = float3(result.b, result.g, result.r);\n" -" }\n" -" return float4(result.r, result.g, result.b, 1);\n" -"}\n" -"technique T0\n" -"{\n" -" pass p0 { PixelShader = compile ps_2_0 P0(); }\n" -"}\n" -"technique T1\n" -"{\n" -" pass p1 { PixelShader = compile ps_2_0 P1(); }\n" -"}\n" -; + "texture image;" + "texture palette;" + "texture head;" + "sampler s0 = sampler_state { texture=; };" + "sampler s1 = sampler_state { texture=; };" + "sampler s2 = sampler_state { texture=; minFilter=linear; magFilter=linear; addressU=clamp; addressV=clamp; };" + "float2 size;" + "float2 corner;" + + // shader for displaying head textures + "float4 P1( in float2 Tex : TEXCOORD0 ) : COLOR0 {" + " float backdrop = tex2D(s0, Tex).a;" + " float3 result;" + " if(abs(backdrop - 1.0) < 0.001) {" // (48.0 / 255.0) // 48 - key index color + " result = tex2D(s2, saturate((Tex - corner) / size));" + " } else {" + " result = tex1D(s1, backdrop);" + " result = float3(result.b, result.g, result.r);" + " }" + " return float4(result.r, result.g, result.b, 1);" + "}" + + "technique T1" + "{" + " pass p1 { PixelShader = compile ps_2_0 P1(); }" + "}" + + "float4 P0( in float2 Tex : TEXCOORD0 ) : COLOR0 {" + " float3 result = tex1D(s1, tex2D(s0, Tex).a);" + " return float4(result.b, result.g, result.r, 1);" + "}" + + "technique T0" + "{" + " pass p0 { PixelShader = compile ps_2_0 P0(); }" + "}"; static D3DXHANDLE gpuBltBuf; static D3DXHANDLE gpuBltPalette; @@ -134,8 +135,6 @@ static D3DXHANDLE gpuBltHeadCorner; static float rcpres[2]; -DWORD GraphicsMode; - struct sShader { ID3DXEffect* Effect; bool Active; @@ -173,10 +172,23 @@ void GetFalloutWindowInfo(DWORD* width, DWORD* height, HWND* wnd) { *wnd = window; } +long Gfx_GetGameWidthRes() { + return ptr_scr_size->offx - (ptr_scr_size->x + 1); +} + +long Gfx_GetGameHeightRes() { + return ptr_scr_size->offy - (ptr_scr_size->y + 1); +} + int _stdcall GetShaderVersion() { return ShaderVersion; } +void rcpresInit() { + rcpres[0] = 1.0f / (float)Gfx_GetGameWidthRes(); + rcpres[1] = 1.0f / (float)Gfx_GetGameHeightRes(); +} + void _stdcall SetShaderMode(DWORD d, DWORD mode) { if (d >= shaders.size() || !shaders[d].Effect) return; if (mode & 0x80000000) { @@ -187,7 +199,7 @@ void _stdcall SetShaderMode(DWORD d, DWORD mode) { } int _stdcall LoadShader(const char* path) { - if ((GraphicsMode < 4) || (strstr(path, "..")) || (strstr(path, ":"))) return -1; + if (!GraphicsMode || strstr(path, "..") || strstr(path, ":")) return -1; char buf[MAX_PATH]; sprintf(buf, "%s\\shaders\\%s", *(char**)_patches, path); for (DWORD d = 0; d < shaders.size(); d++) { @@ -301,9 +313,12 @@ static void ResetDevice(bool CreateNew) { D3DXCreateEffect(d3d9Device, gpuEffect, strlen(gpuEffect), 0, 0, 0, 0, &gpuBltEffect, 0); gpuBltBuf = gpuBltEffect->GetParameterByName(0, "image"); gpuBltPalette = gpuBltEffect->GetParameterByName(0, "palette"); + // for head textures gpuBltHead = gpuBltEffect->GetParameterByName(0, "head"); gpuBltHeadSize = gpuBltEffect->GetParameterByName(0, "size"); gpuBltHeadCorner = gpuBltEffect->GetParameterByName(0, "corner"); + + Gfx_SetDefaultTechnique(); } } else { d3d9Device->Reset(¶ms); @@ -548,19 +563,32 @@ void _stdcall PlayMovieFrame() { Present(); } -void _stdcall SetHeadTex(IDirect3DTexture9* tex, int width, int height, int xoff, int yoff) { - if (tex) { - gpuBltEffect->SetTexture(gpuBltHead, tex); - float size[2]; - size[0] = ((float)width)*rcpres[0]; - size[1] = ((float)height)*rcpres[1]; - gpuBltEffect->SetFloatArray(gpuBltHeadSize, size, 2); - size[0] = (126.0f + xoff + (388 - width) / 2)*rcpres[0]; - size[1] = (14.0f + yoff + (200 - height) / 2)*rcpres[1]; - gpuBltEffect->SetFloatArray(gpuBltHeadCorner, size, 2); - gpuBltEffect->SetTechnique("T1"); - } else - gpuBltEffect->SetTechnique("T0"); +void Gfx_SetHeadTex(IDirect3DTexture9* tex, int width, int height, int xoff, int yoff) { + gpuBltEffect->SetTexture(gpuBltHead, tex); + + float size[2]; + size[0] = (float)width * rcpres[0]; + size[1] = (float)height * rcpres[1]; + gpuBltEffect->SetFloatArray(gpuBltHeadSize, size, 2); + + // adjust head texture position for HRP 4.1.8 + int h = Gfx_GetGameHeightRes(); + if (h > 480) yoff += ((h - 480) / 2) - 47; + xoff += ((Gfx_GetGameWidthRes() - 640) / 2); + + size[0] = (126.0f + xoff + ((388 - width) / 2)) * rcpres[0]; + size[1] = (14.0f + yoff + ((200 - height) / 2)) * rcpres[1]; + gpuBltEffect->SetFloatArray(gpuBltHeadCorner, size, 2); + + Gfx_SetHeadTechnique(); +} + +void Gfx_SetHeadTechnique() { + gpuBltEffect->SetTechnique("T1"); +} + +void Gfx_SetDefaultTechnique() { + gpuBltEffect->SetTechnique("T0"); } void GraphicsResetOnGameLoad() { @@ -700,7 +728,7 @@ public: if (y < yoffset || y > bottom) { int yyp = (y - yoffset) * pitch; int yw = y * width; - for (DWORD x = 0; x < width; x++) { + for (DWORD x = 0; x < width; x++) { ((DWORD*)dRect.pBits)[yyp + x] = palette[titlesBuffer[yw + x]]; } } @@ -959,8 +987,6 @@ public: if (!d3d9Device) { ResetDevice(true); CoInitialize(0); - - if (GPUBlt) HeadsInit(); } dlog("Creating D3D9 Device window...", DL_MAIN); @@ -983,15 +1009,15 @@ public: return DD_OK; } - HRESULT _stdcall SetDisplayMode(DWORD, DWORD, DWORD) { return DD_OK; } + HRESULT _stdcall SetDisplayMode(DWORD, DWORD, DWORD) { return DD_OK; } HRESULT _stdcall WaitForVerticalBlank(DWORD, HANDLE) { UNUSEDFUNCTION; } }; HRESULT _stdcall FakeDirectDrawCreate2(void*, IDirectDraw** b, void*) { dlog("Initializing Direct3D...", DL_MAIN); - ResWidth = *(DWORD*)0x4CAD6B; - ResHeight = *(DWORD*)0x4CAD66; + ResWidth = *(DWORD*)0x4CAD6B; // 640 + ResHeight = *(DWORD*)0x4CAD66; // 480 if (!d3d9) { d3d9 = Direct3DCreate9(D3D_SDK_VERSION); @@ -1022,22 +1048,64 @@ HRESULT _stdcall FakeDirectDrawCreate2(void*, IDirectDraw** b, void*) { gHeight = ResHeight; } GPUBlt = GetPrivateProfileIntA("Graphics", "GPUBlt", 0, ini); - if (!GPUBlt || GPUBlt > 2) GPUBlt = 2; //Swap them around to keep compatibility with old ddraw.ini's - else if (GPUBlt == 2) GPUBlt = 0; + if (!GPUBlt || GPUBlt > 2) GPUBlt = 2; // Swap them around to keep compatibility with old ddraw.ini's + else if (GPUBlt == 2) GPUBlt = 0; // Use CPU if (GraphicsMode == 5) { ScrollWindowKey = GetPrivateProfileInt("Input", "WindowScrollKey", 0, ini); } else ScrollWindowKey = 0; - rcpres[0] = 1.0f / (float)gWidth; - rcpres[1] = 1.0f / (float)gHeight; - *b = (IDirectDraw*)new FakeDirectDraw2(); dlogr(" Done.", DL_MAIN); return DD_OK; } +static double fadeMulti; +static __declspec(naked) void palette_fade_to_hook() { + __asm { + push ebx; // _fade_steps + fild [esp]; + fmul fadeMulti; + fistp [esp]; + pop ebx; + jmp fadeSystemPalette_; + } +} + +void GraphicsInit() { + GraphicsMode = GetPrivateProfileIntA("Graphics", "Mode", 0, ini); + if (GraphicsMode != 4 && GraphicsMode != 5) { + GraphicsMode = 0; + } + if (GraphicsMode == 4 || GraphicsMode == 5) { + dlog("Applying DX9 graphics patch.", DL_INIT); +#ifdef WIN2K +#define _DLL_NAME "d3dx9_42.dll" +#else +#define _DLL_NAME "d3dx9_43.dll" +#endif + HMODULE h = LoadLibraryEx(_DLL_NAME, 0, LOAD_LIBRARY_AS_DATAFILE); + if (!h) { + MessageBoxA(0, "You have selected graphics mode 4 or 5, but " _DLL_NAME " is missing\nSwitch back to mode 0, or install an up to date version of DirectX", "Error", 0); + ExitProcess(-1); + } else { + FreeLibrary(h); + } +#undef _DLL_NAME + SafeWrite8(0x50FB6B, '2'); // Set call DirectDrawCreate2 + dlogr(" Done", DL_INIT); + } + + fadeMulti = GetPrivateProfileIntA("Graphics", "FadeMultiplier", 100, ini); + if (fadeMulti != 100) { + dlog("Applying fade patch.", DL_INIT); + HookCall(0x493B16, palette_fade_to_hook); + fadeMulti = ((double)fadeMulti) / 100.0; + dlogr(" Done", DL_INIT); + } +} + void GraphicsExit() { if (GraphicsMode != 0) { if (titlesBuffer) delete[] titlesBuffer; diff --git a/sfall/Graphics.h b/sfall/Graphics.h index 9987aa31..fd9fb68d 100644 --- a/sfall/Graphics.h +++ b/sfall/Graphics.h @@ -18,10 +18,24 @@ #pragma once +#include +#include +#include + extern DWORD GraphicsMode; +extern DWORD GPUBlt; + void GraphicsResetOnGameLoad(); +void GraphicsInit(); void GraphicsExit(); +long Gfx_GetGameWidthRes(); +long Gfx_GetGameHeightRes(); +void Gfx_SetHeadTex(IDirect3DTexture9* tex, int width, int height, int xoff, int yoff); +void Gfx_SetHeadTechnique(); +void Gfx_SetDefaultTechnique(); +void rcpresInit(); + int _stdcall GetShaderVersion(); int _stdcall LoadShader(const char*); void _stdcall ActivateShader(DWORD); diff --git a/sfall/LoadGameHook.cpp b/sfall/LoadGameHook.cpp index 985caa33..ad134d0d 100644 --- a/sfall/LoadGameHook.cpp +++ b/sfall/LoadGameHook.cpp @@ -258,16 +258,25 @@ static void __declspec(naked) EndLoadHook() { } } -static void _stdcall GameInitialized() { +static void __stdcall GameInitialization() { MusicVolInitialization(); } +static void __stdcall GameInitialized() { + rcpresInit(); + if (Use32BitTalkingHeads) TalkingHeadsSetup(); +} + static void __declspec(naked) GameInitHook() { __asm { + pushadc; + call GameInitialization; + popadc; + call main_init_system_; pushadc; call GameInitialized; popadc; - jmp main_init_system_; + retn; } } diff --git a/sfall/TalkingHeads.cpp b/sfall/TalkingHeads.cpp index 2815f4c6..7cbcf62e 100644 --- a/sfall/TalkingHeads.cpp +++ b/sfall/TalkingHeads.cpp @@ -16,21 +16,17 @@ * along with this program. If not, see . */ -#include "main.h" - -#include -#include #include #include -#include "FalloutEngine.h" -void _stdcall SetHeadTex(IDirect3DTexture9* tex, int width, int height, int xoff, int yoff); +#include "main.h" + +#include "FalloutEngine.h" +#include "Graphics.h" + +#include "TalkingHeads.h" extern IDirect3DDevice9* d3d9Device; -static stdext::hash_map<__int64, IDirect3DTexture9**> texMap; -typedef stdext::hash_map<__int64, IDirect3DTexture9**> :: iterator tex_itr; -typedef stdext::hash_map<__int64, IDirect3DTexture9**> :: const_iterator tex_citr; -static BYTE overridden=0; #pragma pack(push, 1) struct Frm { @@ -61,127 +57,204 @@ struct Frm { }; }; }; -struct Frame { - WORD width; - WORD height; - DWORD size; - WORD xoffset; - WORD yoffset; - BYTE data[1]; -}; #pragma pack(pop) -static Frame* FramePointer(const Frm* frm, int frameno) { - Frame* result; - __asm { - mov eax, frm; - mov edx, frameno; - xor ebx, ebx; - call frame_ptr_; - mov result, eax; - } - return result; +struct TextureData { + IDirect3DTexture9** textures; + BYTE showHighlights; + BYTE bakedBackground; + int frames; + + TextureData(IDirect3DTexture9** tex, BYTE show, BYTE baked, int frames) + : textures(tex), showHighlights(show), bakedBackground(baked), frames(frames) {} +}; + +typedef stdext::hash_map<__int64, TextureData> :: iterator tex_itr; +typedef stdext::hash_map<__int64, TextureData> :: const_iterator tex_citr; + +static stdext::hash_map<__int64, TextureData> texMap; + +static const char* headSuffix[] = { "gv", "gf", "gn", "ng", "nf", "nb", "bn", "bf", "bv", "gp", "np", "bp" }; + +static BYTE showHighlights; +static long reactionID; + +bool Use32BitTalkingHeads = false; + +/* Head FID + 0-000-1000-00000000-0000-000000000000 + ID3 Type ID2 ID1 .lst index +*/ +static bool GetHeadFrmName(char* name) { + int headFid = (*(DWORD*)_lips_draw_head) + ? *ptr_lipsFID + : *ptr_fidgetFID; + int index = headFid & 0xFFF; + if (index >= ptr_art[8].total) return true; // OBJ_TYPE_HEAD + int ID2 = (*(DWORD*)_fidgetFp) ? (headFid & 0xFF0000) >> 16 : reactionID; + if (ID2 > 11) return true; + int ID1 = (ID2 == 1 || ID2 == 4 || ID2 == 7) ? (headFid & 0xF000) >> 12 : -1; + //if (ID1 > 3) ID1 = 3; + const char* headLst = ptr_art[8].names; // OBJ_TYPE_HEAD + char* fmt = (ID1 != -1) ? "%s%s%d" : "%s%s"; + _snprintf(name, 8, fmt, &headLst[13 * index], headSuffix[ID2], ID1); + return false; } -static void LoadFrm(Frm* frm) { - tex_citr itr=texMap.find(frm->key); - if(itr==texMap.end()) { - //Load textures +static void StrAppend(char* buf, const char* str, int pos) { + int i = 0; + while (pos < MAX_PATH && str[i]) buf[pos++] = str[i++]; + buf[pos] = str[i]; // copy '\0' +} + +static bool LoadFrm(Frm* frm) { // backporting WIP + if (!frm->key && GetHeadFrmName(frm->path)) { + frm->broken = 1; + return false; + } + tex_citr itr = texMap.find(frm->key); + if (itr == texMap.end()) { + // Loading head frames textures + *(DWORD*)_bk_disabled = 1; char buf[MAX_PATH]; - IDirect3DTexture9** textures=new IDirect3DTexture9*[frm->frames]; + int pathLen = sprintf_s(buf, "%s\\art\\heads\\%s\\", *(char**)_patches, frm->path); + if (pathLen > 250) return false; + IDirect3DTexture9** textures = new IDirect3DTexture9*[frm->frames]; for (int i = 0; i < frm->frames; i++) { - sprintf(buf, "%s\\art\\heads\\%s\\%d.png", *(char**)_patches, frm->path, i); + sprintf(&buf[pathLen], "%d.png", i); if (FAILED(D3DXCreateTextureFromFileExA(d3d9Device, buf, 0, 0, 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, 0, 0, &textures[i]))) { - for(int j=0;jRelease(); + for (int j = 0; j < i; j++) textures[j]->Release(); delete[] textures; - frm->broken=1; - return; + frm->broken = 1; + *(DWORD*)_bk_disabled = 0; + return false; } + ProcessBk(); // eliminate lag when loading textures } - frm->textures=textures; - texMap[frm->key]=textures; + if (frm->magic != 0xABCD) { // frm file not patched + StrAppend(buf, "highlight.off", pathLen); + if (GetFileAttributes(buf) != INVALID_FILE_ATTRIBUTES) frm->showHighlights = 1; // disable highlights + StrAppend(buf, "background.off", pathLen); + if (GetFileAttributes(buf) != INVALID_FILE_ATTRIBUTES) frm->bakedBackground = 1; // fills entire frame surface with a key-color + } + frm->textures = textures; + texMap.insert(std::make_pair(frm->key, TextureData(textures, frm->showHighlights, frm->bakedBackground, frm->frames))); + *(DWORD*)_bk_disabled = 0; } else { - //Use preloaded textures - frm->textures=itr->second; + // Use preloaded textures + frm->textures = itr->second.textures; + frm->showHighlights = itr->second.showHighlights; + frm->bakedBackground = itr->second.bakedBackground; } - //mask image - for(int i=0;iframes;i++) { - Frame* frame=FramePointer(frm, i); - if(frm->bakedBackground) { - memset(frame->data, 0x30, frame->size); + // make mask image + for (int i = 0; i < frm->frames; i++) { + FrmSubframeData* frame = FramePtr((FrmFrameData*)frm, i, 0); + if (frm->bakedBackground) { + memset(frame->data, 255, frame->size); } else { - for(DWORD j=0;jsize;j++) { - if(frame->data[j]) frame->data[j]=0x30; + for (DWORD j = 0; j < frame->size; j++) { + if (frame->data[j]) frame->data[j] = 255; // set index color } } } - frm->loaded=1; + frm->loaded = 1; + return true; } -static void _stdcall DrawFrmHookInternal(Frm* frm, int frameno) { - if(!frm) return; - if(frm->magic==0xabcd&&!frm->broken) { - if(!frm->loaded) LoadFrm(frm); - if(frm->broken) return; - Frame* frame=FramePointer(frm, frameno); - SetHeadTex(frm->textures[frameno], frame->width, frame->height, frame->xoffset+frm->xshift, frame->yoffset+frm->yshift); - overridden=!frm->showHighlights; - } else overridden=0; +static void __fastcall DrawHeadFrame(Frm* frm, int frameno) { + if (frm && !frm->broken) { + if (!frm->loaded && !LoadFrm(frm)) goto loadFail; + FrmSubframeData* frame = FramePtr((FrmFrameData*)frm, frameno, 0); + Gfx_SetHeadTex(frm->textures[frameno], frame->width, frame->height, frame->x + frm->xshift, frame->y + frm->yshift/*, (frm->showHighlights == 2)*/); + showHighlights = frm->showHighlights; + return; + } +loadFail: + showHighlights = 0; // show vanilla highlights + Gfx_SetDefaultTechnique(); } -static const DWORD gdDisplayFrameRet=0x44AD06; -static void __declspec(naked) DrawFrmHook() { +static const DWORD gdDisplayFrameRet = 0x44AD06; +static void __declspec(naked) gdDisplayFrame_hack() { __asm { push edx; push eax; - push edx; - push eax; - call DrawFrmHookInternal; - pop eax; - pop edx; - sub esp, 0x38; - mov esi, eax; - jmp gdDisplayFrameRet; + mov ecx, eax; // frm file + call DrawHeadFrame; // edx - frameno + pop eax; + pop edx; + sub esp, 0x38; + mov esi, eax; + jmp gdDisplayFrameRet; } } -static const DWORD EndSpeechHookRet=0x447299; -void __declspec(naked) EndSpeechHook() { +void __declspec(naked) gdDestroyHeadWindow_hack() { __asm { - push label; - push ebx; - push ecx; - push edx; - push edi; - push ebp; - jmp EndSpeechHookRet; -label: - xor eax, eax; - push eax; - push eax; - push eax; - push eax; - push eax; - call SetHeadTex; + call Gfx_SetDefaultTechnique; + mov showHighlights, 0; + pop ebp; + pop edi; + pop edx; + pop ecx; + pop ebx; retn; } } static void __declspec(naked) TransTalkHook() { __asm { - cmp overridden, 0; - jne skip; - jmp talk_to_translucent_trans_buf_to_buf_; + test showHighlights, 0xFF; + jnz skip; + jmp talk_to_translucent_trans_buf_to_buf_; skip: retn 0x18; } } -void HeadsInit() { - if (GetPrivateProfileInt("Graphics", "Use32BitHeadGraphics", 0, ini)) { - HookCall(0x44AFB4, &TransTalkHook); - HookCall(0x44B00B, &TransTalkHook); - MakeJump(0x44AD01, DrawFrmHook); - MakeJump(0x447294, EndSpeechHook); +static void __declspec(naked) gdPlayTransition_hook() { + __asm { + mov reactionID, ebx; + jmp art_id_; + } +} + +static void __declspec(naked) gdialogInitFromScript_hook() { + __asm { + cmp dword ptr ds:[_dialogue_head], -1; + jnz noScroll; + jmp tile_scroll_to_; +noScroll: + retn; + } +} + +void TalkingHeadsSetup() { + if (!GPUBlt) return; + + HookCall(0x44AFB4, TransTalkHook); + HookCall(0x44B00B, TransTalkHook); + MakeJump(0x44AD01, gdDisplayFrame_hack); // Draw Frm + MakeJump(0x4472F8, gdDestroyHeadWindow_hack); + HookCall(0x44768B, gdPlayTransition_hook); +} + +void TalkingHeadsInit() { + // Disable centering the screen if NPC has talking head + HookCall(0x445224, gdialogInitFromScript_hook); + + if (GraphicsMode && GetPrivateProfileInt("Graphics", "Use32BitHeadGraphics", 0, ini)) { + Use32BitTalkingHeads = true; + } +} + +void TalkingHeadsExit() { + if (!texMap.empty()) { + for (tex_citr it = texMap.begin(); it != texMap.end(); ++it) { + for (int i = 0; i < it->second.frames; i++) { + it->second.textures[i]->Release(); + } + delete[] it->second.textures; + } } } diff --git a/sfall/TalkingHeads.h b/sfall/TalkingHeads.h index b6ae737b..c5e4484c 100644 --- a/sfall/TalkingHeads.h +++ b/sfall/TalkingHeads.h @@ -1 +1,5 @@ -void HeadsInit(); \ No newline at end of file +extern bool Use32BitTalkingHeads; + +void TalkingHeadsSetup(); +void TalkingHeadsInit(); +void TalkingHeadsExit(); diff --git a/sfall/main.cpp b/sfall/main.cpp index f6eba69e..da4640b5 100644 --- a/sfall/main.cpp +++ b/sfall/main.cpp @@ -228,20 +228,6 @@ static __declspec(naked) void PathfinderFix() { } } -static double FadeMulti; -static __declspec(naked) void palette_fade_to_hook() { - __asm { - //pushf; - push ebx; - fild [esp]; - fmul FadeMulti; - fistp [esp]; - pop ebx; - //popf; - jmp fadeSystemPalette_; - } -} - static int mapSlotsScrollMax = 27 * (17 - 7); static __declspec(naked) void ScrollCityListFix() { __asm { @@ -875,6 +861,12 @@ static void DllMain2() { dlogr("Running SpeedPatchInit().", DL_INIT); SpeedPatchInit(); + dlogr("Running GraphicsInit().", DL_INIT); + GraphicsInit(); + + dlogr("Running TalkingHeadsInit().", DL_INIT); + TalkingHeadsInit(); + //if (GetPrivateProfileIntA("Input", "Enable", 0, ini)) { dlog("Applying input patch.", DL_INIT); SafeWriteStr(0x50FB70, "ddraw.dll"); @@ -882,36 +874,6 @@ static void DllMain2() { dlogr(" Done", DL_INIT); //} - GraphicsMode = GetPrivateProfileIntA("Graphics", "Mode", 0, ini); - if (GraphicsMode != 4 && GraphicsMode != 5) { - GraphicsMode = 0; - } - if (GraphicsMode == 4 || GraphicsMode == 5) { - dlog("Applying DX9 graphics patch.", DL_INIT); -#ifdef WIN2K -#define _DLL_NAME "d3dx9_42.dll" -#else -#define _DLL_NAME "d3dx9_43.dll" -#endif - HMODULE h = LoadLibraryEx(_DLL_NAME, 0, LOAD_LIBRARY_AS_DATAFILE); - if (!h) { - MessageBoxA(0, "You have selected graphics mode 4 or 5, but " _DLL_NAME " is missing\nSwitch back to mode 0, or install an up to date version of DirectX", "Error", 0); - ExitProcess(-1); - } else { - FreeLibrary(h); - } -#undef _DLL_NAME - SafeWrite8(0x50FB6B, '2'); // Set call DirectDrawCreate2 - dlogr(" Done", DL_INIT); - } - FadeMulti = GetPrivateProfileIntA("Graphics", "FadeMultiplier", 100, ini); - if (FadeMulti != 100) { - dlog("Applying fade patch.", DL_INIT); - HookCall(0x493B16, palette_fade_to_hook); - FadeMulti = ((double)FadeMulti) / 100.0; - dlogr(" Done", DL_INIT); - } - dlogr("Running DamageModInit().", DL_INIT); DamageModInit(); @@ -1606,6 +1568,7 @@ static void _stdcall OnExit() { HeroAppearanceModExit(); MoviesExit(); GraphicsExit(); + TalkingHeadsExit(); //SoundExit(); }