Modified some of the mechanics of "interface_overlay" function

Changed "intface_redraw" with one argument to redraw the specified
interface window.
This commit is contained in:
NovaRain
2020-12-25 14:46:47 +08:00
parent 9d5bfaa059
commit 279f91274e
12 changed files with 137 additions and 80 deletions
+3 -1
View File
@@ -338,7 +338,8 @@
#define interface_art_draw_ex(winID, artID, x, y, frame, param) sfall_func6("interface_art_draw", winID, artID, x, y, frame, param)
#define interface_print(text, winType, x, y, color) sfall_func5("interface_print", text, winType, x, y, color)
#define interface_print_width(text, winType, x, y, color, w) sfall_func6("interface_print", text, winType, x, y, color, w)
#define interface_redraw_all sfall_func1("intface_redraw", 1)
#define interface_redraw_all sfall_func1("intface_redraw", -1)
#define interface_redraw_win(winType) sfall_func1("intface_redraw", winType)
#define intface_hide sfall_func0("intface_hide")
#define intface_is_hidden sfall_func0("intface_is_hidden")
#define intface_is_shown(winType) sfall_func1("get_window_attribute", winType)
@@ -358,6 +359,7 @@
#define overlay_create(winType) sfall_func2("interface_overlay", winType, 1)
#define overlay_clear(winType) sfall_func2("interface_overlay", winType, 2)
#define overlay_clear_rectangle(winType, x, y, w, h) sfall_func6("interface_overlay", winType, 2, x, y, w, h)
#define overlay_destroy(winType) sfall_func2("interface_overlay", winType, 0)
#define real_dude_obj sfall_func0("real_dude_obj")
#define remove_all_timer_events sfall_func0("remove_timer_event")
#define remove_timer_event(fixedParam) sfall_func1("remove_timer_event", fixedParam)
+10 -2
View File
@@ -402,9 +402,9 @@ Some utility/math functions are available:
- works just like vanilla critter_inven_obj, but correctly reports item in player's inactive hand slot
> void sfall_func0("intface_redraw")
> void sfall_func1("intface_redraw", bool eachWin)
> void sfall_func1("intface_redraw", int winType)
- redraws main game interface, useful to reflect changes after directly changing current player weapons or stats
- eachWin: pass True to redraw all interface windows
- winType: the type number of the interface window (see WINTYPE_* constants in sfall.h). Pass -1 to redraw all interface windows
> void sfall_func0("intface_hide")
- hides main interface
@@ -782,6 +782,14 @@ optional arguments:
- fills the rectangle area of the currently selected script window with the specified color, or clears the window with transparent (index 0) color (call the function without arguments)
- color: the color index in the game palette (from 0 to 255)
> int sfall_func2("interface_overlay", int winType, int mode)
> int sfall_func6("interface_overlay", int winType, 2, int x, int y, int width, int height)
- creates an additional drawing surface above the graphic layer of the specified interface window. All subsequent calls of interface_art_draw and interface_print functions will draw on it
- winType: the type number of the interface window (see WINTYPE_* constants in sfall.h)
- mode: 1 - creates a new overlay surface
2 - clears the overlay area or the specified rectangle defined by the x, y, width, height arguments
0 - destroys the created overlay surface (frees up the memory allocated to the surface)
------------------------
------ MORE INFO -------
------------------------
@@ -365,6 +365,4 @@
0x8280 - any sfall_func7(string funcName, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
0x8281 - any sfall_func8(string funcName, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
* These functions require AllowUnsafeScripting to be enabled in ddraw.ini
+4 -3
View File
@@ -499,10 +499,11 @@ void RedrawObject(GameObject* obj) {
func::tile_refresh_rect(&rect, obj->elevation);
}
// Redraws all interface windows
void RefreshGNW(size_t from) {
// Redraws all windows
void RefreshGNW(bool skipOwner) {
*(DWORD*)FO_VAR_doing_refresh_all = 1;
for (size_t i = from; i < fo::var::num_windows; i++) {
for (size_t i = 0; i < fo::var::num_windows; i++) {
if (skipOwner && fo::var::window[i]->flags & fo::WinFlags::OwnerFlag) continue;
fo::func::GNW_win_refresh(fo::var::window[i], &fo::var::scr_size, 0);
}
*(DWORD*)FO_VAR_doing_refresh_all = 0;
+2 -2
View File
@@ -148,8 +148,8 @@ DWORD GetMaxCharWidth();
// Redraw the given object on screen (does not always redraws the whole object)
void RedrawObject(GameObject* obj);
// Redraws all interface windows
void RefreshGNW(size_t from = 0);
// Redraws all windows
void RefreshGNW(bool skipOwner = false);
UnlistedFrm *LoadUnlistedFrm(char *frmName, unsigned int folderRef);
+10 -10
View File
@@ -789,16 +789,16 @@ namespace Fields {
namespace WinFlags {
enum WinButtonFlags : long
{
OwnerFlag = 0x1,
DontMoveTop = 0x2,
MoveOnTop = 0x4,
Hidden = 0x8,
Exclusive = 0x10,
Transparent = 0x20,
UnknownFlag40 = 0x40,
UnknownFlag80 = 0x80,
ScriptWindow = 0x100,
itsButton = 0x10000,
OwnerFlag = 0x000001, // sfall Render flag, indicates that the window surface is used for rendering the game scene
DontMoveTop = 0x000002, // does not move the window to top when the mouse is clicked in the window area or when it is showing
MoveOnTop = 0x000004, // places the window on top when it is created
Hidden = 0x000008,
Exclusive = 0x000010,
Transparent = 0x000020,
UnknownFlag40 = 0x000040,
UnknownFlag80 = 0x000080,
ScriptWindow = 0x000100,
itsButton = 0x010000,
};
}
+28
View File
@@ -22,6 +22,18 @@
#include "Enums.h"
namespace sfall
{
struct Rectangle {
long x, y, width, height;
long right() { return x + (width - 1); }
long bottom() { return y + (height - 1); }
};
}
namespace fo
{
@@ -74,6 +86,22 @@ struct BoundRect {
long y;
long offx; // right
long offy; // bottom
BoundRect() {};
BoundRect(sfall::Rectangle rect) {
x = rect.x;
y = rect.y;
offx = rect.right();
offy = rect.bottom();
}
BoundRect(RECT* rect) {
x = rect->left;
y = rect->top;
offx = rect->right;
offy = rect->bottom;
}
};
struct RectList {
+24 -13
View File
@@ -572,11 +572,32 @@ static void AlwaysReloadMsgs() {
}
}
static void RemoveWindowRoundingPatch() {
static void InterfaceWindowPatch() {
if (GetConfigInt("Misc", "RemoveWindowRounding", 1)) {
SafeWriteBatch<BYTE>(CodeType::JumpShort, {0x4D6EDD, 0x4D6F12});
//SafeWrite16(0x4B8090, 0x04EB); // jmps 0x4B8096 (old)
}
dlog("Applying flags patch for interface windows.", DL_INIT);
// Remove MoveOnTop flag for interfaces
SafeWrite8(0x46ECE9, (*(BYTE*)0x46ECE9) ^ fo::WinFlags::MoveOnTop); // Player Inventory/Loot/UseOn
SafeWrite8(0x41B966, (*(BYTE*)0x41B966) ^ fo::WinFlags::MoveOnTop); // Automap
// Set OwnerFlag flag
SafeWrite8(0x481CEC, (*(BYTE*)0x481CEC) | fo::WinFlags::OwnerFlag); // _display_win (map win)
SafeWrite8(0x44E7D2, (*(BYTE*)0x44E7D2) | fo::WinFlags::OwnerFlag); // gmovie_play_ (movie win)
// Remove OwnerFlag flag
SafeWrite8(0x4B801B, (*(BYTE*)0x4B801B) ^ fo::WinFlags::OwnerFlag); // createWindow_
// Remove OwnerFlag and Transparent flags
SafeWrite8(0x42F869, (*(BYTE*)0x42F869) ^ (fo::WinFlags::Transparent | fo::WinFlags::OwnerFlag)); // addWindow_
dlogr(" Done", DL_INIT);
// Disable unused code for the RandX and RandY window structure fields (these fields can now be used for other purposes)
SafeWrite32(0x4D630C, 0x9090C031); // xor eax, eax
SafeWrite8(0x4D6310, 0x90);
BlockCall(0x4D6319);
}
static void InventoryCharacterRotationSpeedPatch() {
@@ -685,15 +706,6 @@ static void SkipLoadingGameSettingsPatch() {
}
}
static void InterfaceDontMoveOnTopPatch() {
//if (GetConfigInt("Misc", "InterfaceDontMoveOnTop", 0)) {
dlog("Applying no MoveOnTop flag for interface patch.", DL_INIT);
SafeWrite8(0x46ECE9, fo::WinFlags::Exclusive); // Player Inventory/Loot/UseOn
SafeWrite8(0x41B966, fo::WinFlags::Exclusive); // Automap
dlogr(" Done", DL_INIT);
//}
}
static void UseWalkDistancePatch() {
int distance = GetConfigInt("Misc", "UseWalkDistance", 3) + 2;
if (distance > 1 && distance < 5) {
@@ -834,7 +846,7 @@ void MiscPatches::init() {
PlayIdleAnimOnReloadPatch();
SkilldexImagesPatch();
RemoveWindowRoundingPatch();
InterfaceWindowPatch();
ScienceOnCrittersPatch();
InventoryCharacterRotationSpeedPatch();
@@ -862,7 +874,6 @@ void MiscPatches::init() {
PartyMemberSkillPatch();
SkipLoadingGameSettingsPatch();
InterfaceDontMoveOnTopPatch();
UseWalkDistancePatch();
}
+14 -9
View File
@@ -268,10 +268,17 @@ void op_is_iface_tag_active(OpcodeContext &ctx) {
}
void mf_intface_redraw(OpcodeContext& ctx) {
if (ctx.arg(0).rawValue() == 0) {
if (ctx.numArgs() == 0) {
fo::func::intface_redraw();
} else {
fo::func::RefreshGNW(2); // fake redraw all interfaces (TODO: need a real redraw of interfaces)
// fake redraw interfaces (TODO: need a real redraw of interface?)
long winType = ctx.arg(0).rawValue();
if (winType == -1) {
fo::func::RefreshGNW(true);
} else {
fo::Window* win = Interface::GetWindow(winType);
if (win && (int)win != -1) fo::func::GNW_win_refresh(win, &win->rect, 0);
}
}
}
@@ -636,7 +643,7 @@ static long InterfaceDrawImage(OpcodeContext& ctx, fo::Window* ifaceWin) {
surface + (y * ifaceWin->width) + x, width, height, ifaceWin->width
);
if (!(ctx.arg(0).rawValue() & 0x1000000)) {
if (!(ctx.arg(0).rawValue() & 0x1000000)) { // is set to "Don't redraw"
fo::func::GNW_win_refresh(ifaceWin, &ifaceWin->rect, 0);
}
@@ -828,15 +835,15 @@ void mf_win_fill_color(OpcodeContext& ctx) {
}
void mf_interface_overlay(OpcodeContext& ctx) {
fo::Window* win = nullptr;
long winType = ctx.arg(0).rawValue();
if (ctx.arg(1).rawValue()) {
win = Interface::GetWindow(winType);
fo::Window* win = Interface::GetWindow(winType);
if (!win || (int)win == -1) return;
}
switch (ctx.arg(1).rawValue()) {
case 0:
GameRender::DestroyOverlaySurface(win);
break;
case 1:
GameRender::CreateOverlaySurface(win, winType);
break;
@@ -856,8 +863,6 @@ void mf_interface_overlay(OpcodeContext& ctx) {
GameRender::ClearOverlay(win);
}
break;
//case 0: // unused (reserved)
// GameRender::DestroyOverlaySurface(winType);
}
}
+38 -27
View File
@@ -25,6 +25,8 @@
namespace sfall
{
static void __fastcall sf_GNW_win_refresh(fo::Window* win, RECT* updateRect, BYTE* toBuffer);
class OverlaySurface
{
private:
@@ -34,12 +36,12 @@ private:
BYTE* surface = nullptr;
public:
//long winType = -1;
long winType = -1;
BYTE* Surface() { return surface; }
void CreateSurface(fo::Window* win, long winType) {
//this->winType = winType;
this->winType = winType;
this->surfWidth = win->width;
this->size = win->height * win->width;
@@ -66,26 +68,28 @@ public:
size_t sizeD = rect.width >> 2;
size_t sizeB = rect.width & 3;
size_t stride = sizeD << 2;
size_t strideD = sizeD << 2;
size_t stride = surfWidth - rect.width;
long height = rect.height;
while (height--) {
if (sizeD) {
__stosd((DWORD*)surf, 0, sizeD);
surf += stride;
surf += strideD;
}
if (sizeB) {
__stosb(surf, 0, sizeB);
surf += sizeB;
}
surf += stride;
};
}
}
/*void DestroySurface() {
void DestroySurface() {
delete[] surface;
surface = nullptr;
}*/
}
~OverlaySurface() {
delete[] surface;
@@ -95,32 +99,45 @@ public:
static long indexPosition = 0;
void GameRender::CreateOverlaySurface(fo::Window* win, long winType) {
overlaySurfaces[indexPosition].CreateSurface(win, winType);
win->randY = reinterpret_cast<long*>(&overlaySurfaces[indexPosition]);
if (win->randY) return;
if (overlaySurfaces[indexPosition].winType == winType) {
overlaySurfaces[indexPosition].ClearSurface();
} else {
if (++indexPosition == 5) indexPosition = 0;
};
overlaySurfaces[indexPosition].CreateSurface(win, winType);
}
win->randY = reinterpret_cast<long*>(&overlaySurfaces[indexPosition]);
}
BYTE* GameRender::GetOverlaySurface(fo::Window* win) {
return reinterpret_cast<OverlaySurface*>(win->randY)->Surface();
};
}
void GameRender::ClearOverlay(fo::Window* win) {
if (win->randY) reinterpret_cast<OverlaySurface*>(win->randY)->ClearSurface();
};
}
void GameRender::ClearOverlay(fo::Window* win, Rectangle &rect) {
if (win->randY) reinterpret_cast<OverlaySurface*>(win->randY)->ClearSurface(rect);
};
if (win->randY) {
reinterpret_cast<OverlaySurface*>(win->randY)->ClearSurface(rect);
fo::BoundRect updateRect = rect;
updateRect.x += win->rect.x;
updateRect.y += win->rect.y;
updateRect.offx += win->rect.x;
updateRect.offy += win->rect.y;
sf_GNW_win_refresh(win, reinterpret_cast<RECT*>(&updateRect), 0);
}
}
/*void GameRender::DestroyOverlaySurface(long winType) {
for (size_t i = 0; i < 5; i++) {
if (overlaySurfaces[i].winType == winType) {
overlaySurfaces[i].DestroySurface();
overlaySurfaces[i].winType = -1;
//break;
void GameRender::DestroyOverlaySurface(fo::Window* win) {
if (win->randY) {
auto overlay = reinterpret_cast<OverlaySurface*>(win->randY);
win->randY = nullptr;
overlay->winType = -1;
overlay->DestroySurface();
sf_GNW_win_refresh(win, &win->wRect, 0);
}
}
};*/
static BYTE* GetBuffer() {
return (BYTE*)*(DWORD*)FO_VAR_screen_buffer;
@@ -202,7 +219,7 @@ static void __fastcall sf_GNW_win_refresh(fo::Window* win, RECT* updateRect, BYT
__asm mov rects, eax;
if (!rects) return;
rects->rect = { updateRect->left, updateRect->top, updateRect->right, updateRect->bottom };
rects->rect = updateRect;
rects->nextRect = nullptr;
/*
@@ -312,17 +329,11 @@ void GameRender::init() {
0x4D5D46, // win_init_ (create screen_buffer)
0x4D75E6 // win_clip_ (remove _buffering checking)
});
SafeWrite8(0x42F869, fo::WinFlags::MoveOnTop | fo::WinFlags::OwnerFlag); // addWindow_ (remove Transparent flag)
// Custom implementation of the GNW_win_refresh function
MakeJump(0x4D6FD9, GNW_win_refresh_hack, 1);
// Replace _screendump_buf with _screen_buffer for creating screenshots
SafeWriteBatch<DWORD>(FO_VAR_screen_buffer, {0x4C8FD1, 0x4C900D});
// Disable unused code for the RandX and RandY window structure fields (these fields can now be used for other purposes)
SafeWrite32(0x4D630C, 0x9090C031); // xor eax, eax
SafeWrite8(0x4D6310, 0x90);
BlockCall(0x4D6319);
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ public:
static void init();
static void CreateOverlaySurface(fo::Window* win, long winType);
// static void DestroyOverlaySurface(long winType);
static void DestroyOverlaySurface(fo::Window* win);
static void ClearOverlay(fo::Window* win);
static void ClearOverlay(fo::Window* win, Rectangle &rect);
static BYTE* GetOverlaySurface(fo::Window* win);
-7
View File
@@ -80,13 +80,6 @@ namespace sfall
#define pushadc __asm push eax __asm push edx __asm push ecx
#define popadc __asm pop ecx __asm pop edx __asm pop eax
struct Rectangle {
long x, y, width, height;
long right() { return x + width; }
long bottom() { return y + height; }
};
// Gets the integer value from given INI file.
int iniGetInt(const char* section, const char* setting, int defaultValue, const char* iniFile);