diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 2abc03e1..b143050c 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -561,8 +561,8 @@ SuperStimExploitFix=0 InventoryApCost=4 QuickPocketsApCostReduction=2 -;Set to 1 to fix obj_can_see_obj script function to allow critters to see through other critters and objects with 'ShootThru' flag set -;Note that enabling this option can cause unexpected NPC behavior in some cases, e.g. initiating combat or dialogue when the player is hiding behind some obstacles +;Set to 1 to fix obj_can_see_obj script function to allow critters to see through objects with 'ShootThru' flag set and other critters in front of them +;Note that enabling this option can cause unexpected NPC behavior in some cases, e.g. initiating combat or dialogue when the player is behind certain obstacles ObjCanSeeObj_ShootThru_Fix=0 ;Set to 1 to fix the broken obj_can_hear_obj script function diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index 6dfb6b9d..459a4225 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -219,6 +219,8 @@ DWORD* ptr_text_char_width = reinterpret_cast(_text_char_widt DWORD* ptr_text_height = reinterpret_cast(_text_height); DWORD* ptr_text_max = reinterpret_cast(_text_max); DWORD* ptr_text_mono_width = reinterpret_cast(_text_mono_width); +DWORD* ptr_text_object_index = reinterpret_cast(_text_object_index); +FloatText** ptr_text_object_list = reinterpret_cast(_text_object_list); // array of 20 FloatText* DWORD* ptr_text_spacing = reinterpret_cast(_text_spacing); DWORD* ptr_text_to_buf = reinterpret_cast(_text_to_buf); DWORD* ptr_text_width = reinterpret_cast(_text_width); @@ -737,6 +739,7 @@ const DWORD tile_num_in_direction_ = 0x4B1A6C; const DWORD tile_refresh_display_ = 0x4B12D8; const DWORD tile_refresh_rect_ = 0x4B12C0; const DWORD tile_scroll_to_ = 0x4B3924; +const DWORD tile_set_center_ = 0x4B12F8; const DWORD trait_get_ = 0x4B3B54; const DWORD trait_init_ = 0x4B39F0; const DWORD trait_level_ = 0x4B3BC8; @@ -1490,6 +1493,10 @@ void __stdcall MapDirErase(const char* folder, const char* ext) { WRAP_WATCOM_CALL2(MapDirErase_, folder, ext) } +void __stdcall MemFree(void* folder) { + WRAP_WATCOM_CALL1(mem_free_, folder) +} + void __stdcall MouseGetPosition(long* outX, long* outY) { WRAP_WATCOM_CALL2(mouse_get_position_, outX, outY) } diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index 6690dddc..61843246 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -268,6 +268,8 @@ #define _text_height 0x51E3BC #define _text_max 0x51E3D4 #define _text_mono_width 0x51E3C8 +#define _text_object_index 0x51D944 +#define _text_object_list 0x6681C0 #define _text_spacing 0x51E3CC #define _text_to_buf 0x51E3B8 #define _text_width 0x51E3C0 @@ -513,6 +515,8 @@ extern DWORD* ptr_text_char_width; extern DWORD* ptr_text_height; extern DWORD* ptr_text_max; extern DWORD* ptr_text_mono_width; +extern DWORD* ptr_text_object_index; +extern FloatText** ptr_text_object_list; // array of 20 FloatText* extern DWORD* ptr_text_spacing; extern DWORD* ptr_text_to_buf; extern DWORD* ptr_text_width; @@ -1023,6 +1027,7 @@ extern const DWORD tile_num_in_direction_; extern const DWORD tile_refresh_display_; extern const DWORD tile_refresh_rect_; // (int elevation, unkown) extern const DWORD tile_scroll_to_; +extern const DWORD tile_set_center_; extern const DWORD trait_get_; extern const DWORD trait_init_; extern const DWORD trait_level_; @@ -1355,6 +1360,8 @@ void __fastcall GNWWinRefresh(WINinfo* win, BoundRect* rect, long* buffer); void __stdcall MapDirErase(const char* folder, const char* ext); +void __stdcall MemFree(void* folder); + void __stdcall MouseGetPosition(long* outX, long* outY); void __stdcall MouseShow(); diff --git a/sfall/FalloutStructs.h b/sfall/FalloutStructs.h index ea5cf517..45989133 100644 --- a/sfall/FalloutStructs.h +++ b/sfall/FalloutStructs.h @@ -28,7 +28,7 @@ struct TGameObj; struct TProgram; struct TScript; -#pragma pack(push, 1) +#pragma pack(1) struct sArt { long flags; char path[16]; @@ -36,20 +36,18 @@ struct sArt { long d18; long total; }; -#pragma pack(pop) // Bounding rectangle, used by tile_refresh_rect and related functions. -#pragma pack(push, 1) +#pragma pack(1) struct BoundRect { long x; long y; long offx; long offy; }; -#pragma pack(pop) // Game objects (items, critters, etc.), including those stored in inventories. -#pragma pack(push, 1) +#pragma pack(1) struct TGameObj { long id; long tile; @@ -110,10 +108,9 @@ struct TGameObj { return ((artFid >> 24) & 0x0F); } }; -#pragma pack(pop) // Results of compute_attack_() function. -#pragma pack(push, 1) +#pragma pack(1) struct TComputeAttack { TGameObj* attacker; long hitMode; @@ -150,10 +147,9 @@ struct CombatGcsd { DWORD flagsSource; DWORD flagsTarget; }; -#pragma pack(pop) // Script instance attached to an object or tile (spatial script). -#pragma pack(push, 1) +#pragma pack(1) struct TScript { long id; long next; @@ -179,10 +175,9 @@ struct TScript { char gap_50[4]; long procedureTable[28]; }; -#pragma pack(pop) // Script run-time data -#pragma pack(push, 1) +#pragma pack(1) struct TProgram { const char* fileName; long *codeStackPtr; @@ -200,9 +195,8 @@ struct TProgram { long gap_34; long *procTablePtr; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct ItemButtonItem { TGameObj* item; union { @@ -218,13 +212,12 @@ struct ItemButtonItem { long mode; long fid; }; -#pragma pack(pop) // When gained, the perk increases Stat by StatMag, which may be negative. All other perk effects come from being // specifically checked for by scripts or the engine. If a primary stat requirement is negative, that stat must be // below the value specified (e.g., -7 indicates a stat must be less than 7). Type is only non-zero when there // are two skill requirements. If set to 1, only one of those requirements must be met; if set to 2, both must be met. -#pragma pack(push, 1) +#pragma pack(1) struct PerkInfo { const char* Name; const char* Desc; @@ -246,16 +239,14 @@ struct PerkInfo { long Agl; long Lck; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct DbFile { long fileType; void* handle; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct sElevator { long ID1; long Elevation1; @@ -271,13 +262,13 @@ struct sElevator { long Tile4; }; +#pragma pack(1) struct sElevatorFrms { DWORD main; DWORD buttons; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct FrmFile { long id; //0x00 short fps; //0x04 @@ -294,10 +285,9 @@ struct FrmFile { short yoffset; //0x48 BYTE pixels[80 * 36]; //0x4a }; -#pragma pack(pop) //structures for holding frms loaded with fallout2 functions -#pragma pack(push, 1) +#pragma pack(1) typedef class FrmFrameData { // sizeof 12 + 1 byte public: WORD width; @@ -307,9 +297,8 @@ public: WORD y; BYTE data[1]; // begin frame data } FrmFrameData; -#pragma pack(pop) -#pragma pack(push, 2) +#pragma pack(2) typedef class FrmHeaderData { // sizeof 62 public: DWORD version; // version num @@ -321,10 +310,9 @@ public: DWORD oriOffset[6]; // offset of first frame for direction [0-5] from begining of frame area DWORD frameAreaSize; // size of all frames area } FrmHeaderData; -#pragma pack(pop) // structures for loading unlisted frms -#pragma pack(push, 1) +#pragma pack(1) struct UNLSTDfrm { DWORD version; WORD FPS; @@ -375,10 +363,9 @@ struct UNLSTDfrm { delete[] frames; } }; -#pragma pack(pop) //for holding a message -#pragma pack(push, 1) +#pragma pack(1) struct MSGNode { long number; long flags; @@ -392,10 +379,9 @@ struct MSGNode { message = nullptr; } }; -#pragma pack(pop) //for holding msg array -#pragma pack(push, 1) +#pragma pack(1) typedef struct MSGList { long numMsgs; MSGNode *nodes; @@ -405,9 +391,8 @@ typedef struct MSGList { numMsgs = 0; } } MSGList; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct CritInfo { union { struct { @@ -429,9 +414,8 @@ struct CritInfo { long values[7]; }; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct SkillInfo { const char* name; const char* description; @@ -447,36 +431,32 @@ struct SkillInfo { // 1 for Lockpick, Steal, Traps; 0 otherwise long f; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct TraitInfo { const char* Name; const char* Desc; long Image; }; -#pragma pack(pop) //fallout2 path node structure -#pragma pack(push, 1) +#pragma pack(1) struct PathNode { char* path; void* pDat; long isDat; PathNode* next; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct PremadeChar { char path[20]; DWORD fid; char unknown[20]; }; -#pragma pack(pop) //for holding window info -#pragma pack(push, 1) +#pragma pack(1) struct WINinfo { long wID; long flags; @@ -493,9 +473,8 @@ struct WINinfo { long *menuBar; long *drawFunc; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct sWindow { char name[32]; long wID; @@ -514,9 +493,8 @@ struct sWindow { long unknown7; long unknown8; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct LSData { char signature[24]; short majorVer; @@ -539,9 +517,8 @@ struct LSData { short mapNumber; char mapName[16]; }; -#pragma pack(pop) -#pragma pack(push, 1) +#pragma pack(1) struct Queue { DWORD time; long type; @@ -554,4 +531,18 @@ struct QueueRadiation { long level; long init; // 1 - for removing effect }; -#pragma pack(pop) + +struct FloatText { + long flags; + void* unknown0; + long unknown1; + long unknown2; + long unknown3; + long unknown4; + long unknown5; + long unknown6; + long unknown7; + long unknown8; + long unknown9; + void* unknown10; +}; diff --git a/sfall/MiscPatches.cpp b/sfall/MiscPatches.cpp index 22a7b0bd..6f4743a4 100644 --- a/sfall/MiscPatches.cpp +++ b/sfall/MiscPatches.cpp @@ -244,6 +244,30 @@ palColor: } } +static void __fastcall RemoveAllFloatTextObjects(DWORD tile, DWORD flags) { + if (*ptr_text_object_index > 0) { + for (size_t i = 0; i < *ptr_text_object_index; i++) { + MemFree(ptr_text_object_list[i]->unknown10); + MemFree(ptr_text_object_list[i]); + } + *ptr_text_object_index = 0; + } + __asm { + mov eax, tile; + mov edx, flags; + call tile_set_center_; + } +} + +static void __declspec(naked) obj_move_to_tile_hook() { + __asm { + mov ecx, eax; + call RemoveAllFloatTextObjects; + mov eax, ds:[_display_win]; + jmp win_draw_; // update black edges + } +} + static void AdditionalWeaponAnimsPatch() { if (GetConfigInt("Misc", "AdditionalWeaponAnims", 0)) { dlog("Applying additional weapon animations patch.", DL_INIT); @@ -617,6 +641,8 @@ void MiscPatchesInit() { dlogr(" Done", DL_INIT); } + BlockCall(0x4425E6); // Patch out ereg call + SimplePatch(0x440C2A, "Misc", "SpecialDeathGVAR", GVAR_MODOC_SHITTY_DEATH); // Remove hardcoding for maps with IDs 19 and 37 @@ -642,6 +668,11 @@ void MiscPatchesInit() { // Allow setting custom colors from the game palette for object outlines MakeCall(0x48EE00, obj_render_outline_hack); + // Remove floating text messages after moving to another map elevation + // and redraw the screen to update black edges of the map (HRP bug) + // https://github.com/phobos2077/sfall/issues/282 + HookCall(0x48A954, obj_move_to_tile_hook); + F1EngineBehaviorPatch(); DialogueFix(); AdditionalWeaponAnimsPatch(); @@ -654,9 +685,6 @@ void MiscPatchesInit() { ScienceOnCrittersPatch(); InventoryCharacterRotationSpeedPatch(); - dlogr("Patching out ereg call.", DL_INIT); - BlockCall(0x4425E6); - OverrideMusicDirPatch(); BoostScriptDialogLimitPatch(); MotionScannerFlagsPatch(); diff --git a/sfall/MiscPatches.h b/sfall/MiscPatches.h index 0bbb199a..64d95b91 100644 --- a/sfall/MiscPatches.h +++ b/sfall/MiscPatches.h @@ -21,11 +21,10 @@ void MiscPatchesInit(); void MiscPatchesExit(); -#pragma pack(push, 1) +#pragma pack(1) struct CodeData { DWORD dd; BYTE db; CodeData() : dd(0x0024548D), db(0x90) {} }; -#pragma pack(pop) diff --git a/sfall/ScriptOps/InterfaceOps.hpp b/sfall/ScriptOps/InterfaceOps.hpp index 860f0f66..7e72b578 100644 --- a/sfall/ScriptOps/InterfaceOps.hpp +++ b/sfall/ScriptOps/InterfaceOps.hpp @@ -584,10 +584,7 @@ static void mf_draw_image() { } // with x/y frame offsets WindowDisplayBuf(x + frmPtr->xshift[direction], framePtr->width, y + frmPtr->yshift[direction], framePtr->height, framePtr->data, noTrans); - __asm { - mov eax, frmPtr; - call mem_free_; - } + MemFree(frmPtr); opHandler.setReturn(1); } @@ -677,10 +674,7 @@ static void mf_draw_image_scaled() { long xy_pos = (y * w_width) + x; TransCscale(framePtr->width, framePtr->height, s_width, s_height, xy_pos, w_width, framePtr->data); // custom scaling } - __asm { - mov eax, frmPtr; - call mem_free_; - } + MemFree(frmPtr); opHandler.setReturn(1); }