diff --git a/artifacts/config_files/Unarmed.ini b/artifacts/config_files/Unarmed.ini index 83693beb..16ccc400 100644 --- a/artifacts/config_files/Unarmed.ini +++ b/artifacts/config_files/Unarmed.ini @@ -1,5 +1,7 @@ ; This file lets you configure the requirements and effects of unarmed attacks +; You can leave the value empty or omit the parameter to use the engine default value + ; Strong Punch [8] ReqLevel=1 ; required player level @@ -18,7 +20,7 @@ MinDamage=1 MaxDamage=2 BonusDamage=3 ; bonus damage added to the minimum and maximum damage BonusCrit=0 ; value of the critical hit chance -APCost= ; you can leave the value empty or omit the parameter to use the engine default value +APCost= Penetrate=0 ; set to 1 to make the attack reduce target's armor DT (the formula is determined by the engine or a hook script) Secondary=0 ; set to 1 to assign the attack to the secondary mode (be careful when setting this parameter) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index f8e610f5..0e0da033 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -113,7 +113,7 @@ ExpandWorldMap=0 ;Set to 1 to draw a dotted line while traveling on the world map (similar to Fallout 1) WorldMapTravelMarkers=0 ;Uncomment these lines to change the appearance of the markers -;The color index in Fallout default palette (valid range: 1..255; default is 134) +;The color index in Fallout default palette (valid range: 1..228; default is 134) ;TravelMarkerColor=134 ;The length and spacing of the dots in pixels for each type of terrain in worldmap.txt ;Syntax is 'length:spacing', with each pair separated by a comma (valid range: 1..10; default is 2) diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index 31df6bb1..a36df9df 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -235,6 +235,7 @@ WRAP_WATCOM_FUNC1(void, scr_build_lookup_table, fo::ScriptInstance*, script) WRAP_WATCOM_FUNC1(fo::ScriptInstance*, scr_find_first_at, long, elevation) WRAP_WATCOM_FUNC0(fo::ScriptInstance*, scr_find_next_at) WRAP_WATCOM_FUNC1(fo::GameObject*, scr_find_obj_from_program, fo::Program*, program) +WRAP_WATCOM_FUNC1(long, scr_find_sid_from_program, fo::Program*, program) WRAP_WATCOM_FUNC2(long, scr_new, long*, scriptID, long, sType) // Saves pointer to script object into scriptPtr using scriptID WRAP_WATCOM_FUNC2(long, scr_ptr, long, scriptId, fo::ScriptInstance**, scriptPtr) // Returns 0 on success, -1 on failure diff --git a/sfall/FalloutEngine/Structs.h b/sfall/FalloutEngine/Structs.h index e9dfea3d..2974cb7e 100644 --- a/sfall/FalloutEngine/Structs.h +++ b/sfall/FalloutEngine/Structs.h @@ -230,7 +230,7 @@ struct GameObject { long lightDistance; long lightIntensity; DWORD outline; - long scriptId; // SID 0x0Y00XXXX: Y - type: 0=s_system, 1=s_spatial, 2=s_time, 3=s_item, 4=s_critter; XXXX - index in scripts.lst; 0xFFFFFFFF no attached script + long scriptId; // SID 0x0Y00XXXX: Y - type: 0=s_system, 1=s_spatial, 2=s_time, 3=s_item, 4=s_critter; XXXX - ID number (1-32000); 0xFFFFFFFF no attached script GameObject* owner; // not saved long scriptIndex; @@ -295,12 +295,12 @@ struct CombatGcsd { // Script instance attached to an object or tile (spatial script). struct ScriptInstance { - long id; + long id; // same as sid long next; long elevationAndTile; // first 3 bits - elevation, rest - tile number long spatialRadius; long flags; - long scriptIdx; + long scriptIdx; // script index in scripts.lst? Program *program; long ownerObjectId; long localVarOffset; // data @@ -313,9 +313,9 @@ struct ScriptInstance { GameObject *targetObject; long actionNum; long scriptOverrides; - long field_48; + long field_48; // unknown long howMuch; - long field_50; + long field_50; // unused long procedureTable[28]; long gap[7]; }; diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index 18807776..cb7abf90 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -193,7 +193,9 @@ #define FO_VAR_movie_list 0x518DA0 #define FO_VAR_Mutate_ 0x5708B4 #define FO_VAR_name_color 0x56D744 +#define FO_VAR_name_critter 0x51833C #define FO_VAR_name_font 0x56D74C +#define FO_VAR_name_item 0x519238 #define FO_VAR_name_sort_list 0x56FCB0 #define FO_VAR_num_caps 0x518060 #define FO_VAR_num_game_global_vars 0x5186C4 diff --git a/sfall/Modules/DamageMod.cpp b/sfall/Modules/DamageMod.cpp index ea8ef9d4..27abb8f8 100644 --- a/sfall/Modules/DamageMod.cpp +++ b/sfall/Modules/DamageMod.cpp @@ -284,7 +284,7 @@ void DamageMod::DamageYAAM(fo::ComputeAttackResult &ctd, DWORD &accumulatedDamag } //////////////////////////////////////////////////////////////////////////////// -// Display melee damage w/o perk bonus +// Display melee damage w/o PERK_bonus_hth_damage bonus static __declspec(naked) void MeleeDmgDisplayPrintFix_hook() { using namespace fo; __asm { @@ -304,7 +304,7 @@ static __declspec(naked) void MeleeDmgDisplayPrintFix_hook() { } } -// Display max melee damage w/o perk bonus +// Display max melee damage w/o PERK_bonus_hth_damage bonus static __declspec(naked) void CommonDmgRngDispFix_hook() { using namespace fo; __asm { diff --git a/sfall/Modules/Graphics.cpp b/sfall/Modules/Graphics.cpp index f6755dec..d2314bba 100644 --- a/sfall/Modules/Graphics.cpp +++ b/sfall/Modules/Graphics.cpp @@ -35,7 +35,13 @@ namespace sfall typedef HRESULT (__stdcall *DDrawCreateProc)(void*, IDirectDraw**, void*); //typedef IDirect3D9* (__stdcall *D3DCreateProc)(UINT version); -IDirectDrawSurface* primaryDDSurface = nullptr; // aka _GNW95_DDPrimarySurface +#if !(NDEBUG) && !(_DEBUG) +static LPD3DXFONT font; +static RECT fontPosition; +#endif + +IDirectDrawSurface* primarySurface = nullptr; // aka _GNW95_DDPrimarySurface +IDirectDrawPalette* primaryPalette = nullptr; // aka _GNW95_DDPrimaryPalette static DWORD ResWidth; static DWORD ResHeight; @@ -50,7 +56,7 @@ static DWORD yoffset; //static DWORD xoffset; bool DeviceLost = false; -static bool mainTexLock = false; +//static bool mainTexLock = false; // for preventing a crash during the locked state of the texture static char textureFilter; // 1 - auto, 2 - force static DDSURFACEDESC surfaceDesc; @@ -68,7 +74,13 @@ static struct PALCOLOR { BYTE x; }; }; -} palette[256]; +} *palette; + +struct PALETTE { // F2 palette + BYTE B; + BYTE G; + BYTE R; +}; #pragma pack(pop) //static bool paletteInit = false; @@ -88,22 +100,24 @@ static int windowData; static DWORD ShaderVersion; -IDirect3D9* d3d9 = 0; -IDirect3DDevice9* d3d9Device = 0; +IDirect3D9* d3d9; +IDirect3DDevice9* d3d9Device; -static IDirect3DTexture9* mainTex = 0; -static IDirect3DTexture9* sTex1 = 0; -static IDirect3DTexture9* sTex2 = 0; +static IDirect3DTexture9* mainTex; +static IDirect3DTexture9* mainTexD; +static IDirect3DTexture9* sTex1; +static IDirect3DTexture9* sTex2; static IDirect3DTexture9* movieTex; -static IDirect3DSurface9* sSurf1 = 0; -static IDirect3DSurface9* sSurf2 = 0; -static IDirect3DSurface9* backBuffer = 0; +static IDirect3DSurface9* sSurf1; +static IDirect3DSurface9* sSurf2; +static IDirect3DSurface9* backBuffer; static IDirect3DVertexBuffer9* vertexOrigRes; static IDirect3DVertexBuffer9* vertexSfallRes; static IDirect3DVertexBuffer9* vertexMovie; +static IDirect3DTexture9* paletteTex; static IDirect3DTexture9* gpuPalette; static ID3DXEffect* gpuBltEffect; @@ -181,7 +195,7 @@ static void GetDisplayMode(D3DDISPLAYMODE &ddm) { dlog_f("Display mode format ID: %d\n", DL_INIT, ddm.Format); } -static void ResetDevice(bool createNew) { +static void ResetDevice(bool create) { D3DPRESENT_PARAMETERS params; ZeroMemory(¶ms, sizeof(params)); @@ -203,9 +217,10 @@ static void ResetDevice(bool createNew) { static bool software = false; static D3DFORMAT textureFormat = D3DFMT_X8R8G8B8; - bool A8_IsSupport = false; - if (createNew) { + if (create) { + bool A8_IsSupport = false; + dlog("Creating D3D9 Device...", DL_MAIN); if (FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_PUREDEVICE | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, ¶ms, &d3d9Device))) { MessageBoxA(window, "Failed to create hardware vertex processing device.\nUsing software vertex processing instead.", @@ -222,7 +237,9 @@ static void ResetDevice(bool createNew) { if (Graphics::GPUBlt == 2 && ShaderVersion < 20) Graphics::GPUBlt = 0; if (Graphics::GPUBlt) { - A8_IsSupport = (d3d9Device->CreateTexture(ResWidth, ResHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8, D3DPOOL_DEFAULT, &mainTex, 0) == D3D_OK); + d3d9Device->CreateTexture(256, 1, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &paletteTex, 0); + + A8_IsSupport = (d3d9Device->CreateTexture(ResWidth, ResHeight, 1, 0, D3DFMT_A8, D3DPOOL_SYSTEMMEM, &mainTex, 0) == D3D_OK); textureFormat = (A8_IsSupport) ? D3DFMT_A8 : D3DFMT_L8; // D3DFMT_A8 - not supported on some older video cards const char* shader = (A8_IsSupport) ? gpuEffectA8 : gpuEffectL8; @@ -240,22 +257,33 @@ static void ResetDevice(bool createNew) { Graphics::SetDefaultTechnique(); } + + if (!A8_IsSupport && d3d9Device->CreateTexture(ResWidth, ResHeight, 1, 0, textureFormat, D3DPOOL_SYSTEMMEM, &mainTex, 0) != D3D_OK) { + textureFormat = D3DFMT_X8R8G8B8; + d3d9Device->CreateTexture(ResWidth, ResHeight, 1, 0, textureFormat, D3DPOOL_SYSTEMMEM, &mainTex, 0); + MessageBoxA(window, "GPU does not support the D3DFMT_L8 texture format.\nNow CPU is used to convert the palette.", + "Texture format error", MB_TASKMODAL | MB_ICONWARNING); + Graphics::GPUBlt = 0; + } + if (Graphics::GPUBlt == 0) palette = new PALCOLOR[256]; + + #if !(NDEBUG) && !(_DEBUG) + D3DXCreateFontA(d3d9Device, 24, 0, 500, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial", &font); // create a font + + fontPosition.top = 10; + fontPosition.left = 10; + fontPosition.right = 610; + fontPosition.bottom = 30; + #endif } else { dlog("Resetting D3D9 Device...", DL_MAIN); d3d9Device->Reset(¶ms); if (gpuBltEffect) gpuBltEffect->OnResetDevice(); ScriptShaders::OnResetDevice(); - mainTexLock = false; - } - - if (!A8_IsSupport && d3d9Device->CreateTexture(ResWidth, ResHeight, 1, D3DUSAGE_DYNAMIC, textureFormat, D3DPOOL_DEFAULT, &mainTex, 0) != D3D_OK) { - d3d9Device->CreateTexture(ResWidth, ResHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &mainTex, 0); - Graphics::GPUBlt = 0; - textureFormat = D3DFMT_X8R8G8B8; - MessageBoxA(window, "GPU does not support the D3DFMT_L8 texture format.\nNow CPU is used to convert the palette.", - "Texture format error", MB_TASKMODAL | MB_ICONWARNING); + //mainTexLock = false; } + d3d9Device->CreateTexture(ResWidth, ResHeight, 1, 0, textureFormat, D3DPOOL_DEFAULT, &mainTexD, 0); d3d9Device->CreateTexture(ResWidth, ResHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &sTex1, 0); d3d9Device->CreateTexture(ResWidth, ResHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &sTex2, 0); sTex1->GetSurfaceLevel(0, &sSurf1); @@ -263,7 +291,7 @@ static void ResetDevice(bool createNew) { if (Graphics::GPUBlt) { d3d9Device->CreateTexture(256, 1, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &gpuPalette, 0); - gpuBltEffect->SetTexture(gpuBltMainTex, mainTex); + gpuBltEffect->SetTexture(gpuBltMainTex, mainTexD); gpuBltEffect->SetTexture(gpuBltPalette, gpuPalette); } @@ -300,7 +328,7 @@ static void ResetDevice(bool createNew) { d3d9Device->CreateVertexBuffer(4 * sizeof(VertexFormat), D3DUSAGE_WRITEONLY | (software ? D3DUSAGE_SOFTWAREPROCESSING : 0), _VERTEXFORMAT, D3DPOOL_DEFAULT, &vertexMovie, 0); d3d9Device->SetFVF(_VERTEXFORMAT); - d3d9Device->SetTexture(0, mainTex); + d3d9Device->SetTexture(0, mainTexD); d3d9Device->SetStreamSource(0, vertexOrigRes, 0, sizeof(VertexFormat)); //d3d9Device->SetRenderState(D3DRS_ALPHABLENDENABLE, false); // default false @@ -317,6 +345,41 @@ static void ResetDevice(bool createNew) { dlogr(" Done", DL_MAIN); } +#if !(NDEBUG) && !(_DEBUG) +static long frameCount; +static long elapsedTime; +static long fps; +static long palCounter; +static long lockCounter; + +static void CalcFPS() { + static DWORD lastTime = GetTickCount(); + + frameCount++; + + DWORD time = GetTickCount(); + elapsedTime += time - lastTime; + lastTime = time; + + if (elapsedTime >= 1000) { + fps = (1000 * frameCount) / elapsedTime; + elapsedTime = 0; + frameCount = 0; + } +} + +static char text[64] = "FPS: "; + +static void DrawFPS() { + _itoa(fps, &text[5], 10); + //sprintf(text, "FPS: %d | Lock/PAL: %d/%d", fps, lockCounter, palCounter); + font->DrawTextA(0, text, -1, &fontPosition, DT_LEFT, D3DCOLOR_RGBA(255, 255, 128, 192)); +} +#else +static void CalcFPS() {} +static void DrawFPS() {} +#endif + static void Present() { if ((moveWindowKey[0] != 0 && KeyDown(moveWindowKey[0])) || (moveWindowKey[1] != 0 && KeyDown(moveWindowKey[1]))) @@ -367,7 +430,7 @@ static void Present() { #endif DeviceLost = true; d3d9Device->SetTexture(0, 0); - SAFERELEASE(mainTex) + SAFERELEASE(mainTexD) SAFERELEASE(backBuffer); SAFERELEASE(sSurf1); SAFERELEASE(sSurf2); @@ -381,6 +444,7 @@ static void Present() { if (gpuBltEffect) gpuBltEffect->OnLostDevice(); ScriptShaders::OnLostDevice(); } + CalcFPS(); } static void Refresh() { @@ -389,11 +453,11 @@ static void Refresh() { d3d9Device->BeginScene(); d3d9Device->SetStreamSource(0, vertexOrigRes, 0, sizeof(VertexFormat)); d3d9Device->SetRenderTarget(0, sSurf1); - d3d9Device->SetTexture(0, mainTex); + d3d9Device->SetTexture(0, mainTexD); UINT passes; if (Graphics::GPUBlt) { - // converts the palette in mainTex to RGB colors on the target surface (sSurf1/sTex1) + // converts the palette index in mainTexD to RGB colors on the target surface (sSurf1/sTex1) gpuBltEffect->Begin(&passes, 0); gpuBltEffect->BeginPass(0); d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); @@ -412,7 +476,9 @@ static void Refresh() { d3d9Device->SetStreamSource(0, vertexSfallRes, 0, sizeof(VertexFormat)); d3d9Device->SetRenderTarget(0, backBuffer); - d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); // render square with a texture image (mainTex/sTex1/sTex2) to the backBuffer + d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); // render square with a texture image (mainTexD/sTex1/sTex2) to the backBuffer + DrawFPS(); + d3d9Device->EndScene(); Present(); } @@ -505,11 +571,11 @@ void Graphics::ShowMovieFrame(IDirect3DTexture9* tex) { d3d9Device->SetRenderTarget(0, backBuffer); d3d9Device->BeginScene(); - if (!mainTexLock) { + //if (!mainTexLock) { if (ScriptShaders::Count() && Graphics::GPUBlt) { d3d9Device->SetTexture(0, sTex2); } else { - d3d9Device->SetTexture(0, mainTex); + d3d9Device->SetTexture(0, mainTexD); } d3d9Device->SetStreamSource(0, vertexSfallRes, 0, sizeof(VertexFormat)); @@ -524,7 +590,7 @@ void Graphics::ShowMovieFrame(IDirect3DTexture9* tex) { gpuBltEffect->EndPass(); gpuBltEffect->End(); } - } + //} // for avi movie d3d9Device->SetTexture(0, movieTex); d3d9Device->SetStreamSource(0, vertexMovie, 0, sizeof(VertexFormat)); @@ -572,11 +638,7 @@ void Graphics::SetDefaultTechnique() { } static void SetGPUPalette() { - D3DLOCKED_RECT rect; - if (gpuPalette && !FAILED(gpuPalette->LockRect(0, &rect, 0, D3DLOCK_DISCARD))) { - CopyMemory(rect.pBits, palette, 256 * 4); - gpuPalette->UnlockRect(0); - } + d3d9Device->UpdateTexture(paletteTex, gpuPalette); } class FakeDirectDrawSurface : IDirectDrawSurface { @@ -593,7 +655,7 @@ public: Refs = 1; isPrimary = primary; if (primary && Graphics::GPUBlt) { - // use the mainTex texture as a buffer + // use the mainTex texture as source buffer } else { lockTarget = new BYTE[ResWidth * ResHeight]; } @@ -618,10 +680,10 @@ public: HRESULT __stdcall AddAttachedSurface(LPDIRECTDRAWSURFACE) { UNUSEDFUNCTION; } HRESULT __stdcall AddOverlayDirtyRect(LPRECT) { UNUSEDFUNCTION; } - HRESULT __stdcall Blt(LPRECT dsc, LPDIRECTDRAWSURFACE b, LPRECT scr, DWORD d, LPDDBLTFX e) { // called 0x4868DA movie_MVE_ShowFrame_ (used for game movies, only for w/o HRP) - mveDesc.dwHeight = (dsc->bottom - dsc->top); + HRESULT __stdcall Blt(LPRECT dst, LPDIRECTDRAWSURFACE b, LPRECT scr, DWORD d, LPDDBLTFX e) { // called 0x4868DA movie_MVE_ShowFrame_ (used for game movies, only for w/o HRP) + mveDesc.dwHeight = (dst->bottom - dst->top); yoffset = (ResHeight - mveDesc.dwHeight) / 2; - mveDesc.lPitch = (dsc->right - dsc->left); + mveDesc.lPitch = (dst->right - dst->left); //xoffset = (ResWidth - mveDesc.lPitch) / 2; //dlog_f("\nBlt: [mveDesc: w:%d, h:%d]", DL_INIT, mveDesc.lPitch, mveDesc.dwHeight); @@ -632,7 +694,8 @@ public: BYTE* lockTarget = ((FakeDirectDrawSurface*)b)->lockTarget; D3DLOCKED_RECT dRect; - mainTex->LockRect(0, &dRect, dsc, 0); + mainTex->LockRect(0, &dRect, dst, D3DLOCK_NO_DIRTY_UPDATE); + mainTex->AddDirtyRect(dst); DWORD width = mveDesc.lPitch; // the current size of the width of the mve movie @@ -656,6 +719,8 @@ public: } } mainTex->UnlockRect(0); + d3d9Device->UpdateTexture(mainTex, mainTexD); + //mainTexLock = false; //if (Graphics::PlayAviMovie) return DD_OK; // Blt method is not executed during avi playback because the sfShowFrame_ function is blocked @@ -696,8 +761,9 @@ public: lockRect = a; if (Graphics::GPUBlt) { D3DLOCKED_RECT buf; - if (SUCCEEDED(mainTex->LockRect(0, &buf, lockRect, 0))) { - mainTexLock = true; + if (SUCCEEDED(mainTex->LockRect(0, &buf, lockRect, D3DLOCK_NO_DIRTY_UPDATE))) { + mainTex->AddDirtyRect(lockRect); + //mainTexLock = true; b->lpSurface = buf.pBits; b->lPitch = buf.Pitch; } @@ -732,13 +798,17 @@ public: HRESULT __stdcall SetColorKey(DWORD, LPDDCOLORKEY) { UNUSEDFUNCTION; } HRESULT __stdcall SetOverlayPosition(LONG, LONG) { UNUSEDFUNCTION; } - HRESULT __stdcall SetPalette(LPDIRECTDRAWPALETTE a) { // called 0x4CB198 GNW95_init_DirectDraw_ - if (DeviceLost || a) return DD_OK; // prevents executing the function when called from outside of sfall - //dlog("\nSetPalette", DL_INIT); - mainTexLock = true; + HRESULT __stdcall SetPalette(LPDIRECTDRAWPALETTE a) { + if (a) { // called 0x4CB198 GNW95_init_DirectDraw_ + primaryPalette = a; + return DD_OK; // prevents executing the function when called from outside of sfall + } + if (DeviceLost) return DD_OK; + + //mainTexLock = true; D3DLOCKED_RECT dRect; - mainTex->LockRect(0, &dRect, 0, D3DLOCK_DISCARD); + mainTex->LockRect(0, &dRect, 0, 0); DWORD* pBits = (DWORD*)dRect.pBits; int pitch = (dRect.Pitch / 4) - ResWidth; @@ -756,7 +826,8 @@ public: } mainTex->UnlockRect(0); - mainTexLock = false; + d3d9Device->UpdateTexture(mainTex, mainTexD); + //mainTexLock = false; return DD_OK; } @@ -768,15 +839,15 @@ public: 0x4868BA movie_MVE_ShowFrame_ (capture never call) */ HRESULT __stdcall Unlock(LPVOID lockSurface) { - //dlog("\nUnlock", DL_INIT); if (!isPrimary) return DD_OK; - //dlog("\nUnlock -> primary", DL_INIT); + //lockCounter++; if (Graphics::GPUBlt == 0) { - mainTexLock = true; + //mainTexLock = true; D3DLOCKED_RECT dRect; - mainTex->LockRect(0, &dRect, lockRect, (lockRect) ? 0 : D3DLOCK_DISCARD); + mainTex->LockRect(0, &dRect, lockRect, D3DLOCK_NO_DIRTY_UPDATE); + mainTex->AddDirtyRect(lockRect); DWORD* pBits = (DWORD*)dRect.pBits; int pitch = dRect.Pitch / 4; @@ -811,11 +882,11 @@ public: } } } - if (mainTexLock) mainTex->UnlockRect(0); - mainTexLock = false; + /*if (mainTexLock)*/ mainTex->UnlockRect(0); + //mainTexLock = false; + d3d9Device->UpdateTexture(mainTex, mainTexD); if (!IsPlayMovie && !Graphics::PlayAviMovie) { - //dlog("\nUnlock -> RefreshGraphics", DL_INIT); Refresh(); } IsPlayMovie = false; @@ -860,25 +931,45 @@ public: 0x4CB5C7 GNW95_SetPalette_ 0x4CB36B GNW95_SetPaletteEntries_ */ - HRESULT __stdcall SetEntries(DWORD a, DWORD b, DWORD c, LPPALETTEENTRY destPal) { // used to set palette for splash screen, fades, subtitles - if (!windowInit || c == 0 || b + c > 256) return DDERR_INVALIDPARAMS; + HRESULT __stdcall SetEntries(DWORD a, DWORD b, DWORD c, LPPALETTEENTRY d) { // used to set palette for splash screen, fades, subtitles + if (!windowInit || c <= 0) return DDERR_INVALIDPARAMS; + //palCounter++; - __movsd((DWORD*)&palette[b], (DWORD*)destPal, c); // copy DWORDs + PALETTE* destPal = (PALETTE*)d; if (Graphics::GPUBlt) { + D3DLOCKED_RECT pal; + if (c != 256) { + RECT rect = { b, 0, b + c, 1 }; + paletteTex->LockRect(0, &pal, &rect, D3DLOCK_NO_DIRTY_UPDATE); + paletteTex->AddDirtyRect(&rect); + b = 0; + } else { + paletteTex->LockRect(0, &pal, 0, 0); + } + // copy and swap color B <> R + do { + ((PALCOLOR*)pal.pBits)[b].R = destPal->R << 2; + ((PALCOLOR*)pal.pBits)[b].G = destPal->G << 2; + ((PALCOLOR*)pal.pBits)[b].B = destPal->B << 2; + destPal++; + b++; + } while (--c); + paletteTex->UnlockRect(0); SetGPUPalette(); } else { - // X8B8G8R8 format - for (size_t i = b; i < b + c; i++) { // swap color B <> R - BYTE clrB = palette[i].R; - palette[i].R = palette[i].B; - palette[i].B = clrB; - } - primaryDDSurface->SetPalette(0); // update texture + // copy and swap color B <> R + do { + palette[b].R = destPal->R << 2; + palette[b].G = destPal->G << 2; + palette[b].B = destPal->B << 2; + destPal++; + b++; + } while (--c); + primarySurface->SetPalette(0); // update texture if (FakeDirectDrawSurface::IsPlayMovie) return DD_OK; // prevents flickering at the beginning of playback (w/o HRP & GPUBlt=2) } if (!Graphics::PlayAviMovie) { - //dlog("\nSetEntries -> RefreshGraphics", DL_INIT); Refresh(); } return DD_OK; @@ -907,16 +998,19 @@ public: SAFERELEASE(sSurf1); SAFERELEASE(sSurf2); SAFERELEASE(mainTex); + SAFERELEASE(mainTexD); SAFERELEASE(sTex1); SAFERELEASE(sTex2); SAFERELEASE(vertexOrigRes); SAFERELEASE(vertexSfallRes); - SAFERELEASE(d3d9Device); - SAFERELEASE(d3d9); + SAFERELEASE(paletteTex); SAFERELEASE(gpuPalette); SAFERELEASE(gpuBltEffect); SAFERELEASE(vertexMovie); + SAFERELEASE(d3d9Device); + SAFERELEASE(d3d9); + delete[] palette; delete this; return 0; } else return Refs; @@ -938,7 +1032,7 @@ public: */ HRESULT __stdcall CreateSurface(LPDDSURFACEDESC a, LPDIRECTDRAWSURFACE* b, IUnknown* c) { if (a->ddsCaps.dwCaps == DDSCAPS_PRIMARYSURFACE && a->dwFlags == DDSD_CAPS) { - *b = primaryDDSurface = (IDirectDrawSurface*)new FakeDirectDrawSurface(true); + *b = primarySurface = (IDirectDrawSurface*)new FakeDirectDrawSurface(true); } else { *b = (IDirectDrawSurface*)new FakeDirectDrawSurface(false); } @@ -1098,6 +1192,49 @@ static __declspec(naked) void game_init_hook() { } } +static __declspec(naked) void GNW95_SetPaletteEntries_hack() { + LPPALETTEENTRY palette; + DWORD startIndex; + DWORD count; + __asm { + push ebp; + mov ebp, esp; + sub esp, __LOCAL_SIZE; + mov count, ebx; + mov palette, eax; + mov startIndex, edx; + } + primaryPalette->SetEntries(0, startIndex, count, palette); + + __asm { + mov esp, ebp; // epilog + pop ebp; + pop ecx; + retn; + } +} + +static __declspec(naked) void GNW95_SetPalette_hack() { + LPPALETTEENTRY palette; + __asm { + push ecx; + push edx; + push ebp; + mov ebp, esp; + sub esp, __LOCAL_SIZE; + mov palette, eax; + } + primaryPalette->SetEntries(0, 0, 256, palette); + + __asm { + mov esp, ebp; // epilog + pop ebp; + pop edx; + pop ecx; + retn; + } +} + static DWORD forcingGraphicsRefresh = 0; void Graphics::RefreshGraphics() { @@ -1132,6 +1269,9 @@ void Graphics::init() { SafeWrite8(0x50FB6B, '2'); // Set call DirectDrawCreate2 HookCall(0x44260C, game_init_hook); + MakeJump(fo::funcoffs::GNW95_SetPaletteEntries_ + 1, GNW95_SetPaletteEntries_hack); // 0x4CB311 + MakeJump(fo::funcoffs::GNW95_SetPalette_, GNW95_SetPalette_hack); // 0x4CB568 + if (hrpVersionValid) { // Patch HRP to show the mouse cursor over the window title if (Graphics::mode == 5) SafeWrite8(HRPAddress(0x10027142), CodeType::JumpShort); diff --git a/sfall/Modules/Graphics.h b/sfall/Modules/Graphics.h index 74031b2c..7e35042e 100644 --- a/sfall/Modules/Graphics.h +++ b/sfall/Modules/Graphics.h @@ -29,7 +29,7 @@ namespace sfall extern IDirect3D9* d3d9; extern IDirect3DDevice9* d3d9Device; -extern IDirectDrawSurface* primaryDDSurface; +extern IDirectDrawSurface* primarySurface; extern bool DeviceLost; /* @@ -106,12 +106,12 @@ public: DDSURFACEDESC desc; RECT lockRect = { x, y, rect->right + 1, rect->bottom + 1 }; - if (primaryDDSurface->Lock(&lockRect, &desc, 0, 0)) return; // lock error + if (primarySurface->Lock(&lockRect, &desc, 0, 0)) return; // lock error if (Graphics::GPUBlt == 0) desc.lpSurface = (BYTE*)desc.lpSurface + (desc.lPitch * y) + x; fo::func::buf_to_buf(surface, width, height, widthFrom, (BYTE*)desc.lpSurface, desc.lPitch); - primaryDDSurface->Unlock(desc.lpSurface); + primarySurface->Unlock(desc.lpSurface); } } }; @@ -137,7 +137,7 @@ static const char* gpuEffectA8 = "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).bgr;" // get color in palette and swap R <> B + "result = tex1D(s1, backdrop);" // get color in palette "}" // blend highlights "if (showhl) {" @@ -154,7 +154,7 @@ static const char* gpuEffectA8 = // main shader "float4 P0( in float2 Tex : TEXCOORD0 ) : COLOR0 {" "float3 result = tex1D(s1, tex2D(s0, Tex).a);" // get color in palette - "return float4(result.bgr, 1);" // swap R <> B + "return float4(result, 1);" "}" "technique T0" "{" @@ -182,7 +182,7 @@ static const char* gpuEffectL8 = "if (abs(backdrop - 1.0) < 0.001) {" "result = tex2D(s2, saturate((Tex - corner) / size));" "} else {" - "result = tex1D(s1, backdrop).bgr;" + "result = tex1D(s1, backdrop);" "}" // blend highlights "if (showhl) {" @@ -199,7 +199,7 @@ static const char* gpuEffectL8 = // main shader "float4 P0( in float2 Tex : TEXCOORD0 ) : COLOR0 {" "float3 result = tex1D(s1, tex2D(s0, Tex).r);" - "return float4(result.bgr, 1);" + "return float4(result, 1);" "}" "technique T0" "{" diff --git a/sfall/Modules/Interface.cpp b/sfall/Modules/Interface.cpp index d9b45147..c8c8bcbb 100644 --- a/sfall/Modules/Interface.cpp +++ b/sfall/Modules/Interface.cpp @@ -796,8 +796,6 @@ static void __declspec(naked) wmInterfaceInit_hook() { } static void WorldMapInterfacePatch() { - BlockCall(0x4C2380); // Remove disabling palette animations (can be used as a place to call a hack function in wmInterfaceInit_) - if (IniReader::GetConfigInt("Misc", "WorldMapFontPatch", 0)) { dlog("Applying world map font patch.", DL_INIT); HookCall(0x4C2343, wmInterfaceInit_text_font_hook); @@ -846,7 +844,7 @@ static void WorldMapInterfacePatch() { dlog("Applying world map travel markers patch.", DL_INIT); int color = IniReader::GetConfigInt("Interface", "TravelMarkerColor", 134); // color index in palette: R = 224, G = 0, B = 0 - if (color > 255) color = 255; else if (color < 1) color = 1; + if (color > 228) color = 228; else if (color < 1) color = 1; // no palette animation colors colorDot = color; auto dotList = IniReader::GetConfigList("Interface", "TravelMarkerStyles", "", 512); diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index a44ef5ae..b6f91a23 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -228,7 +228,7 @@ static void __fastcall SwapHandSlots(fo::GameObject* item, fo::GameObject* &toSl fo::ItemButtonItem* leftSlot = &fo::var::itemButtonItems[fo::HandSlot::Left]; fo::ItemButtonItem* rightSlot = &fo::var::itemButtonItems[fo::HandSlot::Right]; - if (toSlot == nullptr) { // copy to slot + if (toSlot == nullptr) { // copy to empty slot fo::ItemButtonItem* dstSlot; fo::ItemButtonItem item; if ((int)&toSlot == FO_VAR_i_lhand) { diff --git a/sfall/Modules/Objects.cpp b/sfall/Modules/Objects.cpp index 21eab06f..c462c775 100644 --- a/sfall/Modules/Objects.cpp +++ b/sfall/Modules/Objects.cpp @@ -31,6 +31,10 @@ static int maxCountLoadProto = 512; long Objects::uniqueID = UniqueID::Start; // current counter id, saving to sfallgv.sav +bool Objects::IsUniqueID(long id) { + return (id > UniqueID::Start || (id >= fo::PLAYER_ID && id < 83536)); // 65535 maximum possible number of prototypes +} + static void SetScriptObjectID(fo::GameObject* obj) { fo::ScriptInstance* script; if (fo::func::scr_ptr(obj->scriptId, &script) != -1) { @@ -43,7 +47,7 @@ static void SetScriptObjectID(fo::GameObject* obj) { // player ID = 18000, all party members have ID = 18000 + its pid (file number of prototype) long __fastcall Objects::SetObjectUniqueID(fo::GameObject* obj) { long id = obj->id; - if (id > UniqueID::Start || (id >= fo::PLAYER_ID && id < 83536)) return id; // 65535 maximum possible number of prototypes + if (IsUniqueID(id)) return id; if ((DWORD)uniqueID >= (DWORD)UniqueID::End) uniqueID = UniqueID::Start; obj->id = ++uniqueID; diff --git a/sfall/Modules/Objects.h b/sfall/Modules/Objects.h index cada4d4e..59ab0c43 100644 --- a/sfall/Modules/Objects.h +++ b/sfall/Modules/Objects.h @@ -17,6 +17,8 @@ public: static long uniqueID; + static bool IsUniqueID(long id); + static long __fastcall SetObjectUniqueID(fo::GameObject* obj); static long __fastcall SetSpecialID(fo::GameObject* obj); static void SetNewEngineID(fo::GameObject* obj); diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index 2b8bd2e3..08d8ea6e 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -1007,7 +1007,7 @@ void ScriptExtender::init() { MakeCall(0x423DEB, (void*)fo::funcoffs::compute_damage_); } - InitNewOpcodes(); + Opcodes::InitNew(); ScriptExtender::OnMapExit() += ClearEventsOnMapExit; // for reordering the execution of functions before exiting the map } diff --git a/sfall/Modules/Scripting/Handlers/Arrays.cpp b/sfall/Modules/Scripting/Handlers/Arrays.cpp index d460eeb0..a90bed13 100644 --- a/sfall/Modules/Scripting/Handlers/Arrays.cpp +++ b/sfall/Modules/Scripting/Handlers/Arrays.cpp @@ -151,24 +151,22 @@ struct ListId { static std::vector mList; static void FillListVector(DWORD type, std::vector& vec) { + if (type == 4) return; // LIST_TILES + vec.reserve(100); - if (type == 6) { - fo::ScriptInstance* scriptPtr; - fo::GameObject* self_obj; - fo::Program* programPtr; + if (type == 6) { // LIST_SPATIAL for (int elev = 0; elev <= 2; elev++) { - scriptPtr = fo::func::scr_find_first_at(elev); + fo::ScriptInstance* scriptPtr = fo::func::scr_find_first_at(elev); while (scriptPtr != nullptr) { - self_obj = scriptPtr->selfObject; + fo::GameObject* self_obj = scriptPtr->selfObject; if (self_obj == nullptr) { - programPtr = scriptPtr->program; - self_obj = fo::func::scr_find_obj_from_program(programPtr); + self_obj = fo::func::scr_find_obj_from_program(scriptPtr->program); } vec.push_back(self_obj); scriptPtr = fo::func::scr_find_next_at(); } } - /*} else if (type == 4) { + /*} else if (type == 4) { // LIST_TILES // TODO: verify code correctness for(int elv=0;elv<2;elv++) { DWORD* esquares = &fo::var::squares[elv]; @@ -176,7 +174,7 @@ static void FillListVector(DWORD type, std::vector& vec) { esquares[tile]=0x8f000002; } }*/ - } else if (type != 4) { + } else { for (int elv = 0; elv < 3; elv++) { for (int tile = 0; tile < 40000; tile++) { fo::GameObject* obj = fo::func::obj_find_first_at_tile(elv, tile); diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index 5da383c2..fca27678 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -270,7 +270,7 @@ static void __fastcall defaultOpcodeHandler(fo::Program* program, DWORD opcodeOf __asm pop ecx; } -void InitNewOpcodes() { +void Opcodes::InitNew() { dlogr("Adding additional opcodes", DL_SCRIPT); SafeWrite32(0x46E370, opcodeCount); // Maximum number of allowed opcodes diff --git a/sfall/Modules/Scripting/Opcodes.h b/sfall/Modules/Scripting/Opcodes.h index d0404b0e..f1677be4 100644 --- a/sfall/Modules/Scripting/Opcodes.h +++ b/sfall/Modules/Scripting/Opcodes.h @@ -25,7 +25,10 @@ namespace sfall namespace script { -void InitNewOpcodes(); +class Opcodes { +public: + static void InitNew(); +}; } } diff --git a/sfall/Modules/Unarmed.cpp b/sfall/Modules/Unarmed.cpp index aa1b4777..993902be 100644 --- a/sfall/Modules/Unarmed.cpp +++ b/sfall/Modules/Unarmed.cpp @@ -442,10 +442,10 @@ void Unarmed::init() { if (val >= 0) hit.reqSkill = val; val = IniReader::GetInt(sHit, "MinDamage", -1, file); - if (val >= 0) hit.minDamage = val; + if (val > 0) hit.minDamage = val; val = IniReader::GetInt(sHit, "MaxDamage", -1, file); - if (val >= 0) hit.maxDamage = val; + if (val > 0) hit.maxDamage = val; val = IniReader::GetInt(sHit, "BonusDamage", -1, file); if (val >= 0) hit.bonusDamage = val; @@ -454,7 +454,7 @@ void Unarmed::init() { if (val >= 0) hit.bonusCrit = val; val = IniReader::GetInt(sHit, "APCost", -1, file); - if (val >= 0) hit.apCost = val; + if (val > 0) hit.apCost = val; val = IniReader::GetInt(sHit, "Penetrate", -1, file); if (val >= 0) hit.isPenetrate = (val != 0);