From 279c524da9032d71e86d906e99f5cb32e7cd0457 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 14 May 2018 10:05:49 +0800 Subject: [PATCH 01/29] Added support for adding custom background image to the character creation/screen of the hero appearance mod (From Mr.Stalin) AppChCrt.frm (for the character creation) and AppChEdt.frm (for the character screen) should be in art/intrface, and the image size must be 640x480. --- sfall/Modules/HeroAppearance.cpp | 129 +++++++++++++++++-------------- 1 file changed, 70 insertions(+), 59 deletions(-) diff --git a/sfall/Modules/HeroAppearance.cpp b/sfall/Modules/HeroAppearance.cpp index c7268f6c9..2d4443b63 100644 --- a/sfall/Modules/HeroAppearance.cpp +++ b/sfall/Modules/HeroAppearance.cpp @@ -1503,6 +1503,7 @@ static void __declspec(naked) AddCharScrnButtons(void) { //------------------------------------------ static void __declspec(naked) FixCharScrnBack(void) { //00432B92 |. A3 A4075700 MOV DWORD PTR DS:[5707A4],EAX + int gMode; __asm { mov dword ptr ds:[FO_VAR_bckgnd], eax //surface ptr for char scrn back test eax, eax //check if frm loaded ok @@ -1512,71 +1513,81 @@ static void __declspec(naked) FixCharScrnBack(void) { mov ebp, esp sub esp, __LOCAL_SIZE pushad + mov eax, ds:[FO_VAR_glblmode] + mov gMode, eax } if (charScrnBackSurface == nullptr) { charScrnBackSurface = new BYTE [640*480]; - BYTE *OldCharScrnBackSurface = fo::var::bckgnd; //char screen background frm surface + UnlistedFrm *frm; + frm = LoadUnlistedFrm((gMode) ? "AppChCrt.frm" : "AppChEdt.frm", 6); - //copy old charscrn surface to new - sub_draw(640, 480, 640, 480, 0, 0, OldCharScrnBackSurface, 640, 480, 0, 0, charScrnBackSurface, 0); - - //copy Tag Skill Counter background to the right - sub_draw(38, 26, 640, 480, 519, 228, OldCharScrnBackSurface, 640, 480, 519+36, 228, charScrnBackSurface, 0); - //copy a blank part of the Tag Skill Bar hiding the old counter - sub_draw(38, 26, 640, 480, 460, 228, OldCharScrnBackSurface, 640, 480, 519, 228, charScrnBackSurface, 0); - - sub_draw(36, 258, 640, 480, 332, 0, OldCharScrnBackSurface, 640, 480, 408, 0, charScrnBackSurface, 0); //shift behind button rail - sub_draw(6, 32, 640, 480, 331, 233, OldCharScrnBackSurface, 640, 480, 330, 6, charScrnBackSurface, 0); //shadow for style/race button - - - DWORD FrmObj, FrmMaskObj; //frm objects for char screen Appearance button - BYTE *FrmSurface,*FrmMaskSurface; - - FrmSurface = fo::func::art_ptr_lock_data(BuildFrmId(6, 113), 0, 0, &FrmObj); - sub_draw(81, 132, 292, 376, 163, 20, FrmSurface, 640, 480, 331, 63, charScrnBackSurface, 0); //char view win - sub_draw(79, 31, 292, 376, 154, 228, FrmSurface, 640, 480, 331, 32, charScrnBackSurface, 0); //upper char view win - sub_draw(79, 30, 292, 376, 158, 236, FrmSurface, 640, 480, 331, 195, charScrnBackSurface, 0); //lower char view win - fo::func::art_ptr_unlock(FrmObj); - - //Sexoff Frm - FrmSurface = fo::func::art_ptr_lock_data(BuildFrmId(6, 188), 0, 0, &FrmObj); - //Sex button mask frm - FrmMaskSurface = fo::func::art_ptr_lock_data(BuildFrmId(6, 187), 0, 0, &FrmMaskObj); - - sub_draw(80, 28, 80, 32, 0, 0, FrmMaskSurface, 80, 32, 0, 0, FrmSurface, 0x39); //mask for style and race buttons - fo::func::art_ptr_unlock(FrmMaskObj); - FrmMaskSurface = nullptr; - - FrmSurface[80*32 - 1] = 0; - FrmSurface[80*31 - 1] = 0; - FrmSurface[80*30 - 1] = 0; - - FrmSurface[80*32 - 2] = 0; - FrmSurface[80*31 - 2] = 0; - FrmSurface[80*30 - 2] = 0; - - FrmSurface[80*32 - 3] = 0; - FrmSurface[80*31 - 3] = 0; - FrmSurface[80*30 - 3] = 0; - - FrmSurface[80*32 - 4] = 0; - FrmSurface[80*31 - 4] = 0; - FrmSurface[80*30 - 4] = 0; - - sub_draw(80, 32, 80, 32, 0, 0, FrmSurface, 640, 480, 332, 0, charScrnBackSurface, 0); //style and race buttons - sub_draw(80, 32, 80, 32, 0, 0, FrmSurface, 640, 480, 332, 225, charScrnBackSurface, 0); //style and race buttons - fo::func::art_ptr_unlock(FrmObj); - - //frm background for char screen Appearance button - FrmSurface = fo::func::art_ptr_lock_data(BuildFrmId(6, 174), 0, 0, &FrmObj); //Pickchar frm - sub_draw(69, 20, 640, 480, 282, 320, FrmSurface, 640, 480, 337, 37, charScrnBackSurface, 0); //button backround top - sub_draw(69, 20, 640, 480, 282, 320, FrmSurface, 640, 480, 337, 199, charScrnBackSurface, 0); //button backround bottom - sub_draw(47, 16, 640, 480, 94, 394, FrmSurface, 640, 480, 347, 39, charScrnBackSurface, 0); //cover buttons pics top - sub_draw(47, 16, 640, 480, 94, 394, FrmSurface, 640, 480, 347, 201, charScrnBackSurface, 0); //cover buttons pics bottom - fo::func::art_ptr_unlock(FrmObj); - FrmSurface = nullptr; + if (frm != nullptr) { + sub_draw(640, 480, 640, 480, 0, 0, frm->frames[0].indexBuff, 640, 480, 0, 0, charScrnBackSurface, 0); + delete frm; + } else { + BYTE *OldCharScrnBackSurface = fo::var::bckgnd; //char screen background frm surface + + //copy old charscrn surface to new + sub_draw(640, 480, 640, 480, 0, 0, OldCharScrnBackSurface, 640, 480, 0, 0, charScrnBackSurface, 0); + + //copy Tag Skill Counter background to the right + sub_draw(38, 26, 640, 480, 519, 228, OldCharScrnBackSurface, 640, 480, 519+36, 228, charScrnBackSurface, 0); + //copy a blank part of the Tag Skill Bar hiding the old counter + sub_draw(38, 26, 640, 480, 460, 228, OldCharScrnBackSurface, 640, 480, 519, 228, charScrnBackSurface, 0); + + sub_draw(36, 258, 640, 480, 332, 0, OldCharScrnBackSurface, 640, 480, 408, 0, charScrnBackSurface, 0); //shift behind button rail + sub_draw(6, 32, 640, 480, 331, 233, OldCharScrnBackSurface, 640, 480, 330, 6, charScrnBackSurface, 0); //shadow for style/race button + + + DWORD FrmObj, FrmMaskObj; //frm objects for char screen Appearance button + BYTE *FrmSurface,*FrmMaskSurface; + + FrmSurface = fo::func::art_ptr_lock_data(BuildFrmId(6, 113), 0, 0, &FrmObj); + sub_draw(81, 132, 292, 376, 163, 20, FrmSurface, 640, 480, 331, 63, charScrnBackSurface, 0); //char view win + sub_draw(79, 31, 292, 376, 154, 228, FrmSurface, 640, 480, 331, 32, charScrnBackSurface, 0); //upper char view win + sub_draw(79, 30, 292, 376, 158, 236, FrmSurface, 640, 480, 331, 195, charScrnBackSurface, 0); //lower char view win + fo::func::art_ptr_unlock(FrmObj); + + //Sexoff Frm + FrmSurface = fo::func::art_ptr_lock_data(BuildFrmId(6, 188), 0, 0, &FrmObj); + //Sex button mask frm + FrmMaskSurface = fo::func::art_ptr_lock_data(BuildFrmId(6, 187), 0, 0, &FrmMaskObj); + + sub_draw(80, 28, 80, 32, 0, 0, FrmMaskSurface, 80, 32, 0, 0, FrmSurface, 0x39); //mask for style and race buttons + fo::func::art_ptr_unlock(FrmMaskObj); + FrmMaskSurface = nullptr; + + FrmSurface[80*32 - 1] = 0; + FrmSurface[80*31 - 1] = 0; + FrmSurface[80*30 - 1] = 0; + + FrmSurface[80*32 - 2] = 0; + FrmSurface[80*31 - 2] = 0; + FrmSurface[80*30 - 2] = 0; + + FrmSurface[80*32 - 3] = 0; + FrmSurface[80*31 - 3] = 0; + FrmSurface[80*30 - 3] = 0; + + FrmSurface[80*32 - 4] = 0; + FrmSurface[80*31 - 4] = 0; + FrmSurface[80*30 - 4] = 0; + + sub_draw(80, 32, 80, 32, 0, 0, FrmSurface, 640, 480, 332, 0, charScrnBackSurface, 0); //style and race buttons + sub_draw(80, 32, 80, 32, 0, 0, FrmSurface, 640, 480, 332, 225, charScrnBackSurface, 0); //style and race buttons + fo::func::art_ptr_unlock(FrmObj); + + //frm background for char screen Appearance button + FrmSurface = fo::func::art_ptr_lock_data(BuildFrmId(6, 174), 0, 0, &FrmObj); //Pickchar frm + sub_draw(69, 20, 640, 480, 282, 320, FrmSurface, 640, 480, 337, 37, charScrnBackSurface, 0); //button backround top + sub_draw(69, 20, 640, 480, 282, 320, FrmSurface, 640, 480, 337, 199, charScrnBackSurface, 0); //button backround bottom + sub_draw(47, 16, 640, 480, 94, 394, FrmSurface, 640, 480, 347, 39, charScrnBackSurface, 0); //cover buttons pics top + sub_draw(47, 16, 640, 480, 94, 394, FrmSurface, 640, 480, 347, 201, charScrnBackSurface, 0); //cover buttons pics bottom + fo::func::art_ptr_unlock(FrmObj); + FrmSurface = nullptr; + } int oldFont; oldFont = GetFont(); From 470a0b3386fdb38822cd56c8b255d47c9ec2783f Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 14 May 2018 20:52:26 +0800 Subject: [PATCH 02/29] Simplified the code from previous commit. --- sfall/Modules/HeroAppearance.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sfall/Modules/HeroAppearance.cpp b/sfall/Modules/HeroAppearance.cpp index 2d4443b63..5d615370a 100644 --- a/sfall/Modules/HeroAppearance.cpp +++ b/sfall/Modules/HeroAppearance.cpp @@ -1503,7 +1503,6 @@ static void __declspec(naked) AddCharScrnButtons(void) { //------------------------------------------ static void __declspec(naked) FixCharScrnBack(void) { //00432B92 |. A3 A4075700 MOV DWORD PTR DS:[5707A4],EAX - int gMode; __asm { mov dword ptr ds:[FO_VAR_bckgnd], eax //surface ptr for char scrn back test eax, eax //check if frm loaded ok @@ -1513,15 +1512,13 @@ static void __declspec(naked) FixCharScrnBack(void) { mov ebp, esp sub esp, __LOCAL_SIZE pushad - mov eax, ds:[FO_VAR_glblmode] - mov gMode, eax } if (charScrnBackSurface == nullptr) { charScrnBackSurface = new BYTE [640*480]; UnlistedFrm *frm; - frm = LoadUnlistedFrm((gMode) ? "AppChCrt.frm" : "AppChEdt.frm", 6); + frm = LoadUnlistedFrm((FO_VAR_glblmode) ? "AppChCrt.frm" : "AppChEdt.frm", 6); if (frm != nullptr) { sub_draw(640, 480, 640, 480, 0, 0, frm->frames[0].indexBuff, 640, 480, 0, 0, charScrnBackSurface, 0); @@ -1614,8 +1611,8 @@ static void __declspec(naked) FixCharScrnBack(void) { mov esp, ebp //epilog pop ebp mov eax, charScrnBackSurface -EndFunc: mov dword ptr ds:[FO_VAR_bckgnd], eax //surface ptr for char scrn back +EndFunc: retn } } From 56fdec8b37b800bad7355fbeab6ab85ef309aec3 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 14 May 2018 21:14:50 +0800 Subject: [PATCH 03/29] Reverted the previous changes of ASM code due to the bug that AppChCrt.frm overwrites AppChEdt.frm. --- sfall/Modules/HeroAppearance.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sfall/Modules/HeroAppearance.cpp b/sfall/Modules/HeroAppearance.cpp index 5d615370a..9222db385 100644 --- a/sfall/Modules/HeroAppearance.cpp +++ b/sfall/Modules/HeroAppearance.cpp @@ -1503,6 +1503,7 @@ static void __declspec(naked) AddCharScrnButtons(void) { //------------------------------------------ static void __declspec(naked) FixCharScrnBack(void) { //00432B92 |. A3 A4075700 MOV DWORD PTR DS:[5707A4],EAX + int gMode; __asm { mov dword ptr ds:[FO_VAR_bckgnd], eax //surface ptr for char scrn back test eax, eax //check if frm loaded ok @@ -1512,13 +1513,15 @@ static void __declspec(naked) FixCharScrnBack(void) { mov ebp, esp sub esp, __LOCAL_SIZE pushad + mov eax, ds:[FO_VAR_glblmode] + mov gMode, eax } if (charScrnBackSurface == nullptr) { charScrnBackSurface = new BYTE [640*480]; UnlistedFrm *frm; - frm = LoadUnlistedFrm((FO_VAR_glblmode) ? "AppChCrt.frm" : "AppChEdt.frm", 6); + frm = LoadUnlistedFrm((gMode) ? "AppChCrt.frm" : "AppChEdt.frm", 6); if (frm != nullptr) { sub_draw(640, 480, 640, 480, 0, 0, frm->frames[0].indexBuff, 640, 480, 0, 0, charScrnBackSurface, 0); From b9c7f5ea82eebff14a3abdc4209713d274c8b7f0 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 15 May 2018 20:20:07 +0800 Subject: [PATCH 04/29] Fixed commit 470a0b3386fdb38822cd56c8b255d47c9ec2783f. --- sfall/Modules/HeroAppearance.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sfall/Modules/HeroAppearance.cpp b/sfall/Modules/HeroAppearance.cpp index 9222db385..d2c353005 100644 --- a/sfall/Modules/HeroAppearance.cpp +++ b/sfall/Modules/HeroAppearance.cpp @@ -1503,7 +1503,6 @@ static void __declspec(naked) AddCharScrnButtons(void) { //------------------------------------------ static void __declspec(naked) FixCharScrnBack(void) { //00432B92 |. A3 A4075700 MOV DWORD PTR DS:[5707A4],EAX - int gMode; __asm { mov dword ptr ds:[FO_VAR_bckgnd], eax //surface ptr for char scrn back test eax, eax //check if frm loaded ok @@ -1513,15 +1512,13 @@ static void __declspec(naked) FixCharScrnBack(void) { mov ebp, esp sub esp, __LOCAL_SIZE pushad - mov eax, ds:[FO_VAR_glblmode] - mov gMode, eax } if (charScrnBackSurface == nullptr) { charScrnBackSurface = new BYTE [640*480]; UnlistedFrm *frm; - frm = LoadUnlistedFrm((gMode) ? "AppChCrt.frm" : "AppChEdt.frm", 6); + frm = LoadUnlistedFrm((*(long*)FO_VAR_glblmode) ? "AppChCrt.frm" : "AppChEdt.frm", 6); if (frm != nullptr) { sub_draw(640, 480, 640, 480, 0, 0, frm->frames[0].indexBuff, 640, 480, 0, 0, charScrnBackSurface, 0); From e0c0b9ba19a3f1c01f3b68db6646e221dc8690d6 Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Mon, 21 May 2018 05:41:59 +0300 Subject: [PATCH 05/29] Added function 'set_iface_tag_text' - sets custom text and color to bar boxes. (#152) --- artifacts/scripting/headers/sfall.h | 1 + sfall/FalloutEngine/Functions_def.h | 1 + sfall/FalloutEngine/VariableOffsets.h | 5 + sfall/FalloutEngine/Variables_def.h | 5 + sfall/Modules/BarBoxes.cpp | 158 ++++++++++++++++-- sfall/Modules/BarBoxes.h | 2 + .../Modules/Scripting/Handlers/Interface.cpp | 12 +- sfall/Modules/Scripting/Handlers/Interface.h | 2 + sfall/Modules/Scripting/Handlers/Metarule.cpp | 1 + 9 files changed, 168 insertions(+), 19 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 6114f980f..7af342605 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -240,6 +240,7 @@ #define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode) #define set_dude_obj(critter) sfall_func1("set_dude_obj", critter) #define set_flags(obj, flags) sfall_func2("set_flags", obj, flags) +#define set_iface_tag_text(tagId, text, clr) sfall_func3("set_iface_tag_text", tagId, text, clr) #define set_ini_setting(setting, value) sfall_func2("set_ini_setting", setting, value) #define set_map_enter_position(tile, elev, rot) sfall_func3("set_map_enter_position", tile, elev, rot) #define set_outline(obj, color) sfall_func2("set_outline", obj, color) diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index 9ebda0e4e..0f96d09a2 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -30,6 +30,7 @@ WRAP_WATCOM_FUNC3(long, db_freadShortCount, DbFile*, file, WORD*, dest, long, co WRAP_WATCOM_FUNC3(long, db_freadIntCount, DbFile*, file, DWORD*, dest, long, count) WRAP_WATCOM_FUNC2(long, db_fwriteByte, DbFile*, file, long, value) WRAP_WATCOM_FUNC2(long, db_fwriteInt, DbFile*, file, long, value) +WRAP_WATCOM_FUNC0(void, display_stats) // perform combat turn for a given critter WRAP_WATCOM_FUNC2(long, combat_turn, GameObject*, critter, long, isDudeTurn) WRAP_WATCOM_FUNC1(long, critter_is_dead, GameObject*, critter) diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index 3f9b7cca0..4f44dd7ac 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -195,3 +195,8 @@ #define FO_VAR_world_ypos 0x672E10 #define FO_VAR_WorldMapCurrArea 0x672E08 #define FO_VAR_YellowColor 0x6AB8BB + +#define FO_VAR_BlueColor 0x6A38EF +#define FO_VAR_GoodColor 0x6AB4EF +#define FO_VAR_PeanutButter 0x6A82F3 +#define FO_VAR_WhiteColor 0x6AB8CF \ No newline at end of file diff --git a/sfall/FalloutEngine/Variables_def.h b/sfall/FalloutEngine/Variables_def.h index fe41348ba..281ceb79e 100644 --- a/sfall/FalloutEngine/Variables_def.h +++ b/sfall/FalloutEngine/Variables_def.h @@ -191,6 +191,11 @@ VAR_(world_ypos, DWORD) VAR_(WorldMapCurrArea, DWORD) VAR_(YellowColor, BYTE) +VAR_(BlueColor, BYTE) +VAR_(GoodColor, BYTE) +VAR_(PeanutButter, BYTE) +VAR_(WhiteColor, BYTE) + #undef VAR_ #undef VARP #undef VARA diff --git a/sfall/Modules/BarBoxes.cpp b/sfall/Modules/BarBoxes.cpp index 24cd5b92b..aa6dbd919 100644 --- a/sfall/Modules/BarBoxes.cpp +++ b/sfall/Modules/BarBoxes.cpp @@ -18,6 +18,7 @@ #include "..\main.h" #include "..\FalloutEngine\Fallout2.h" +#include "LoadGameHook.h" #include "BarBoxes.h" @@ -26,6 +27,9 @@ namespace sfall static const DWORD DisplayBoxesRet1 = 0x4615A8; static const DWORD DisplayBoxesRet2 = 0x4615BE; +static const DWORD SetIndexBoxRet = 0x4612E8; + +#define sSize 12 struct sBox { DWORD msg; DWORD colour; @@ -34,6 +38,17 @@ struct sBox { static sBox boxes[10]; static DWORD boxesEnabled[5]; +#define tSize 28 +struct tBox { + DWORD hasText; + DWORD color; + char text[tSize - 8]; +}; +static tBox boxText[5]; + +static DWORD clrBakup[5]; +static bool setCustomBoxText; + static void __declspec(naked) DisplayBoxesHook() { __asm { mov ebx, 0; @@ -56,39 +71,147 @@ static void __declspec(naked) DisplayBoxesHook() { } } +static void __declspec(naked) BarBoxesTextHack() { + __asm { + //mov ecx, [esp+0x440-0x1C]; + push ecx; // ecx = BoxIndex + sub ecx, 5; + imul ecx, tSize; + cmp boxText[ecx], 1; // .hasText + jnz end; + // get color + mov ebx, boxText[ecx+4]; // .color + // set text + lea eax, [boxText+ecx+8]; // .text + // set color + pop ecx; + imul ecx, sSize; + cmp boxes[ecx+4], 2; // .colour + jb skip; + mov [esp+0x440-0x20], ebx; // Color +skip: + retn; +end: + add esp, 4; + jmp fo::funcoffs::getmsg_; + } +} + +static void __declspec(naked) BarBoxesIndexHack() { + __asm { + mov eax, ds:[0x4612E2]; // fontnum + mov ecx, 5; // start index + mov edx, ecx; + jmp SetIndexBoxRet; + } +} + +static void ReconstructBarBoxes() { + __asm { + call fo::funcoffs::refresh_box_bar_win_; + call fo::funcoffs::reset_box_bar_win_; + call fo::funcoffs::construct_box_bar_win_; + } +} + +void BarBoxes::SetText(int box, const char* text, DWORD color) { + boxes[box].colour = color; + box -= 5; + boxText[box].hasText = 1; + strncpy_s(boxText[box].text, text, _TRUNCATE); + + DWORD clr; + switch (color) { + case 2: + clr = fo::var::WhiteColor; + break; + case 3: + clr = fo::var::YellowColor; + break; + case 4: + clr = fo::var::PeanutButter; + break; + case 5: + clr = fo::var::BlueColor; + break; + case 6: + clr = fo::var::GoodColor; + break; + default: + clr = fo::var::GreenColor; + } + boxText[box].color = clr; + + int enabled[5]; + for (int i = 0; i < 5; i++) { + enabled[i] = boxesEnabled[i]; + boxesEnabled[i] = 0; + } + + if (!setCustomBoxText) { + MakeCall(0x461342, BarBoxesTextHack); + MakeJump(0x461243, BarBoxesIndexHack); + setCustomBoxText = true; + } + + ReconstructBarBoxes(); + + for (int i = 0; i < 5; i++) { + boxesEnabled[i] = enabled[i]; + } + __asm call refresh_box_bar_win_; +} + +static void ResetBoxes() { + for (int i = 0; i < 5; i++) { + boxesEnabled[i] = 0; + boxes[i + 5].colour = clrBakup[i]; + } + + if (!setCustomBoxText) return; + + //Restore boxes + SafeWrite32(0x461343, 0x23D05); // call + ReconstructBarBoxes(); + SafeWrite8(0x461243, 0x31); + SafeWrite32(0x461244, 0x249489D2); + + setCustomBoxText = false; +} + void BarBoxes::init() { - SafeWrite32(0x461266, (DWORD)boxes + 8); - SafeWrite32(0x4612AC, (DWORD)boxes + 8); - SafeWrite32(0x4612FE, (DWORD)boxes + 4); - SafeWrite32(0x46133C, (DWORD)boxes + 0); - SafeWrite32(0x461374, (DWORD)boxes + 8); - SafeWrite32(0x4613E8, (DWORD)boxes + 8); - - SafeWrite32(0x461479, (DWORD)boxes + 8); - SafeWrite32(0x46148C, (DWORD)boxes + 8); - SafeWrite32(0x4616BB, (DWORD)boxes + 8); - - memset(boxes, 0, 12 * 10); + DWORD addr[] = {0x461266, 0x4612AC, 0x461374, 0x4613E8, 0x461479, 0x46148C, 0x4616BB}; + for (int i = 0; i < 7; i++) + SafeWrite32(addr[i], (DWORD)boxes + 8); //.mem + SafeWrite32(0x4612FE, (DWORD)boxes + 4); //.colour + SafeWrite32(0x46133C, (DWORD)boxes); //.msg + + int size = sSize * 10; + memset(boxes, 0, size); memset(boxesEnabled, 0, 5 * 4); - memcpy(boxes, (void*)0x518FE8, 12 * 5); + memcpy(boxes, (void*)0x518FE8, sSize * 5); for (int i = 5; i < 10; i++) { - boxes[i].msg = 0x69 + i - 5; + boxes[i].msg = 100 + i; } SafeWrite8(0x46127C, 10); SafeWrite8(0x46140B, 10); - SafeWrite8(0x461495, 0x78); + SafeWrite8(0x461495, size); MakeJump(0x4615A3, DisplayBoxesHook); auto boxBarColors = GetConfigString("Misc", "BoxBarColours", "", 6); - if (boxBarColors.size() == 5) { + if (boxBarColors.size() >= 5) { for (int i = 0; i < 5; i++) { if (boxBarColors[i] == '1') { boxes[i + 5].colour = 1; - } + clrBakup[i] = 1; + } else + clrBakup[i] = 0; } } + + LoadGameHook::OnGameReset() += ResetBoxes; } int _stdcall GetBox(int i) { @@ -105,5 +228,4 @@ void _stdcall RemoveBox(int i) { if (i < 5 || i > 9) return; boxesEnabled[i - 5] = 0; } - } diff --git a/sfall/Modules/BarBoxes.h b/sfall/Modules/BarBoxes.h index 5d7b2ed91..e73d7aabc 100644 --- a/sfall/Modules/BarBoxes.h +++ b/sfall/Modules/BarBoxes.h @@ -7,6 +7,8 @@ class BarBoxes : public Module { public: const char* name() { return "BarBoxes"; } void init(); + + static void SetText(int box, const char* text, DWORD color); }; int _stdcall GetBox(int i); diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index f41d5de43..aa8506a64 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -453,7 +453,17 @@ void sf_set_cursor_mode(OpcodeContext& ctx) { void sf_display_stats(OpcodeContext& ctx) { // calling the function outside of inventory screen will crash the game if (GetLoopFlags() & INVENTORY) { - __asm call fo::funcoffs::display_stats_ + fo::func::display_stats(); + } +} + +void sf_set_iface_tag_text(OpcodeContext& ctx) { + int boxTag = ctx.arg(0).asInt(); + + if (boxTag > 4 && boxTag < 10) { + BarBoxes::SetText(boxTag, ctx.arg(1).asString(), ctx.arg(2).asInt()); + } else { + ctx.printOpcodeError("set_iface_tag_text: value of TagId should be range from 5 to 9."); } } diff --git a/sfall/Modules/Scripting/Handlers/Interface.h b/sfall/Modules/Scripting/Handlers/Interface.h index 69ce8d1cb..1b7b65775 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.h +++ b/sfall/Modules/Scripting/Handlers/Interface.h @@ -89,5 +89,7 @@ void sf_set_cursor_mode(OpcodeContext&); void sf_display_stats(OpcodeContext&); +void sf_set_iface_tag_text(OpcodeContext&); + } } diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index e3ab6ad4e..94c7a4531 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -102,6 +102,7 @@ static const SfallMetarule metarules[] = { {"set_cursor_mode", sf_set_cursor_mode, 1, 1, {ARG_INT}}, {"set_dude_obj", sf_set_dude_obj, 1, 1, {ARG_OBJECT}}, {"set_flags", sf_set_flags, 2, 2, {ARG_OBJECT, ARG_INT}}, + {"set_iface_tag_text", sf_set_iface_tag_text, 3, 3, {ARG_INT, ARG_STRING, ARG_INT}}, {"set_ini_setting", sf_set_ini_setting, 2, 2, {ARG_STRING, ARG_INTSTR}}, {"set_map_enter_position", sf_set_map_enter_position, 3, 3, {ARG_INT, ARG_INT, ARG_INT}}, {"set_outline", sf_set_outline, 2, 2, {ARG_OBJECT, ARG_INT}}, From c4903abd4c15f9bc46c942c4523f92a102c98416 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 21 May 2018 10:51:12 +0800 Subject: [PATCH 06/29] Added the description of set_iface_tag_text to notes.txt. Fixed compilation error in BarBoxes.cpp. Updated version number. --- artifacts/ddraw.ini | 2 +- artifacts/scripting/headers/sfall.h | 2 +- artifacts/scripting/sfall function notes.txt | 6 + sfall/FalloutEngine/VariableOffsets.h | 9 +- sfall/FalloutEngine/Variables_def.h | 9 +- sfall/Modules/BarBoxes.cpp | 108 +++++++++--------- .../Modules/Scripting/Handlers/Interface.cpp | 2 +- sfall/version.h | 6 +- 8 files changed, 76 insertions(+), 68 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index f7da10dd0..7b3c70268 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -1,5 +1,5 @@ ;sfall configuration settings -;v4.0.4 +;v4.0.5 [Main] ;Change to 1 if you want to use command line args to tell sfall to use another ini file. diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 7af342605..0c077e028 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -240,7 +240,7 @@ #define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode) #define set_dude_obj(critter) sfall_func1("set_dude_obj", critter) #define set_flags(obj, flags) sfall_func2("set_flags", obj, flags) -#define set_iface_tag_text(tagId, text, clr) sfall_func3("set_iface_tag_text", tagId, text, clr) +#define set_iface_tag_text(tag, text, color) sfall_func3("set_iface_tag_text", tag, text, color) #define set_ini_setting(setting, value) sfall_func2("set_ini_setting", setting, value) #define set_map_enter_position(tile, elev, rot) sfall_func3("set_map_enter_position", tile, elev, rot) #define set_outline(obj, color) sfall_func2("set_outline", obj, color) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index c9f0aa7c5..7c7820226 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -476,6 +476,12 @@ Some utility/math functions are available: > int sfall_func0("attack_is_aimed") - returns 1 if the aimed attack mode is selected, 0 otherwise +> void sfall_func3("set_iface_tag_text", int tag, string text, int color) +- sets the text messages and colors for custom notification boxes to the interface without the need to add messages to intrface.msg and set up the font colors in ddraw.ini +- tag value is the same as used in show_iface_tag, hide_iface_tag, and is_iface_tag_active. The valid range is from 5 to 9 (custom boxes) +- The text is limited to 19 characters +- available colors: 0 - green, 1 - red, 2 - white, 3 - yellow, 4 - dark yellow, 5 - blue, 6 - purple + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index 4f44dd7ac..976fa32e6 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -14,6 +14,7 @@ #define FO_VAR_art_vault_person_nums 0x5108A8 #define FO_VAR_bckgnd 0x5707A4 #define FO_VAR_black_palette 0x663FD0 +#define FO_VAR_BlueColor 0x6A38EF #define FO_VAR_bottom_line 0x664524 #define FO_VAR_btable 0x59E944 #define FO_VAR_btncnt 0x43EA1C @@ -61,6 +62,7 @@ #define FO_VAR_glblmode 0x5709D0 #define FO_VAR_gmouse_current_cursor 0x518C0C #define FO_VAR_gmovie_played_list 0x596C78 +#define FO_VAR_GoodColor 0x6AB4EF #define FO_VAR_GreenColor 0x6A3CB0 #define FO_VAR_gsound_initialized 0x518E30 #define FO_VAR_hit_location_penalty 0x510954 @@ -136,6 +138,7 @@ #define FO_VAR_pc_proto 0x51C370 #define FO_VAR_pc_trait 0x66BE40 #define FO_VAR_pc_trait2 0x66BE44 +#define FO_VAR_PeanutButter 0x6A82F3 #define FO_VAR_perk_data 0x519DCC #define FO_VAR_perkLevelDataList 0x51C120 #define FO_VAR_pip_win 0x6644C4 @@ -187,6 +190,7 @@ #define FO_VAR_trait_data 0x51DB84 #define FO_VAR_view_page 0x664520 #define FO_VAR_wd_obj 0x59E98C +#define FO_VAR_WhiteColor 0x6AB8CF #define FO_VAR_wmAreaInfoList 0x51DDF8 #define FO_VAR_wmLastRndTime 0x51DEA0 #define FO_VAR_wmWorldOffsetX 0x51DE2C @@ -195,8 +199,3 @@ #define FO_VAR_world_ypos 0x672E10 #define FO_VAR_WorldMapCurrArea 0x672E08 #define FO_VAR_YellowColor 0x6AB8BB - -#define FO_VAR_BlueColor 0x6A38EF -#define FO_VAR_GoodColor 0x6AB4EF -#define FO_VAR_PeanutButter 0x6A82F3 -#define FO_VAR_WhiteColor 0x6AB8CF \ No newline at end of file diff --git a/sfall/FalloutEngine/Variables_def.h b/sfall/FalloutEngine/Variables_def.h index 281ceb79e..4fd1585d7 100644 --- a/sfall/FalloutEngine/Variables_def.h +++ b/sfall/FalloutEngine/Variables_def.h @@ -12,6 +12,7 @@ VAR_(art_vault_guy_num, DWORD) VAR_(art_vault_person_nums, DWORD) VAR_(bckgnd, BYTE*) VAR_(black_palette, DWORD) +VAR_(BlueColor, BYTE) VAR_(bottom_line, DWORD) VAR_(btable, DWORD) VAR_(btncnt, DWORD) @@ -58,6 +59,7 @@ VAR_(gIsSteal, DWORD) VAR_(glblmode, DWORD) VAR_(gmouse_current_cursor, long) VARA(gmovie_played_list, BYTE, 17) +VAR_(GoodColor, BYTE) VAR_(GreenColor, BYTE) VAR_(gsound_initialized, DWORD) VARA(hit_location_penalty, long, 9) @@ -131,6 +133,7 @@ VAR_(pc_kill_counts, DWORD) VARA(pc_name, char, 32) VAR_(pc_proto, Proto) VARA(pc_trait, long, 2) // 2 of them +VAR_(PeanutButter, BYTE) VARA(perk_data, PerkInfo, PERK_count) VAR_(perkLevelDataList, long*) // dynamic array, limited to PERK_Count VAR_(pip_win, DWORD) @@ -182,6 +185,7 @@ VAR_(title_font, DWORD) VARA(trait_data, TraitInfo, TRAIT_count) VAR_(view_page, DWORD) VAR_(wd_obj, DWORD) +VAR_(WhiteColor, BYTE) VAR_(wmAreaInfoList, DWORD) VAR_(wmLastRndTime, DWORD) VAR_(wmWorldOffsetX, DWORD) @@ -191,11 +195,6 @@ VAR_(world_ypos, DWORD) VAR_(WorldMapCurrArea, DWORD) VAR_(YellowColor, BYTE) -VAR_(BlueColor, BYTE) -VAR_(GoodColor, BYTE) -VAR_(PeanutButter, BYTE) -VAR_(WhiteColor, BYTE) - #undef VAR_ #undef VARP #undef VARA diff --git a/sfall/Modules/BarBoxes.cpp b/sfall/Modules/BarBoxes.cpp index aa6dbd919..f8c3502d5 100644 --- a/sfall/Modules/BarBoxes.cpp +++ b/sfall/Modules/BarBoxes.cpp @@ -22,14 +22,14 @@ #include "BarBoxes.h" -namespace sfall +namespace sfall { static const DWORD DisplayBoxesRet1 = 0x4615A8; static const DWORD DisplayBoxesRet2 = 0x4615BE; static const DWORD SetIndexBoxRet = 0x4612E8; -#define sSize 12 +#define sSize (12) struct sBox { DWORD msg; DWORD colour; @@ -38,7 +38,7 @@ struct sBox { static sBox boxes[10]; static DWORD boxesEnabled[5]; -#define tSize 28 +#define tSize (28) struct tBox { DWORD hasText; DWORD color; @@ -49,6 +49,10 @@ static tBox boxText[5]; static DWORD clrBakup[5]; static bool setCustomBoxText; +static const DWORD bboxMemAddr[] = { + 0x461266, 0x4612AC, 0x461374, 0x4613E8, 0x461479, 0x46148C, 0x4616BB, +}; + static void __declspec(naked) DisplayBoxesHook() { __asm { mov ebx, 0; @@ -73,22 +77,22 @@ static void __declspec(naked) DisplayBoxesHook() { static void __declspec(naked) BarBoxesTextHack() { __asm { - //mov ecx, [esp+0x440-0x1C]; - push ecx; // ecx = BoxIndex + //mov ecx, [esp + 0x440 - 0x1C]; + push ecx; // ecx = BoxIndex sub ecx, 5; imul ecx, tSize; - cmp boxText[ecx], 1; // .hasText + cmp boxText[ecx], 1; // .hasText jnz end; // get color - mov ebx, boxText[ecx+4]; // .color + mov ebx, boxText[ecx + 4]; // .color // set text - lea eax, [boxText+ecx+8]; // .text + lea eax, [boxText + ecx + 8]; // .text // set color pop ecx; imul ecx, sSize; - cmp boxes[ecx+4], 2; // .colour + cmp boxes[ecx + 4], 2; // .colour jb skip; - mov [esp+0x440-0x20], ebx; // Color + mov [esp + 0x440 - 0x20], ebx; // Color skip: retn; end: @@ -114,6 +118,23 @@ static void ReconstructBarBoxes() { } } +static void ResetBoxes() { + for (int i = 0; i < 5; i++) { + boxesEnabled[i] = 0; + boxes[i + 5].colour = clrBakup[i]; + } + + if (!setCustomBoxText) return; + + //Restore boxes + SafeWrite32(0x461343, 0x00023D05); // call getmsg_ + ReconstructBarBoxes(); + SafeWrite8(0x461243, 0x31); + SafeWrite32(0x461244, 0x249489D2); + + setCustomBoxText = false; +} + void BarBoxes::SetText(int box, const char* text, DWORD color) { boxes[box].colour = color; box -= 5; @@ -122,28 +143,28 @@ void BarBoxes::SetText(int box, const char* text, DWORD color) { DWORD clr; switch (color) { - case 2: - clr = fo::var::WhiteColor; - break; - case 3: - clr = fo::var::YellowColor; - break; - case 4: - clr = fo::var::PeanutButter; - break; - case 5: - clr = fo::var::BlueColor; - break; - case 6: - clr = fo::var::GoodColor; - break; - default: - clr = fo::var::GreenColor; + case 2: + clr = fo::var::WhiteColor; + break; + case 3: + clr = fo::var::YellowColor; + break; + case 4: + clr = fo::var::PeanutButter; + break; + case 5: + clr = fo::var::BlueColor; + break; + case 6: + clr = fo::var::GoodColor; + break; + default: + clr = fo::var::GreenColor; } boxText[box].color = clr; int enabled[5]; - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) { enabled[i] = boxesEnabled[i]; boxesEnabled[i] = 0; } @@ -159,32 +180,13 @@ void BarBoxes::SetText(int box, const char* text, DWORD color) { for (int i = 0; i < 5; i++) { boxesEnabled[i] = enabled[i]; } - __asm call refresh_box_bar_win_; -} - -static void ResetBoxes() { - for (int i = 0; i < 5; i++) { - boxesEnabled[i] = 0; - boxes[i + 5].colour = clrBakup[i]; - } - - if (!setCustomBoxText) return; - - //Restore boxes - SafeWrite32(0x461343, 0x23D05); // call - ReconstructBarBoxes(); - SafeWrite8(0x461243, 0x31); - SafeWrite32(0x461244, 0x249489D2); - - setCustomBoxText = false; + __asm call fo::funcoffs::refresh_box_bar_win_; } void BarBoxes::init() { - DWORD addr[] = {0x461266, 0x4612AC, 0x461374, 0x4613E8, 0x461479, 0x46148C, 0x4616BB}; - for (int i = 0; i < 7; i++) - SafeWrite32(addr[i], (DWORD)boxes + 8); //.mem - SafeWrite32(0x4612FE, (DWORD)boxes + 4); //.colour - SafeWrite32(0x46133C, (DWORD)boxes); //.msg + SafeWriteBatch((DWORD)boxes + 8, bboxMemAddr); //.mem + SafeWrite32(0x4612FE, (DWORD)boxes + 4); //.colour + SafeWrite32(0x46133C, (DWORD)boxes); //.msg int size = sSize * 10; memset(boxes, 0, size); @@ -206,8 +208,9 @@ void BarBoxes::init() { if (boxBarColors[i] == '1') { boxes[i + 5].colour = 1; clrBakup[i] = 1; - } else + } else { clrBakup[i] = 0; + } } } @@ -228,4 +231,5 @@ void _stdcall RemoveBox(int i) { if (i < 5 || i > 9) return; boxesEnabled[i - 5] = 0; } + } diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index aa8506a64..fade89228 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -463,7 +463,7 @@ void sf_set_iface_tag_text(OpcodeContext& ctx) { if (boxTag > 4 && boxTag < 10) { BarBoxes::SetText(boxTag, ctx.arg(1).asString(), ctx.arg(2).asInt()); } else { - ctx.printOpcodeError("set_iface_tag_text: value of TagId should be range from 5 to 9."); + ctx.printOpcodeError("set_iface_tag_text() - tag value must be in the range of 5 to 9."); } } diff --git a/sfall/version.h b/sfall/version.h index 806be3989..7357e3389 100644 --- a/sfall/version.h +++ b/sfall/version.h @@ -24,13 +24,13 @@ #define VERSION_MAJOR 4 #define VERSION_MINOR 0 -#define VERSION_BUILD 4 +#define VERSION_BUILD 5 #define VERSION_REV 0 #ifdef WIN2K -#define VERSION_STRING "4.0.4 win2k" +#define VERSION_STRING "4.0.5 win2k" #else -#define VERSION_STRING "4.0.4" +#define VERSION_STRING "4.0.5" #endif #define CHECK_VAL (4) From eeef8759d3219733eaf855186fb4d8e4e8309aa3 Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Sun, 27 May 2018 09:48:09 +0300 Subject: [PATCH 07/29] Display statistics of the weapon's range for the second attack mode in player inventory. (#154) --- sfall/Modules/MiscPatches.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index 5d5b679cf..f16ca9597 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -365,6 +365,28 @@ static void __declspec(naked) objCanSeeObj_ShootThru_Fix() {//(EAX *objStruct, E } } +static DWORD __fastcall GetWeaponSlotMode(DWORD itemPtr, DWORD mode) { + int slot = (mode > 0) ? 1 : 0; + auto itemButton = fo::var::itemButtonItems; + if ((DWORD)itemButton.vals[slot].item == itemPtr && (DWORD)itemButton.vals[slot].mode == 3) { + mode++; + } + return mode; +} + +static void __declspec(naked) display_weapon_range_hook() { + __asm { + push eax; + push ecx; + mov ecx, ds:[esp + edi + 0xA8 + 0xC]; // get itemPtr + call GetWeaponSlotMode; // ecx - itemPtr, edx - mode; + mov edx, eax; + pop ecx; + pop eax; + jmp fo::funcoffs::item_w_range_; + } +} + static const DWORD EncounterTableSize[] = { 0x4BD1A3, 0x4BD1D9, 0x4BD270, 0x4BD604, 0x4BDA14, 0x4BDA44, 0x4BE707, 0x4C0815, 0x4C0D4A, 0x4C0FD4, @@ -754,6 +776,14 @@ void DisableHorriganPatch() { } } +void DisplaySecondWeaponRangePatch() { + if (GetConfigInt("Misc", "ShowSecondWeaponRange", 1)) { + dlog("Applying show second weapon range patch.", DL_INIT); + HookCall(0x472201, display_weapon_range_hook); + dlogr(" Done", DL_INIT); + } +} + void MiscPatches::init() { mapName[64] = 0; if (GetConfigString("Misc", "StartingMap", "", mapName, 64)) { @@ -825,6 +855,7 @@ void MiscPatches::init() { NumbersInDialoguePatch(); PipboyAvailableAtStartPatch(); DisableHorriganPatch(); + DisplaySecondWeaponRangePatch(); } void MiscPatches::exit() { From 839e86ed26dfb5e573322add9c9b79b0d99d5c03 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sun, 27 May 2018 15:08:46 +0800 Subject: [PATCH 08/29] Added the description and setting for the previous commit to ddraw.ini. Improved DisablePipboyAlarm so that when the player press Z key they won't see a blank Pipboy screen. --- artifacts/ddraw.ini | 3 +++ sfall/Modules/MiscPatches.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 7b3c70268..20cb28f71 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -401,6 +401,9 @@ BonusHtHDamageFix=1 ;Set to 1 to display additional points of damage from Bonus HtH/Ranged Damage perks in the inventory DisplayBonusDamage=0 +;Set to 1 to display the range of the second attack mode in the inventory when you switch weapon modes in active item slots +DisplaySecondWeaponRange=1 + ;Modify the maximum number of animations allowed to run on a map. (Default is 32, and the maximum is 127) AnimationsAtOnceLimit=120 diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index f16ca9597..21a032f8b 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -374,7 +374,7 @@ static DWORD __fastcall GetWeaponSlotMode(DWORD itemPtr, DWORD mode) { return mode; } -static void __declspec(naked) display_weapon_range_hook() { +static void __declspec(naked) display_stats_hook() { __asm { push eax; push ecx; @@ -671,6 +671,7 @@ void DisablePipboyAlarmPatch() { if (GetConfigInt("Misc", "DisablePipboyAlarm", 0)) { dlog("Applying Disable Pip-Boy alarm button patch.", DL_INIT); SafeWrite8(0x499518, 0xC3); + SafeWrite8(0x443601, 0x0); dlogr(" Done", DL_INIT); } } @@ -777,9 +778,9 @@ void DisableHorriganPatch() { } void DisplaySecondWeaponRangePatch() { - if (GetConfigInt("Misc", "ShowSecondWeaponRange", 1)) { - dlog("Applying show second weapon range patch.", DL_INIT); - HookCall(0x472201, display_weapon_range_hook); + if (GetConfigInt("Misc", "DisplaySecondWeaponRange", 1)) { + dlog("Applying display second weapon range patch.", DL_INIT); + HookCall(0x472201, display_stats_hook); dlogr(" Done", DL_INIT); } } From 04bd88cdc28ff862066584003ad9f9df04feea1a Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Mon, 28 May 2018 04:18:55 +0300 Subject: [PATCH 09/29] Added MoreTiles option to increase the limit of FRM images for tiles from 4096 to 16383 (from Crafty) (#156) --- sfall/Modules/Tiles.cpp | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/sfall/Modules/Tiles.cpp b/sfall/Modules/Tiles.cpp index 50158f083..323839bcc 100644 --- a/sfall/Modules/Tiles.cpp +++ b/sfall/Modules/Tiles.cpp @@ -28,6 +28,29 @@ namespace sfall { +#define _OBJ_TYPE_TILE (4) + +static const DWORD Tiles_0E[] = { + 0x484255, 0x48429D, 0x484377, 0x484385, 0x48A897, 0x48A89A, 0x4B2231, + 0x4B2374, 0x4B2381, 0x4B2480, 0x4B248D, 0x4B2A7C, 0x4B2BDA +}; + +static const DWORD Tiles_3F[] = { + 0x41875D, 0x4839E6, 0x483A2F, 0x484380, 0x48A803, 0x48A9F2, 0x48C96C, + 0x48C99F, 0x48C9D2, 0x4B2247, 0x4B2334, 0x4B2440, 0x4B2AB9, 0x4B2B8F, + 0x4B2BF4, 0x1000E1DA +}; + +static const DWORD Tiles_40[] = { + 0x48C941, 0x48C955, 0x48CA5F, 0x48CA71, 0x48CA9B, 0x48CAAD, 0x48CADB, + 0x48CAEB, 0x48CAF7, 0x48CB20, 0x48CB32, 0x48CB61, 0x1000E1C0 +}; + +static const DWORD Tiles_C0[] = { + 0x48424E, 0x484296, 0x484372, 0x48A88D, 0x48A892, 0x4B222C, 0x4B236F, + 0x4B247B, 0x4B2A77, 0x4B2BD5 +}; + struct OverrideEntry { //DWORD id; DWORD xtiles; @@ -219,12 +242,51 @@ static void __declspec(naked) SquareLoadHook() { } } +static void __declspec(naked) art_id_hack() { + __asm { + cmp esi, (_OBJ_TYPE_TILE << 24); //0x4000000 + jne end; + and eax, 0x3FFF; + retn; +end: + and eax, 0x0FFF; + retn; + } +} + +static void __declspec(naked) art_get_name_hack() { + __asm { + sar eax, 24; + cmp eax, _OBJ_TYPE_TILE; + jne end; + mov esi, edx; + mov ebp, edx; + and esi, 0x3FFF; + and ebp, 0xC000; + sar ebp, 0x0E; +end: + test esi, esi; + retn; + } +} + void Tiles::init() { tileMode = GetConfigInt("Misc", "AllowLargeTiles", 0); if (tileMode) { HookCall(0x481D72, &ArtInitHook); HookCall(0x48434C, SquareLoadHook); } + + if (GetConfigInt("Misc", "MoreTiles", 0)) { + if (*(long*)0x1000E1BF == 0x1000 && *(long*)0x1000E1D9 == 0x0FFF) { // Check HRP 4.1.8 + MakeCall(0x419D46, art_id_hack); + MakeCall(0x419479, art_get_name_hack); + SafeWriteBatch(0x0E, Tiles_0E); + SafeWriteBatch(0x3F, Tiles_3F); + SafeWriteBatch(0x40, Tiles_40); + SafeWriteBatch(0xC0, Tiles_C0); + } + } } } From 5e0e8dd2f17f94c9459d3fbc6fa46e597038637a Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 28 May 2018 09:27:53 +0800 Subject: [PATCH 10/29] Added MoreTiles option to ddraw.ini. Changed MoreTiles to work independently of HRP 4.1.8 and removed the redundant define. Added sfall log messages to both options in Tiles.cpp. Implemented HookCalls in TimeLimitPatch(). Fixed a minor typo in function notes.txt. --- artifacts/ddraw.ini | 9 ++++-- artifacts/scripting/sfall function notes.txt | 2 +- sfall/Modules/Karma.cpp | 2 +- sfall/Modules/Tiles.cpp | 33 +++++++++++--------- sfall/Modules/Worldmap.cpp | 16 +++++----- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 20cb28f71..d5d40f1b4 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -164,7 +164,7 @@ WorldMapEncounterRate=5 ;The number of slots available in the locations list panel of the world map ;Set to 0 to leave unchanged. 17 is default. -;Setting this greater than 17 requires a replacement background frm, or you'll get glitched graphics +;Setting this greater than 17 requires a replacement background FRM, or you'll get glitched graphics WorldMapSlots=0 ;To start a new game somewhere other than artemple.map, uncomment the next line and set it to the map you want to load @@ -344,7 +344,10 @@ NPCsTryToSpendExtraAP=0 ;Set to 2 if you provide a XLtiles.lst file in art/tiles/ containing a list of the tile ids that need checking AllowLargeTiles=0 -;Change the Skilldex cursor frm numbers +;Set to 1 to boost the maximum number of tile FRMs from 4096 to 16383 +MoreTiles=0 + +;Change the Skilldex cursor FRM numbers ;Default is 293 for all skills Lockpick=293 Steal=293 @@ -379,7 +382,7 @@ ExtraSaveSlots=0 ;Set to 2 to update the HP/AC counters instantly SpeedInterfaceCounterAnims=0 -;These lines allow you to control the karma frm's displayed on the character screen +;These lines allow you to control the karma FRMs displayed on the character screen ;Number of KarmaPoints should be 1 less than number of KarmaFRMs ;KarmaFRMs=47,48,49 ;KarmaPoints=-100,100 diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 7c7820226..7c4efebb8 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -50,7 +50,7 @@ has_fake_trait and has_fake_perk return the number of levels the player has of t perk_add_mode, set_selectable_perk, set_perkbox_title, hide_real_perks, show_real_perks and clear_selectable_perks control the behaviour of the select a perk box. set_selectable_perk can be used to add additional items by setting the 'active' parameter to 1, and to remove them again by setting it to 0. set_perkbox_title can be used to change the title of the box, or by using "" it will be set back to the default. hide and show_real_perks can be used to prevent the dialog from displaying any of the original 119 perks. perk_add_mode modifies what happens when a fake perk is selected from the perks dialog. It is treated as a set of flags - if bit 1 is set then it is added to the players traits, if bit 2 is set it is added to the players perks, and if bit 3 is set it is removed from the list of selectable perks. The default is 0x2. clear_selectable_perks restores the dialog to it's default state. -show_iface_tag, hide_iface_tag and is_iface_tag_active relate to the boxes that appear above the interface such as SNEAK and LEVEL. You can use 3 for LEVEL and 4 for ADDICT, or the range from 5 to 9 for custom boxes. Remember to add your messages to intrface.msg and setup the font colours in ddraw.ini if you're going to use custom boxes. +show_iface_tag, hide_iface_tag and is_iface_tag_active relate to the boxes that appear above the interface such as SNEAK and LEVEL. You can use 3 for LEVEL and 4 for ADDICT, or the range from 5 to 9 for custom boxes. Remember to add your messages to intrface.msg and set up the font colours in ddraw.ini if you're going to use custom boxes. get/set_bodypart_hit_modifier alter the hit percentage modifiers for aiming at specific bodyparts. Valid bodypart id's are from 0 to 8. Changes are not saved, and will reset to the defaults (or to the values specified in ddraw.ini if they exist) at each reload. diff --git a/sfall/Modules/Karma.cpp b/sfall/Modules/Karma.cpp index 18d55d0da..f302eb4cc 100644 --- a/sfall/Modules/Karma.cpp +++ b/sfall/Modules/Karma.cpp @@ -89,7 +89,7 @@ void ApplyDisplayKarmaChangesPatch() { void ApplyKarmaFRMsPatch() { auto karmaFrmList = GetConfigList("Misc", "KarmaFRMs", "", 512); if (karmaFrmList.size() > 0) { - dlog("Applying karma frm patch.", DL_INIT); + dlog("Applying karma FRM patch.", DL_INIT); auto karmaPointsList = GetConfigList("Misc", "KarmaPoints", "", 512); karmaFrms.resize(karmaFrmList.size()); diff --git a/sfall/Modules/Tiles.cpp b/sfall/Modules/Tiles.cpp index 323839bcc..24f740f87 100644 --- a/sfall/Modules/Tiles.cpp +++ b/sfall/Modules/Tiles.cpp @@ -27,28 +27,27 @@ namespace sfall { - -#define _OBJ_TYPE_TILE (4) +using namespace fo; static const DWORD Tiles_0E[] = { 0x484255, 0x48429D, 0x484377, 0x484385, 0x48A897, 0x48A89A, 0x4B2231, - 0x4B2374, 0x4B2381, 0x4B2480, 0x4B248D, 0x4B2A7C, 0x4B2BDA + 0x4B2374, 0x4B2381, 0x4B2480, 0x4B248D, 0x4B2A7C, 0x4B2BDA, }; static const DWORD Tiles_3F[] = { 0x41875D, 0x4839E6, 0x483A2F, 0x484380, 0x48A803, 0x48A9F2, 0x48C96C, 0x48C99F, 0x48C9D2, 0x4B2247, 0x4B2334, 0x4B2440, 0x4B2AB9, 0x4B2B8F, - 0x4B2BF4, 0x1000E1DA + 0x4B2BF4, }; static const DWORD Tiles_40[] = { 0x48C941, 0x48C955, 0x48CA5F, 0x48CA71, 0x48CA9B, 0x48CAAD, 0x48CADB, - 0x48CAEB, 0x48CAF7, 0x48CB20, 0x48CB32, 0x48CB61, 0x1000E1C0 + 0x48CAEB, 0x48CAF7, 0x48CB20, 0x48CB32, 0x48CB61, }; static const DWORD Tiles_C0[] = { 0x48424E, 0x484296, 0x484372, 0x48A88D, 0x48A892, 0x4B222C, 0x4B236F, - 0x4B247B, 0x4B2A77, 0x4B2BD5 + 0x4B247B, 0x4B2A77, 0x4B2BD5, }; struct OverrideEntry { @@ -244,7 +243,7 @@ static void __declspec(naked) SquareLoadHook() { static void __declspec(naked) art_id_hack() { __asm { - cmp esi, (_OBJ_TYPE_TILE << 24); //0x4000000 + cmp esi, (OBJ_TYPE_TILE << 24); // 0x4000000 jne end; and eax, 0x3FFF; retn; @@ -257,7 +256,7 @@ static void __declspec(naked) art_id_hack() { static void __declspec(naked) art_get_name_hack() { __asm { sar eax, 24; - cmp eax, _OBJ_TYPE_TILE; + cmp eax, OBJ_TYPE_TILE; jne end; mov esi, edx; mov ebp, edx; @@ -273,19 +272,25 @@ static void __declspec(naked) art_get_name_hack() { void Tiles::init() { tileMode = GetConfigInt("Misc", "AllowLargeTiles", 0); if (tileMode) { + dlog("Applying allow large tiles patch.", DL_INIT); HookCall(0x481D72, &ArtInitHook); HookCall(0x48434C, SquareLoadHook); + dlogr(" Done", DL_INIT); } if (GetConfigInt("Misc", "MoreTiles", 0)) { + dlog("Applying tile FRM limit patch.", DL_INIT); + MakeCall(0x419D46, art_id_hack); + MakeCall(0x419479, art_get_name_hack); + SafeWriteBatch(0x0E, Tiles_0E); + SafeWriteBatch(0x3F, Tiles_3F); + SafeWriteBatch(0x40, Tiles_40); + SafeWriteBatch(0xC0, Tiles_C0); if (*(long*)0x1000E1BF == 0x1000 && *(long*)0x1000E1D9 == 0x0FFF) { // Check HRP 4.1.8 - MakeCall(0x419D46, art_id_hack); - MakeCall(0x419479, art_get_name_hack); - SafeWriteBatch(0x0E, Tiles_0E); - SafeWriteBatch(0x3F, Tiles_3F); - SafeWriteBatch(0x40, Tiles_40); - SafeWriteBatch(0xC0, Tiles_C0); + SafeWrite8(0x1000E1C0, 0x40); + SafeWrite8(0x1000E1DA, 0x3F); } + dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/Worldmap.cpp b/sfall/Modules/Worldmap.cpp index ed91f07b0..14e09f454 100644 --- a/sfall/Modules/Worldmap.cpp +++ b/sfall/Modules/Worldmap.cpp @@ -293,13 +293,15 @@ void TimeLimitPatch() { limit = -1; addUnarmedStatToGetYear = 1; - HookCall(0x4392F8, &GetDateWrapper); - HookCall(0x443808, &GetDateWrapper); - HookCall(0x47E127, &GetDateWrapper); - HookCall(0x4975A2, &GetDateWrapper); - HookCall(0x497712, &GetDateWrapper); - HookCall(0x4979C9, &GetDateWrapper); - HookCall(0x4C3CB5, &GetDateWrapper); + HookCalls(GetDateWrapper, { + 0x4392F8, + 0x443808, + 0x47E127, + 0x4975A2, + 0x497712, + 0x4979C9, + 0x4C3CB5 + }); dlogr(" Done", DL_INIT); } From 4ef20c3526a681a509c49f5d16d988bb8236af92 Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Mon, 28 May 2018 18:32:14 +0300 Subject: [PATCH 11/29] Added new hook for function get_game_mode, when the game mode changes. (#86) (#153) --- artifacts/scripting/headers/sfall.h | 1 + sfall/Modules/HookScripts.cpp | 10 ++ sfall/Modules/HookScripts.h | 1 + sfall/Modules/LoadGameHook.cpp | 136 ++++++++++++++++++---------- sfall/Modules/LoadGameHook.h | 3 + 5 files changed, 102 insertions(+), 49 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 0c077e028..038cd354b 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -51,6 +51,7 @@ #define HOOK_CARTRAVEL (28) #define HOOK_SETGLOBALVAR (29) #define HOOK_RESTTIMER (30) +#define HOOK_GAMEMODECHANGE (31) //Valid arguments to list_begin #define LIST_CRITTERS (0) diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index 039b7739b..6217a0d96 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -64,6 +64,14 @@ void _stdcall MouseClickHook(DWORD button, bool pressed) { EndHook(); } +void _stdcall GameModeChangeHook(DWORD exit) { + BeginHook(); + argCount = 1; + args[0] = exit; + RunHookScript(HOOK_GAMEMODECHANGE); + EndHook(); +} + // END HOOKS DWORD _stdcall GetHSArgCount() { @@ -122,6 +130,7 @@ static void HookScriptInit2() { LoadHookScript("hs_keypress", HOOK_KEYPRESS); LoadHookScript("hs_mouseclick", HOOK_MOUSECLICK); + LoadHookScript("hs_gamemodechange", HOOK_GAMEMODECHANGE); dlogr("Finished loading hook scripts", DL_HOOK|DL_INIT); } @@ -157,6 +166,7 @@ void _stdcall RunHookScriptsAtProc(DWORD procId) { void HookScripts::init() { OnKeyPressed() += KeyPressHook; OnMouseClick() += MouseClickHook; + LoadGameHook::OnGameModeChange() += GameModeChangeHook; } } diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index f3a99ca0a..c800abca8 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -57,6 +57,7 @@ enum HookType HOOK_CARTRAVEL = 28, HOOK_SETGLOBALVAR = 29, HOOK_RESTTIMER = 30, + HOOK_GAMEMODECHANGE = 31, HOOK_COUNT }; diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index 7880ab748..5323e514c 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -37,11 +37,15 @@ namespace sfall { +#define _InLoop(type, flag) _asm pushad _asm push flag _asm push type _asm call SetInLoop _asm popad +#define _InLoop2(type, flag) _asm push flag _asm push type _asm call SetInLoop + static Delegate<> onGameInit; static Delegate<> onGameReset; static Delegate<> onBeforeGameStart; static Delegate<> onAfterGameStarted; static Delegate<> onAfterNewGame; +static Delegate onGameModeChange; static DWORD inLoop = 0; static DWORD saveInCombatFix; @@ -54,11 +58,11 @@ bool IsMapLoaded() { } DWORD InWorldMap() { - return (inLoop&WORLDMAP) ? 1 : 0; + return (inLoop & WORLDMAP) ? 1 : 0; } DWORD InCombat() { - return (inLoop&COMBAT) ? 1 : 0; + return (inLoop & COMBAT) ? 1 : 0; } DWORD GetLoopFlags() { @@ -73,6 +77,19 @@ void ClearLoopFlag(LoopFlag flag) { inLoop &= ~flag; } +static void __stdcall GameModeChange(DWORD state) { + onGameModeChange.invoke(state); +} + +void _stdcall SetInLoop(DWORD mode, LoopFlag flag) { + if (mode) { + SetLoopFlag(flag); + } else { + ClearLoopFlag(flag); + } + GameModeChange(0); +} + void GetSavePath(char* buf, char* ftype) { sprintf(buf, "%s\\savegame\\slot%.2d\\sfall%s.sav", fo::var::patches, fo::var::slot_cursor + 1 + LSPageOffset, ftype); //add SuperSave Page offset } @@ -133,15 +150,16 @@ static void __declspec(naked) SaveGame_hook() { push eax; // save Mode parameter call CombatSaveTest; test eax, eax; - pop edx; // recall Mode parameter + pop edx; // recall Mode parameter (pop eax) jz end; mov eax, edx; - or inLoop, SAVEGAME; + _InLoop(1, SAVEGAME); call fo::funcoffs::SaveGame_; - and inLoop, (-1 ^ SAVEGAME); + _InLoop(0, SAVEGAME); cmp eax, 1; jne end; + // save sfall.sav call SaveGame2; mov eax, 1; end: @@ -185,6 +203,11 @@ static void _stdcall GameReset(DWORD isGameLoad) { if (isGameLoad) { LoadGame_Before(); } + + if (isDebug) { + char* str = (isGameLoad) ? "on Load" : "on Exit"; + fo::func::debug_printf("n\[SFALL: State reset %s]", str); + } } // Called after game was loaded from a save @@ -195,20 +218,21 @@ static void _stdcall LoadGame_After() { static void __declspec(naked) LoadGame_hook() { __asm { - push ebx; - push ecx; - push edx; - or inLoop, LOADGAME; + _InLoop(1, LOADGAME); call fo::funcoffs::LoadGame_; - and inLoop, (-1 ^ LOADGAME); + _InLoop(0, LOADGAME); cmp eax, 1; jne end; + // Invoked + push ebx; + push ecx; + push edx; call LoadGame_After; mov eax, 1; -end: pop edx; pop ecx; pop ebx; +end: retn; } } @@ -282,21 +306,31 @@ static void __declspec(naked) game_reset_on_load_hook() { } } +static void __declspec(naked) before_game_exit_hook() { + __asm { + pushad; + push 1; + call GameModeChange; + popad; + jmp fo::funcoffs::map_exit_; + } +} + static void __declspec(naked) WorldMapHook() { __asm { - or inLoop, WORLDMAP; + _InLoop(1, WORLDMAP); xor eax, eax; call fo::funcoffs::wmWorldMapFunc_; - and inLoop, (-1 ^ WORLDMAP); + _InLoop(0, WORLDMAP); retn; } } static void __declspec(naked) WorldMapHook2() { __asm { - or inLoop, WORLDMAP; + _InLoop(1, WORLDMAP); call fo::funcoffs::wmWorldMapFunc_; - and inLoop, (-1 ^ WORLDMAP); + _InLoop(0, WORLDMAP); retn; } } @@ -305,31 +339,31 @@ static void __declspec(naked) CombatHook() { __asm { pushad; call AICombatStart; - popad - or inLoop, COMBAT; + _InLoop2(1, COMBAT); + popad; call fo::funcoffs::combat_; pushad; call AICombatEnd; - popad - and inLoop, (-1 ^ COMBAT); + _InLoop2(0, COMBAT); + popad; retn; } } static void __declspec(naked) PlayerCombatHook() { __asm { - or inLoop, PCOMBAT; + _InLoop(1, PCOMBAT); call fo::funcoffs::combat_input_; - and inLoop, (-1 ^ PCOMBAT); + _InLoop(0, PCOMBAT); retn; } } static void __declspec(naked) EscMenuHook() { __asm { - or inLoop, ESCMENU; + _InLoop(1, ESCMENU); call fo::funcoffs::do_optionsFunc_; - and inLoop, (-1 ^ ESCMENU); + _InLoop(0, ESCMENU); retn; } } @@ -337,35 +371,35 @@ static void __declspec(naked) EscMenuHook() { static void __declspec(naked) EscMenuHook2() { //Bloody stupid watcom compiler optimizations... __asm { - or inLoop, ESCMENU; + _InLoop(1, ESCMENU); call fo::funcoffs::do_options_; - and inLoop, (-1 ^ ESCMENU); + _InLoop(0, ESCMENU); retn; } } static void __declspec(naked) OptionsMenuHook() { __asm { - or inLoop, OPTIONS; + _InLoop(1, OPTIONS); call fo::funcoffs::do_prefscreen_; - and inLoop, (-1 ^ OPTIONS); + _InLoop(0, OPTIONS); retn; } } static void __declspec(naked) HelpMenuHook() { __asm { - or inLoop, HELP; + _InLoop(1, HELP); call fo::funcoffs::game_help_; - and inLoop, (-1 ^ HELP); + _InLoop(0, HELP); retn; } } static void __declspec(naked) CharacterHook() { __asm { - or inLoop, CHARSCREEN; pushad; + _InLoop2(1, CHARSCREEN); call PerksEnterCharScreen; popad; call fo::funcoffs::editor_design_; @@ -377,81 +411,81 @@ static void __declspec(naked) CharacterHook() { success: call PerksAcceptCharScreen; end: + _InLoop2(0, CHARSCREEN); popad; - and inLoop, (-1 ^ CHARSCREEN); retn; } } static void __declspec(naked) DialogHook() { __asm { - or inLoop, DIALOG; + _InLoop(1, DIALOG); call fo::funcoffs::gdProcess_; - and inLoop, (-1 ^ DIALOG); + _InLoop(0, DIALOG); retn; } } static void __declspec(naked) PipboyHook() { __asm { - or inLoop, PIPBOY; + _InLoop(1, PIPBOY); call fo::funcoffs::pipboy_; - and inLoop, (-1 ^ PIPBOY); + _InLoop(0, PIPBOY); retn; } } static void __declspec(naked) SkilldexHook() { __asm { - or inLoop, SKILLDEX; + _InLoop(1, SKILLDEX); call fo::funcoffs::skilldex_select_; - and inLoop, (-1 ^ SKILLDEX); + _InLoop(0, SKILLDEX); retn; } } static void __declspec(naked) HandleInventoryHook() { __asm { - or inLoop, INVENTORY; + _InLoop(1, INVENTORY); call fo::funcoffs::handle_inventory_; - and inLoop, (-1 ^ INVENTORY); + _InLoop(0, INVENTORY); retn; } } static void __declspec(naked) UseInventoryOnHook() { __asm { - or inLoop, INTFACEUSE; + _InLoop(1, INTFACEUSE); call fo::funcoffs::use_inventory_on_; - and inLoop, (-1 ^ INTFACEUSE); + _InLoop(0, INTFACEUSE); retn; } } static void __declspec(naked) LootContainerHook() { __asm { - or inLoop, INTFACELOOT; + _InLoop(1, INTFACELOOT); call fo::funcoffs::loot_container_; - and inLoop, (-1 ^ INTFACELOOT); + _InLoop(0, INTFACELOOT); retn; } } static void __declspec(naked) BarterInventoryHook() { __asm { - or inLoop, BARTER; + _InLoop(1, BARTER); push [ESP + 4]; call fo::funcoffs::barter_inventory_; - and inLoop, (-1 ^ BARTER); + _InLoop(0, BARTER); retn 4; } } static void __declspec(naked) AutomapHook() { __asm { - or inLoop, AUTOMAP; + _InLoop(1, AUTOMAP); call fo::funcoffs::automap_; - and inLoop, (-1 ^ AUTOMAP); + _InLoop(0, AUTOMAP); retn; } } @@ -471,10 +505,10 @@ void LoadGameHook::init() { HookCalls(game_reset_hook, { 0x47DD6B, // LoadSlot_ (on error) 0x47DDF3, // LoadSlot_ (on error) - 0x480708, // RestoreLoad_ (never called) + //0x480708, // RestoreLoad_ (never called) 0x480AD3, // gnw_main_ (game ended after playing via New Game) 0x480BCC, // gnw_main_ (game ended after playing via Load Game) - 0x480D0C, // main_reset_system_ (never called) + //0x480D0C, // main_reset_system_ (never called) 0x481028, // main_selfrun_record_ 0x481062, // main_selfrun_record_ 0x48110B, // main_selfrun_play_ @@ -483,6 +517,7 @@ void LoadGameHook::init() { HookCalls(game_reset_on_load_hook, { 0x47F491, // PrepLoad_ (the very first step during save game loading) }); + HookCalls(before_game_exit_hook, {0x480ACE, 0x480BC7}); HookCalls(WorldMapHook, {0x483668, 0x4A4073}); HookCalls(WorldMapHook2, {0x4C4855}); @@ -526,4 +561,7 @@ Delegate<>& LoadGameHook::OnAfterNewGame() { return onAfterNewGame; } +Delegate& LoadGameHook::OnGameModeChange() { + return onGameModeChange; +} } diff --git a/sfall/Modules/LoadGameHook.h b/sfall/Modules/LoadGameHook.h index 804e7daf4..0ad5d8275 100644 --- a/sfall/Modules/LoadGameHook.h +++ b/sfall/Modules/LoadGameHook.h @@ -43,6 +43,9 @@ class LoadGameHook : public Module { // Invoked after new game has started static Delegate<>& OnAfterNewGame(); + + // Invoked when the game mode is changed. + static Delegate& OnGameModeChange(); }; // True if some map was loaded, false when on the main menu From 2d8ea2b44cb9a638eba4c18787eecad21dd01c38 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 28 May 2018 23:37:45 +0800 Subject: [PATCH 12/29] Added description of HOOK_GAMEMODECHANGE to hookscripts.txt. Fixed the line break for debug.log message of GameReset. Minor edits to Tiles.cpp code format. --- artifacts/scripting/hookscripts.txt | 8 ++++++++ sfall/Modules/LoadGameHook.cpp | 15 ++++++++++++--- sfall/Modules/Tiles.cpp | 4 ++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index 3f8a53304..8cdc7ff0d 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -498,3 +498,11 @@ int arg3 - the hour part of the length of resting time int arg4 - the minute part of the length of resting time int ret1 - pass 1 to interrupt the resting + +------------------------------------------- + +HOOK_GAMEMODECHANGE (hs_gamemodechange.int) + +Runs once every time when the game mode was changed, like opening/closing the inventory, character screen, pipboy, etc. + +int arg1 - event type: 1 - when the player exits the game, 0 - otherwise diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index 5323e514c..b4ccbee96 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -37,8 +37,16 @@ namespace sfall { -#define _InLoop(type, flag) _asm pushad _asm push flag _asm push type _asm call SetInLoop _asm popad -#define _InLoop2(type, flag) _asm push flag _asm push type _asm call SetInLoop +#define _InLoop(type, flag) __asm { \ + _asm pushad \ + _asm push flag \ + _asm push type \ + _asm call SetInLoop \ + _asm popad } +#define _InLoop2(type, flag) __asm { \ + _asm push flag \ + _asm push type \ + _asm call SetInLoop } static Delegate<> onGameInit; static Delegate<> onGameReset; @@ -206,7 +214,7 @@ static void _stdcall GameReset(DWORD isGameLoad) { if (isDebug) { char* str = (isGameLoad) ? "on Load" : "on Exit"; - fo::func::debug_printf("n\[SFALL: State reset %s]", str); + fo::func::debug_printf("\n[SFALL: State reset %s]\n", str); } } @@ -564,4 +572,5 @@ Delegate<>& LoadGameHook::OnAfterNewGame() { Delegate& LoadGameHook::OnGameModeChange() { return onGameModeChange; } + } diff --git a/sfall/Modules/Tiles.cpp b/sfall/Modules/Tiles.cpp index 24f740f87..484d3da01 100644 --- a/sfall/Modules/Tiles.cpp +++ b/sfall/Modules/Tiles.cpp @@ -125,7 +125,7 @@ static int ProcessTile(fo::Art* tiles, int tile, int listpos) { for (int y2 = 0; y2 < 36; y2++) { for (int x2 = 0; x2 < 80; x2++) { if (mask[y2 * 80 + x2]) { - frame.pixels[y2 * 80 + x2] = pixeldata[(yoffset + y2)*width + xoffset + x2]; + frame.pixels[y2 * 80 + x2] = pixeldata[(yoffset + y2) * width + xoffset + x2]; } else { frame.pixels[y2 * 80 + x2] = 0; } @@ -211,7 +211,7 @@ static void _stdcall SquareLoadCheck(tilestruct* data) { for (DWORD x = 0; x < 100; x++) { for (DWORD z = 0; z < 2; z++) { DWORD tile = data[y * 100 + x].tile[z]; - if (tile > 1 && tile < origTileCount&&overrides[tile]) { + if (tile > 1 && tile < origTileCount && overrides[tile]) { DWORD newtile = overrides[tile]->replacementid - 1; for (DWORD y2 = 0; y2 < overrides[tile]->ytiles; y2++) { for (DWORD x2 = 0; x2 < overrides[tile]->xtiles; x2++) { From 62d4577152f4e5853c2aba4066e43cac00e78777 Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Tue, 29 May 2018 04:29:11 +0300 Subject: [PATCH 13/29] Adding to the function get_mouse_buttons the return of pressing the middle mouse button (#114). (#157) Change the type of argument checking for the len_array function to remove an unwanted error message (# 128). --- sfall/InputFuncs.cpp | 2 +- sfall/InputFuncs.h | 1 + .../Modules/Scripting/Handlers/Interface.cpp | 19 ++++++------------- sfall/Modules/Scripting/Handlers/Interface.h | 4 ++-- sfall/Modules/Scripting/Opcodes.cpp | 4 ++-- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/sfall/InputFuncs.cpp b/sfall/InputFuncs.cpp index d0c107978..a6201a173 100644 --- a/sfall/InputFuncs.cpp +++ b/sfall/InputFuncs.cpp @@ -36,7 +36,7 @@ static DWORD wheelMod; static bool reverseMouse; -static bool middleMouseDown; +bool middleMouseDown; static DWORD middleMouseKey; static bool backgroundKeyboard; diff --git a/sfall/InputFuncs.h b/sfall/InputFuncs.h index 1c27e33e9..b087765f0 100644 --- a/sfall/InputFuncs.h +++ b/sfall/InputFuncs.h @@ -26,6 +26,7 @@ namespace sfall { extern bool useScrollWheel; +extern bool middleMouseDown; void SetMDown(bool down, bool right); void SetMPos(int x, int y); diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index fade89228..3d503959a 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -114,20 +114,13 @@ void __declspec(naked) op_get_mouse_y() { } } -void __declspec(naked) op_get_mouse_buttons() { - __asm { - push ecx; - push edx; - mov ecx, eax; - mov edx, ds:[FO_VAR_last_buttons]; - call fo::funcoffs::interpretPushLong_; - mov eax, ecx; - mov edx, VAR_TYPE_INT; - call fo::funcoffs::interpretPushShort_ - pop edx; - pop ecx; - retn; +#define MOUSE_MIDDLE_BTN (4) +void sf_get_mouse_buttons(OpcodeContext& ctx) { + DWORD button = fo::var::last_buttons; + if (button == 0 && middleMouseDown) { + button = MOUSE_MIDDLE_BTN; } + ctx.setReturn(button); } void __declspec(naked) op_get_window_under_mouse() { diff --git a/sfall/Modules/Scripting/Handlers/Interface.h b/sfall/Modules/Scripting/Handlers/Interface.h index 1b7b65775..01afe81c2 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.h +++ b/sfall/Modules/Scripting/Handlers/Interface.h @@ -38,8 +38,8 @@ void __declspec() op_get_mouse_x(); //Return mouse y position void __declspec() op_get_mouse_y(); -//Return pressed mouse button (1=left, 2=right, 3=left+right) -void __declspec() op_get_mouse_buttons(); +//Return pressed mouse button (1=left, 2=right, 3=left+right, 4=middle) +void sf_get_mouse_buttons(OpcodeContext&); //Return the window number under the mous void __declspec() op_get_window_under_mouse(); diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index 4ccf7527b..33ff65cdf 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -83,12 +83,13 @@ static SfallOpcodeInfo opcodeInfoArray[] = { {0x218, "set_weapon_ammo_pid", sf_set_weapon_ammo_pid, 2, false, {ARG_OBJECT, ARG_INT}}, {0x219, "get_weapon_ammo_count", sf_get_weapon_ammo_count, 1, true, {ARG_OBJECT}}, {0x21a, "set_weapon_ammo_count", sf_set_weapon_ammo_count, 2, false, {ARG_OBJECT, ARG_INT}}, + {0x21e, "get_mouse_buttons", sf_get_mouse_buttons, 0, true}, {0x22d, "create_array", sf_create_array, 2, true, {ARG_INT, ARG_INT}}, {0x22e, "set_array", sf_set_array, 3, false, {ARG_OBJECT, ARG_ANY, ARG_ANY}}, {0x22f, "get_array", sf_get_array, 2, true, {ARG_ANY, ARG_ANY}}, // can also be used on strings {0x230, "free_array", sf_free_array, 1, false, {ARG_OBJECT}}, - {0x231, "len_array", sf_len_array, 1, true, {ARG_OBJECT}}, + {0x231, "len_array", sf_len_array, 1, true, {ARG_INT}}, {0x232, "resize_array", sf_resize_array, 2, false, {ARG_OBJECT, ARG_INT}}, {0x233, "temp_array", sf_temp_array, 2, true, {ARG_INT, ARG_INT}}, {0x234, "fix_array", sf_fix_array, 1, false, {ARG_INT}}, @@ -375,7 +376,6 @@ void InitNewOpcodes() { } opcodes[0x21c] = op_get_mouse_x; opcodes[0x21d] = op_get_mouse_y; - opcodes[0x21e] = op_get_mouse_buttons; opcodes[0x21f] = op_get_window_under_mouse; opcodes[0x220] = op_get_screen_width; opcodes[0x221] = op_get_screen_height; From 120a8cd964683c844f5f35ae9ab168eb348b9bd1 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 29 May 2018 16:22:58 +0800 Subject: [PATCH 14/29] Added WorldMapFont option to use Fallout font on the world map instead of system font. (#48) --- artifacts/ddraw.ini | 3 +++ sfall/Modules/Worldmap.cpp | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index d5d40f1b4..52ce29759 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -554,6 +554,9 @@ InstantWeaponEquip=0 ;Set to 1 to display numbered dialogue options NumbersInDialogue=0 +;Set to 1 to use Fallout font on the world map instead of system font +WorldMapFont=0 + ;Set to 1 to display sfall built-in credits at the bottom of credits.txt contents instead of at the top CreditsAtBottom=0 diff --git a/sfall/Modules/Worldmap.cpp b/sfall/Modules/Worldmap.cpp index 14e09f454..b93781f44 100644 --- a/sfall/Modules/Worldmap.cpp +++ b/sfall/Modules/Worldmap.cpp @@ -225,6 +225,14 @@ static __declspec(naked) void PathfinderFix() { } } +static void __declspec(naked) wmInterfaceInit_text_font_hook() { + __asm { + mov eax, 0x65; // normal text font + call fo::funcoffs::text_font_; + retn; + } +} + static void RestRestore() { if (!restMode) return; @@ -421,6 +429,14 @@ void StartingStatePatches() { } } +void WorldMapFontPatch() { + if (GetConfigInt("Misc", "WorldMapFont", 0)) { + dlog("Applying world map font patch.", DL_INIT); + HookCall(0x4C2343, wmInterfaceInit_text_font_hook); + dlogr(" Done", DL_INIT); + } +} + void Worldmap::init() { PathfinderFixInit(); StartingStatePatches(); @@ -428,6 +444,7 @@ void Worldmap::init() { TownMapsHotkeyFix(); WorldLimitsPatches(); WorldmapFpsPatch(); + WorldMapFontPatch(); LoadGameHook::OnGameReset() += []() { SetCarInterfaceArt(0x1B1); From b24a860d402d761846f61d63a05414b7b12cfb96 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 30 May 2018 09:27:58 +0800 Subject: [PATCH 15/29] Renamed WorldMapFont to WorldMapFontPatch and changed its description in ddraw.ini. --- artifacts/ddraw.ini | 4 ++-- sfall/Modules/Worldmap.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 52ce29759..ed33b6544 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -554,8 +554,8 @@ InstantWeaponEquip=0 ;Set to 1 to display numbered dialogue options NumbersInDialogue=0 -;Set to 1 to use Fallout font on the world map instead of system font -WorldMapFont=0 +;Set to 1 to use Fallout's normal text font instead of DOS-like font on the world map +WorldMapFontPatch=0 ;Set to 1 to display sfall built-in credits at the bottom of credits.txt contents instead of at the top CreditsAtBottom=0 diff --git a/sfall/Modules/Worldmap.cpp b/sfall/Modules/Worldmap.cpp index b93781f44..99bc5e68d 100644 --- a/sfall/Modules/Worldmap.cpp +++ b/sfall/Modules/Worldmap.cpp @@ -430,7 +430,7 @@ void StartingStatePatches() { } void WorldMapFontPatch() { - if (GetConfigInt("Misc", "WorldMapFont", 0)) { + if (GetConfigInt("Misc", "WorldMapFontPatch", 0)) { dlog("Applying world map font patch.", DL_INIT); HookCall(0x4C2343, wmInterfaceInit_text_font_hook); dlogr(" Done", DL_INIT); From 0e715236bfd4da9e29dfbb21fdd5d6fe95fa18c3 Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Wed, 30 May 2018 16:02:35 +0300 Subject: [PATCH 16/29] Added an additional mode to the function 'metarule2_explosions', sets a constant radius of the explosion grenades and rockets. (#146) --- artifacts/scripting/headers/sfall.h | 1 + sfall/Modules/Explosions.cpp | 50 ++++++++++++++++------ sfall/Modules/Scripting/Handlers/Anims.cpp | 10 +++-- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 038cd354b..7a50d7dc7 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -139,6 +139,7 @@ #define set_attack_explosion_radius(x) metarule2_explosions(3, x, 0) #define set_attack_is_explosion(x) metarule2_explosions(4, x, 0) #define set_attack_is_explosion_fire set_attack_is_explosion(DMG_fire) +#define set_explosion_radius(grenade, rocket) metarule2_explosions(5, grenade, rocket) #define GAME_MSG_COMBAT (0) diff --git a/sfall/Modules/Explosions.cpp b/sfall/Modules/Explosions.cpp index 55f063c59..1a7386a5e 100644 --- a/sfall/Modules/Explosions.cpp +++ b/sfall/Modules/Explosions.cpp @@ -21,6 +21,7 @@ #include "..\FalloutEngine\Fallout2.h" #include "..\Logging.h" #include "..\SimplePatch.h" +#include "LoadGameHook.h" #include "MainLoopHook.h" #include "ScriptExtender.h" @@ -30,6 +31,7 @@ namespace sfall { static bool lightingEnabled = false; +static bool explosionsMetaruleReset = false; static const DWORD ranged_attack_lighting_fix_back = 0x4118F8; @@ -153,12 +155,15 @@ static void __declspec(naked) fire_dance_lighting_fix1() { } -static const DWORD explosion_dmg_check_adr[] = {0x411709, 0x4119FC, 0x411C08, 0x4517C1, 0x423BC8}; +static const DWORD explosion_dmg_check_adr[] = {0x411709, 0x4119FC, 0x411C08, 0x4517C1, 0x423BC8, 0x42381A}; static const DWORD explosion_art_adr[] = {0x411A19, 0x411A29, 0x411A35, 0x411A3C}; static const DWORD explosion_art_defaults[] = {10, 2, 31, 29}; static const DWORD explosion_radius_grenade = 0x479183; static const DWORD explosion_radius_rocket = 0x47918B; +static DWORD set_expl_radius_grenade = 2; +static DWORD set_expl_radius_rocket = 3; + static const size_t numArtChecks = sizeof(explosion_art_adr) / sizeof(explosion_art_adr[0]); static const size_t numDmgChecks = sizeof(explosion_dmg_check_adr) / sizeof(explosion_dmg_check_adr[0]); @@ -166,9 +171,15 @@ enum MetaruleExplosionsMode { EXPL_FORCE_EXPLOSION_PATTERN = 1, EXPL_FORCE_EXPLOSION_ART = 2, EXPL_FORCE_EXPLOSION_RADIUS = 3, - EXPL_FORCE_EXPLOSION_DMGTYPE = 4 + EXPL_FORCE_EXPLOSION_DMGTYPE = 4, + EXPL_STATIC_EXPLOSION_RADIUS = 5 }; +static void SetExplosionRadius(int arg1, int arg2) { + SafeWrite32(explosion_radius_grenade, arg1); + SafeWrite32(explosion_radius_rocket, arg2); +} + int _stdcall ExplosionsMetaruleFunc(int mode, int arg1, int arg2) { switch (mode) { case EXPL_FORCE_EXPLOSION_PATTERN: @@ -180,27 +191,33 @@ int _stdcall ExplosionsMetaruleFunc(int mode, int arg1, int arg2) { SafeWrite8(0x411B54, 6); // last direction } break; - case EXPL_FORCE_EXPLOSION_ART: { + case EXPL_FORCE_EXPLOSION_ART: for (int i = 0; i < numArtChecks; i++) { SafeWrite32(explosion_art_adr[i], (BYTE)arg1); } break; - } case EXPL_FORCE_EXPLOSION_RADIUS: - SafeWrite32(explosion_radius_grenade, arg1); - SafeWrite32(explosion_radius_rocket, arg1); + SetExplosionRadius(arg1, arg1); break; - case EXPL_FORCE_EXPLOSION_DMGTYPE: { + case EXPL_FORCE_EXPLOSION_DMGTYPE: for (int i = 0; i < numDmgChecks; i++) { SafeWrite8(explosion_dmg_check_adr[i], (BYTE)arg1); } break; - } + case EXPL_STATIC_EXPLOSION_RADIUS: + if (arg1 > 0) set_expl_radius_grenade = arg1; + if (arg2 > 0) set_expl_radius_rocket = arg2; + SetExplosionRadius(set_expl_radius_grenade, set_expl_radius_rocket); + break; + default: + return -1; } + if (mode != EXPL_STATIC_EXPLOSION_RADIUS) explosionsMetaruleReset = true; return 0; } void ResetExplosionSettings() { + if (!explosionsMetaruleReset) return; // explosion pattern explosion_effect_starting_dir = 0; SafeWrite8(0x411B54, 6); // last direction @@ -209,20 +226,25 @@ void ResetExplosionSettings() { SafeWrite32(explosion_art_adr[i], explosion_art_defaults[i]); } // explosion radiuses - SafeWrite32(explosion_radius_grenade, 2); - SafeWrite32(explosion_radius_rocket, 3); + SetExplosionRadius(set_expl_radius_grenade, set_expl_radius_rocket); // explosion dmgtype for (int i = 0; i < numDmgChecks; i++) { - SafeWrite8(explosion_dmg_check_adr[i], 6); + SafeWrite8(explosion_dmg_check_adr[i], fo::DamageType::DMG_explosion); } + explosionsMetaruleReset = false; +} + +void ResetExplosionRadius() { + if (set_expl_radius_grenade != 2 || set_expl_radius_rocket != 3) + SetExplosionRadius(2, 3); } void Explosions::init() { MakeJump(0x411AB4, explosion_effect_hook); // required for explosions_metarule - if (GetConfigInt("Misc", "ExplosionsEmitLight", 0)) { + lightingEnabled = GetConfigInt("Misc", "ExplosionsEmitLight", 0) != 0; + if (lightingEnabled) { dlog("Applying Explosion changes.", DL_INIT); - lightingEnabled = true; MakeJump(0x4118E1, ranged_attack_lighting_fix); MakeJump(0x410A4A, fire_dance_lighting_fix1); MakeJump(0x415A3F, anim_set_check__light_fix); // this allows to change light intensity @@ -238,6 +260,8 @@ void Explosions::init() { // after each combat attack, reset metarule_explosions settings MainLoopHook::OnAfterCombatAttack() += ResetExplosionSettings; + + LoadGameHook::OnGameReset() += ResetExplosionRadius; } } diff --git a/sfall/Modules/Scripting/Handlers/Anims.cpp b/sfall/Modules/Scripting/Handlers/Anims.cpp index 36c936c85..f90931674 100644 --- a/sfall/Modules/Scripting/Handlers/Anims.cpp +++ b/sfall/Modules/Scripting/Handlers/Anims.cpp @@ -108,10 +108,12 @@ void sf_reg_anim_turn_towards(OpcodeContext& ctx) { void sf_explosions_metarule(OpcodeContext& ctx) { int mode = ctx.arg(0).asInt(), - arg1 = ctx.arg(1).asInt(), - arg2 = ctx.arg(2).asInt(); - - ctx.setReturn(ExplosionsMetaruleFunc(mode, arg1, arg2)); + result = ExplosionsMetaruleFunc(mode, ctx.arg(1).asInt(), ctx.arg(2).asInt()); + + if (result == -1) { + ctx.printOpcodeError("ExplosionsMetalure() - mode (%d) is not supported for the function.", mode); + } + ctx.setReturn(result); } } From 2f6f0d8b28d5b946aeec3e03318e6155e2e8ecde Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 30 May 2018 21:07:51 +0800 Subject: [PATCH 17/29] Added the description of new metarule2_explosions mode to function notes.txt. Fixed a typo in metarule2_explosions error message. --- artifacts/scripting/sfall function notes.txt | 4 ++++ sfall/Modules/Explosions.cpp | 2 +- sfall/Modules/Scripting/Handlers/Anims.cpp | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 7c4efebb8..b746acc4d 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -231,6 +231,10 @@ was made as a dirty easy hack to allow dynamically change some explosion paramet > void set_attack_is_explosion_fire - if you call this right before using a weapon with fire damage type, it will produce explosion effects (and radius damage) just like "explosion" type, but all targets will still receive fire damage. +> void set_explosion_radius(grenade, rocket) +- sets a permanent radius of the explosion for grenades and/or rockets. Passing 0 means not changing the corresponding radius. +- changed radius will be reset each time the player reloads the game. + Some utility/math functions are available: diff --git a/sfall/Modules/Explosions.cpp b/sfall/Modules/Explosions.cpp index 1a7386a5e..c9b324786 100644 --- a/sfall/Modules/Explosions.cpp +++ b/sfall/Modules/Explosions.cpp @@ -251,7 +251,7 @@ void Explosions::init() { dlogr(" Done", DL_INIT); } - + DWORD tmp; tmp = SimplePatch(0x4A2873, "Misc", "Dynamite_DmgMax", 50, 0, 9999); SimplePatch(0x4A2878, "Misc", "Dynamite_DmgMin", 30, 0, tmp); diff --git a/sfall/Modules/Scripting/Handlers/Anims.cpp b/sfall/Modules/Scripting/Handlers/Anims.cpp index f90931674..3be3cb917 100644 --- a/sfall/Modules/Scripting/Handlers/Anims.cpp +++ b/sfall/Modules/Scripting/Handlers/Anims.cpp @@ -109,9 +109,9 @@ void sf_reg_anim_turn_towards(OpcodeContext& ctx) { void sf_explosions_metarule(OpcodeContext& ctx) { int mode = ctx.arg(0).asInt(), result = ExplosionsMetaruleFunc(mode, ctx.arg(1).asInt(), ctx.arg(2).asInt()); - + if (result == -1) { - ctx.printOpcodeError("ExplosionsMetalure() - mode (%d) is not supported for the function.", mode); + ctx.printOpcodeError("ExplosionsMetarule() - mode (%d) is not supported for the function.", mode); } ctx.setReturn(result); } From 56945c7437adc796c3c8da780abe6694d86bcadc Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Fri, 1 Jun 2018 18:30:37 +0300 Subject: [PATCH 18/29] Fixed crash game when playing animation when the critter/pc goes through the door. Refactoring code. (#158) --- sfall/FalloutEngine/VariableOffsets.h | 1 + sfall/Modules/AnimationsAtOnceLimit.cpp | 64 ++++++++++++++++++++----- sfall/ddraw.vcxproj | 9 ++-- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index 976fa32e6..b88fb3853 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -156,6 +156,7 @@ #define FO_VAR_RedColor 0x6AB4D0 #define FO_VAR_retvals 0x43EA7C #define FO_VAR_rotation 0x631D34 +#define FO_VAR_sad 0x530014 #define FO_VAR_script_path_base 0x51C710 #define FO_VAR_scr_size 0x6AC9F0 #define FO_VAR_scriptListInfo 0x51C7C8 diff --git a/sfall/Modules/AnimationsAtOnceLimit.cpp b/sfall/Modules/AnimationsAtOnceLimit.cpp index acd0bacb8..a4d858529 100644 --- a/sfall/Modules/AnimationsAtOnceLimit.cpp +++ b/sfall/Modules/AnimationsAtOnceLimit.cpp @@ -18,6 +18,7 @@ #include "..\main.h" #include "..\FalloutEngine\Fallout2.h" +#include "LoadGameHook.h" #include "AnimationsAtOnceLimit.h" @@ -33,7 +34,8 @@ static int animationLimit = 32; static std::vector new_anim_set; static std::vector new_sad; -static DWORD animSetAddr, sadAddr; +static DWORD animSetAddr = FO_VAR_anim_set; +static DWORD sadAddr = FO_VAR_sad; static const DWORD animPCMove[] = { 0x416E11, 0x416F64, 0x417143, 0x41725C, 0x4179CC, @@ -151,24 +153,58 @@ static const DWORD sad_28[] = { 0x4173CE, 0x4174C1, 0x4175F1, 0x417730, }; +static DWORD __fastcall AnimCombatFix(DWORD* scr, BYTE combatFlag) { + DWORD animAddr = animSetAddr; + + if (animationLimit > 32) { + animAddr += animRecordSize; // include a dummy + } + + if (combatFlag & 2) { // combat flag is set + _asm call fo::funcoffs::combat_anim_finished_; + } + + return animAddr; +} + static void __declspec(naked) anim_set_end_hack() { __asm { - mov edi, FO_VAR_anim_set; - cmp dword ptr animationLimit, 32; - jle skip; - mov edi, animSetAddr; - add edi, animRecordSize; // Include a dummy -skip: - test dl, 0x2; // Is the combat flag set? - jz end; // No - call fo::funcoffs::combat_anim_finished_; -end: - mov [edi][esi], ebx; + call AnimCombatFix; + mov [eax][esi], ebx; push 0x415DF2; retn; } } +static DWORD __fastcall CheckSetSad(BYTE openFlag, DWORD valueMul) { + bool result = false; + int offset = (sadSize * valueMul) + 32; + + if (*(DWORD*)(sadAddr + offset) == -1000) { + result = true; + } else if (!InCombat() && !(openFlag & 1)) { + *(DWORD*)(sadAddr + offset) = -1000; + result = true; + } + + return result; +} + +static void __declspec(naked) obj_move_hack() { + __asm { + mov ecx, ds:[ecx + 0x3C]; // openFlag + mov edx, [esp + 0x4C - 0x20]; // valueMul + call CheckSetSad; + test eax, eax; + jz end; + push 0x417611; // fixed jump + retn; +end: + push 0x417616; // default + retn; + } +} + void ApplyAnimationsAtOncePatches(signed char aniMax) { if (aniMax <= 32) return; @@ -278,7 +314,11 @@ void AnimationsAtOnce::init() { ApplyAnimationsAtOncePatches(animationLimit); dlogr(" Done", DL_INIT); } + // Fixed using animation in combat mode for anim() functions MakeJump(0x415DE2, anim_set_end_hack); + + // Fix game crash when playing animation when the critter/pc goes through the door + MakeJump(0x41755E, obj_move_hack); } void AnimationsAtOnce::exit() { diff --git a/sfall/ddraw.vcxproj b/sfall/ddraw.vcxproj index cf705b756..f38000b6d 100644 --- a/sfall/ddraw.vcxproj +++ b/sfall/ddraw.vcxproj @@ -66,13 +66,16 @@ true - C:\Program Files %28x86%29\Microsoft DirectX SDK\Include;$(IncludePath);$(ProjectDir) + $(DXSDK_DIR)Include;$(IncludePath);$(ProjectDir) + $(DXSDK_DIR)lib\x86\;$(LibraryPath) - C:\Program Files %28x86%29\Microsoft DirectX SDK\Include;$(IncludePath);$(ProjectDir) + $(DXSDK_DIR)Include;$(IncludePath);$(ProjectDir) + $(DXSDK_DIR)lib\x86\;$(LibraryPath) - C:\Program Files %28x86%29\Microsoft DirectX SDK\Include;$(IncludePath);$(ProjectDir) + $(DXSDK_DIR)Include;$(IncludePath);$(ProjectDir) + $(DXSDK_DIR)lib\x86\;$(LibraryPath) From 051b1c98aabff814b44eccd08b59fe1ed869bfc4 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Fri, 1 Jun 2018 23:36:56 +0800 Subject: [PATCH 19/29] Edited the added comments in AnimationsAtOnceLimit.cpp. Renamed obj_move_hack to object_move_hack because it hooks on object_move_ engine function. --- sfall/Modules/AnimationsAtOnceLimit.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sfall/Modules/AnimationsAtOnceLimit.cpp b/sfall/Modules/AnimationsAtOnceLimit.cpp index a4d858529..656e64950 100644 --- a/sfall/Modules/AnimationsAtOnceLimit.cpp +++ b/sfall/Modules/AnimationsAtOnceLimit.cpp @@ -22,7 +22,7 @@ #include "AnimationsAtOnceLimit.h" -namespace sfall +namespace sfall { static constexpr int animRecordSize = sizeof(fo::AnimationSet); @@ -181,7 +181,7 @@ static DWORD __fastcall CheckSetSad(BYTE openFlag, DWORD valueMul) { int offset = (sadSize * valueMul) + 32; if (*(DWORD*)(sadAddr + offset) == -1000) { - result = true; + result = true; } else if (!InCombat() && !(openFlag & 1)) { *(DWORD*)(sadAddr + offset) = -1000; result = true; @@ -190,7 +190,7 @@ static DWORD __fastcall CheckSetSad(BYTE openFlag, DWORD valueMul) { return result; } -static void __declspec(naked) obj_move_hack() { +static void __declspec(naked) object_move_hack() { __asm { mov ecx, ds:[ecx + 0x3C]; // openFlag mov edx, [esp + 0x4C - 0x20]; // valueMul @@ -314,11 +314,11 @@ void AnimationsAtOnce::init() { ApplyAnimationsAtOncePatches(animationLimit); dlogr(" Done", DL_INIT); } - // Fixed using animation in combat mode for anim() functions + // Fix for calling anim() functions in combat MakeJump(0x415DE2, anim_set_end_hack); - // Fix game crash when playing animation when the critter/pc goes through the door - MakeJump(0x41755E, obj_move_hack); + // Fix crash when the critter goes through a door with animation trigger + MakeJump(0x41755E, object_move_hack); } void AnimationsAtOnce::exit() { From 165207239195dc24310d4c3cb375f8b4bacc7a5d Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 2 Jun 2018 18:15:53 +0800 Subject: [PATCH 20/29] Fixed a bug that critters killed in combat by scripting still being able to move in their combat turn if the distance parameter in their AI packages is set to stay_close/charge, or NPCsTryToSpendExtraAP is enabled (from Mr.Stalin) --- sfall/Modules/BugFixes.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index c51df11fb..65e1584c5 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -1109,6 +1109,18 @@ static void __declspec(naked) obj_move_to_tile_hack() { } } +static void __declspec(naked) ai_move_steps_closer_hook() { + __asm { + call fo::funcoffs::combat_turn_run_; + movzx dx, word ptr [esi + 0x44]; // combat_data.results + test dx, DAM_DEAD or DAM_KNOCKED_OUT or DAM_LOSE_TURN; + jz end; + mov [esi + 0x40], 0; // pobj.curr_mp (source reset ap) +end: + retn; + } +} + void BugFixes::init() { @@ -1420,6 +1432,10 @@ void BugFixes::init() // Fix for being at incorrect hex after map change when the exit hex in source map is at the same position as // some exit hex in destination map MakeCall(0x48A704, obj_move_to_tile_hack); + + // Fix for critters killed in combat by scripting still being able to move in their combat turn if the distance parameter + // in their AI packages is set to stay_close/charge, or NPCsTryToSpendExtraAP is enabled + HookCall(0x42A1A8, ai_move_steps_closer_hook); // 0x42B24D } } From ab3ddc68b6afaf1b21835a7a967905075be3a039 Mon Sep 17 00:00:00 2001 From: Vlad Date: Sun, 3 Jun 2018 15:35:08 +0700 Subject: [PATCH 21/29] Retarget project to use VS2017 build tools, fix deprecation warnings (#161) --- sfall/Modules/Message.h | 2 +- sfall/Modules/ScriptExtender.cpp | 2 +- sfall/Modules/Scripting/Arrays.h | 4 ++-- sfall/Modules/Scripting/Handlers/Metarule.cpp | 2 +- sfall/Modules/Scripting/Opcodes.cpp | 2 +- sfall/ddraw.vcxproj | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sfall/Modules/Message.h b/sfall/Modules/Message.h index 2ac52a491..bb8a8b974 100644 --- a/sfall/Modules/Message.h +++ b/sfall/Modules/Message.h @@ -28,7 +28,7 @@ namespace sfall { -typedef std::tr1::unordered_map> ExtraGameMessageListsMap; +typedef std::unordered_map> ExtraGameMessageListsMap; extern ExtraGameMessageListsMap gExtraGameMsgLists; class Message : public Module { diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index fdac394ad..ce97dbdf9 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -80,7 +80,7 @@ static SfallProgsMap sfallProgsMap; // a map scriptPtr => self_obj to override self_obj for all script types using set_self std::unordered_map selfOverrideMap; -typedef std::tr1::unordered_map ExportedVarsMap; +typedef std::unordered_map ExportedVarsMap; static ExportedVarsMap globalExportedVars; DWORD isGlobalScriptLoading = 0; DWORD modifiedIni; diff --git a/sfall/Modules/Scripting/Arrays.h b/sfall/Modules/Scripting/Arrays.h index 9cefda2eb..1949db9ba 100644 --- a/sfall/Modules/Scripting/Arrays.h +++ b/sfall/Modules/Scripting/Arrays.h @@ -83,7 +83,7 @@ struct sArrayVarOld #define ARRAYFLAG_ASSOC (1) // is map -typedef std::tr1::unordered_map ArrayKeysMap; +typedef std::unordered_map ArrayKeysMap; /** This class represents sfall array @@ -128,7 +128,7 @@ class sArrayVar }; // arrays map: arrayId => arrayVar -typedef std::tr1::unordered_map ArraysMap; +typedef std::unordered_map ArraysMap; extern ArraysMap arrays; typedef ArraysMap::const_iterator array_citr; typedef ArraysMap::iterator array_itr; diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 94c7a4531..2414268dc 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -57,7 +57,7 @@ struct SfallMetarule { OpcodeArgumentType argValidation[OP_MAX_ARGUMENTS]; }; -typedef std::tr1::unordered_map MetaruleTableType; +typedef std::unordered_map MetaruleTableType; static MetaruleTableType metaruleTable; diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index 33ff65cdf..9d2094025 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -51,7 +51,7 @@ static const short opcodeCount = 0x300; // Other half is filled by sfall here. static void* opcodes[opcodeCount]; -typedef std::tr1::unordered_map OpcodeInfoMapType; +typedef std::unordered_map OpcodeInfoMapType; // Opcode Table. Add additional (sfall) opcodes here. // Format: { diff --git a/sfall/ddraw.vcxproj b/sfall/ddraw.vcxproj index f38000b6d..bc8641c4b 100644 --- a/sfall/ddraw.vcxproj +++ b/sfall/ddraw.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -24,7 +24,7 @@ DynamicLibrary NotSet true - v140 + v141 DynamicLibrary @@ -35,7 +35,7 @@ DynamicLibrary NotSet - v140 + v141 From 410c7ab41746e9d0237afe3af48f4230e49902e1 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 4 Jun 2018 21:21:32 +0800 Subject: [PATCH 22/29] Minor edits to documents. --- artifacts/config_files/Translations.ini | 2 +- artifacts/ddraw.ini | 2 +- sfall/Modules/LoadGameHook.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/artifacts/config_files/Translations.ini b/artifacts/config_files/Translations.ini index 018c25042..5221ebe4e 100644 --- a/artifacts/config_files/Translations.ini +++ b/artifacts/config_files/Translations.ini @@ -1,5 +1,5 @@ [sfall] -SaveInCombat=Cannot save at this time +SaveInCombat=Cannot save at this time. KarmaGain=You gained %d karma. KarmaLoss=You lost %d karma. HighlightFail1=You aren't carrying a motion sensor. diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index ed33b6544..f70ef0e50 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -288,7 +288,7 @@ SaveInCombatFix=1 ;Player's level is capped once the highest specified level is reached ;XPTable=50,100,200 -;Set to 1 to enable additional weapon animations codes from o-t +;Set to 1 to enable additional weapon animation codes from o-t ;The 4 byte value at 0x39 of weapon protos may range from 0 to 15 rather than 0 to 10 ;Since the letters 'n' and 'r' are in use for other animations, an animation code of 11 corrisponds to 's' and 15 to 't' AdditionalWeaponAnims=1 diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index b4ccbee96..039161336 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -501,7 +501,7 @@ static void __declspec(naked) AutomapHook() { void LoadGameHook::init() { saveInCombatFix = GetConfigInt("Misc", "SaveInCombatFix", 1); if (saveInCombatFix > 2) saveInCombatFix = 0; - saveFailMsg = Translate("sfall", "SaveInCombat", "Cannot save at this time"); + saveFailMsg = Translate("sfall", "SaveInCombat", "Cannot save at this time."); saveSfallDataFailMsg = Translate("sfall", "SaveSfallDataFail", "ERROR saving extended savegame information! Check if other programs interfere with savegame files/folders and try again!"); From ea1c00ec9156d72b05cfd67e7101894c18c0927a Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 5 Jun 2018 22:08:39 +0800 Subject: [PATCH 23/29] Added the ability to define allowed weapon animations for NPCs to NPC armor appearance mod (#159) --- artifacts/config_files/npcarmor.ini | 6 ++++ artifacts/mods/gl_npcarmor.int | Bin 2642 -> 3664 bytes artifacts/mods/gl_npcarmor.ssl | 48 +++++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/artifacts/config_files/npcarmor.ini b/artifacts/config_files/npcarmor.ini index 7bb98a82c..dca0babbc 100644 --- a/artifacts/config_files/npcarmor.ini +++ b/artifacts/config_files/npcarmor.ini @@ -19,6 +19,7 @@ Robe=16777218 ; Sulik [1] PID=16777313 +WeaponAnims=1,3,4,6 Default=16777280 Leather=16777325 Power=16777324 @@ -29,6 +30,7 @@ Combat=16777322 ; Vic [2] PID=16777278 +WeaponAnims=1,5,7 Default=16777307 Jacket=16777329 Combat=16777330 @@ -39,6 +41,7 @@ Leather=16777333 ; Cassidy [3] PID=16777305 +WeaponAnims=4,5,7 Default=16777354 Leather=16777260 Power=16777328 @@ -49,6 +52,7 @@ Combat=16777326 ; Myron [4] PID=16777376 +WeaponAnims=1,5 Default=16777304 Leather= Power=16777349 @@ -57,6 +61,7 @@ Combat=16777350 ; Cat Jules [5] PID=16777734 +WeaponAnims=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 Default=16777353 Leather=16777347 Metal=16777348 @@ -66,6 +71,7 @@ Combat=16777226 ; Kitsune [6] PID=16777724 +WeaponAnims=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 Default=16777222 Leather=16777221 Metal=16777223 diff --git a/artifacts/mods/gl_npcarmor.int b/artifacts/mods/gl_npcarmor.int index 3006723a002a25309c3ee979131097d131735213..c6cfde80ae5de2c7fe1cf9e1e027579edb850c12 100644 GIT binary patch literal 3664 zcmb_e&2Jk;6rWwMzY^QE+zPcNhX8FvOX^TlNZJFUQi+HJs1i{*AY^UgO|z|IN4Ap^ zDAMzaKL8=rGeU?{)D!2HLk{KAV^3U=$_4ezfkWwU-n{YdCPqpmR@$AN_x*nF%?G)^ zI!dV;mG$WUKps`;G)?1u1@EhPU!ya0mS!N8$D6~Oc-%diyqh56m+2Y&ET`$-dCWEa zR+^rDB6CX9^WVw*`!v0I+`J)oCb!J5C-9xR5fK4yMzquaY4wm$MV zl`3>LSNTVsSX~cRZ#S9STwV7&Hv{Mj^-kb#b~_{TiLkRBbnb*fyVZnbs~z+pTk~7D zw)%s$FhP8YB?sN!&PI1Th=p_gf!`abfAJ{gl#~m7w+@^U%tGd(bb_DLPN*s6*+tJ%BCrD*?c?JXp0b`{gH9+1G*IVTcCHoW07o;|M=*`ocV$q-tUUY*g#n_6> zZJlyr?Hi`UJC8YN&J)*SKfcVjULCqDbB--rG2NAYpvSSADp|dw)N1&YJt?{?Y zDkE1ilD<^vyy2e`-67UlVVWLtfBznB6SAj=Mt7Lw5mnP;{%`bw;aFVlsOS<)rtwAH zHMKC!Jg!L!U%g)*Axfpj^^>+;tf%8QH1?|N@JRd%=7rrvMKu36=4Wh83V$W|aVJ@A z&5bK&`J;*zrw)mdt(kP8LjN5N4U^UX`K>GrTc$6Ij|>J;mF;`?cSB#G41&k@0b=z%K@Tt zvdNB#eWAwoc&+2K}eo7 zd&%4aCS;E)q7&_DVAmCRavIp&EGNz_vF16VeP@(JQIaU)GilOLN;8~KNurocL;+dL zlPJou73P#j2-_3W-bwVWVxDDmqy}N@!y+s(P5x+3AZ3xTd_it7IBRbMtrs@^~S4 delta 623 zcmZ9I&r4fD5Xaxn?!I5XV2nl67(v7zv575>Az%)gLk=E-cqm0LqM^{zQ_vuu(lL1K zA$I@TMy%a=(N0FSwOMCDrrKtP%J;AuJJ3F75{m#y`ljkp@2tS!&7%`0a z7IJ&h;V)7FQ|%`UmP2Rm2~=0jxw^dT=KMJHKX-G{4*hyJms_EaMs)9Tk&0}p*W9eF zZ`6!?wN&tqn(Q}ygcVb6p};h)IRn5Cr~`R`3mV`Vmmi?;yHK>u=UIWi^2wLqbbk`F z+8Q{6Lpo=hPI;aF%S=kN!caB{iB}lMH<-|r;Uit3B{K}VooO_twPn~J}O7`r6D*L?$N3CDMa11vb z1;be_;07&Nb5!!utV30AEb1158kp63ceL+K(jRXYoHk8F%HSMQE%H9$q(V)=*s}*$ Okx)z6Efh3j#~%O*S%_5t diff --git a/artifacts/mods/gl_npcarmor.ssl b/artifacts/mods/gl_npcarmor.ssl index f73298e5e..d6476dd32 100644 --- a/artifacts/mods/gl_npcarmor.ssl +++ b/artifacts/mods/gl_npcarmor.ssl @@ -4,18 +4,19 @@ Used to replace the scripted part of B-Team mod. Appropriate graphics are required for this mod to work. - Can be adopted to any mod by adjusting armor PIDs, NPC PIDs and NPC FIDs in INI file. + Can be adopted to any mod by adjusting armor PIDs, allowed weapon anim codes, NPC PIDs and NPC FIDs in INI file. NOTE: this script requires compiler from sfall modderspack with -s option (short circuit evaluation) - version 1.0 + version 1.1 */ #include "main.h" #define IS_ARMOR(item) (obj_type(item) == OBJ_TYPE_ITEM and obj_item_subtype(item) == item_type_armor) +#define IS_WEAPON(item) (obj_type(item) == OBJ_TYPE_ITEM and obj_item_subtype(item) == item_type_weapon) variable modIni := "npcarmor.ini", @@ -41,9 +42,28 @@ procedure check_armor_change(variable critter, variable item, variable isWorn) b return -1; end -// for NPCs when they change armor themselves +procedure check_weapon_change(variable critter, variable item, variable isWield) begin + variable npc, newWeaponAnim, weaponAnimList, i; + if (npcMap[obj_pid(critter)]) then begin + npc := npcMap[obj_pid(critter)]; + if isWield then begin + newWeaponAnim := get_proto_data(obj_pid(item), PROTO_WP_ANIM); + weaponAnimList := string_split(npc["WeaponAnims"], ","); + if newWeaponAnim then begin + foreach (i in weaponAnimList) begin + if (newWeaponAnim == atoi(i)) then return -1; + end + end else begin // anim code 0 - none/unarmed + return -1; + end + end + end + return 0; +end + +// for NPCs when they change armor/weapon themselves procedure invenwield_handler begin - variable critter, item, fid, slot, isWorn; + variable critter, item, fid, slot, isWorn, canWield; critter := get_sfall_arg; item := get_sfall_arg; slot := get_sfall_arg; @@ -55,6 +75,11 @@ procedure invenwield_handler begin art_change_fid_num(critter, fid); end end + + if (critter and item and (slot == INVEN_TYPE_RIGHT_HAND or slot == INVEN_TYPE_LEFT_HAND)) then begin + canWield := check_weapon_change(critter, item, isWorn); + set_sfall_return(canWield); + end end // when changing armor from inventory while controlling other NPCs @@ -69,12 +94,26 @@ procedure adjustfid_handler begin end end +// when changing weapon from inventory while controlling other NPCs +procedure inventorymove_handler begin + variable slot, item, canWield; + slot := get_sfall_arg; + item := get_sfall_arg; + if (dude_obj != real_dude_obj) then begin + if (IS_WEAPON(item) and (slot == INVEN_TYPE_RIGHT_HAND or slot == INVEN_TYPE_LEFT_HAND)) then begin + canWield := check_weapon_change(dude_obj, item, item != 0); + set_sfall_return(canWield); + end + end +end + procedure start begin variable sect, sects, armorTypes, armorType, npc, pid, pids, i; if game_loaded and (sfall_ver_major >= 4) then begin register_hook_proc(HOOK_INVENWIELD, invenwield_handler); register_hook_proc(HOOK_ADJUSTFID, adjustfid_handler); + register_hook_proc(HOOK_INVENTORYMOVE, inventorymove_handler); defaultFids := get_ini_section(modIni, "Default"); fix_array(defaultFids); @@ -97,6 +136,7 @@ procedure start begin sect := get_ini_section(modIni, ""+i); while (sect.PID) do begin npc := create_array_map; + npc["WeaponAnims"] := sect["WeaponAnims"]; npc["Default"] := atoi(sect["Default"]); foreach (armorType: pids in armorTypes) begin if (sect[armorType]) then begin From aaa76cb3d1c4daaa898a776bd18232c3d691a9e1 Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Wed, 6 Jun 2018 01:23:07 +0300 Subject: [PATCH 24/29] Quickly moving items in inventory. (#162) * Added an option for quickly moving items (w/o dialog box) in inventory. * An separate option is added to set the counter of maximum number of items when moving items. --- sfall/Modules/Inventory.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/sfall/Modules/Inventory.cpp b/sfall/Modules/Inventory.cpp index 4cad3ce69..783f8987f 100644 --- a/sfall/Modules/Inventory.cpp +++ b/sfall/Modules/Inventory.cpp @@ -35,6 +35,7 @@ static Delegate onAdjustFid; static DWORD mode; static DWORD maxItemSize; static DWORD reloadWeaponKey = 0; +static DWORD itemFastMoveKey = 0; long& GetActiveItemMode() { return fo::var::itemButtonItems[fo::var::itemCurrentItem].mode; @@ -794,6 +795,27 @@ void __declspec(naked) adjust_fid_replacement() { } } +void __declspec(naked) do_move_timer_hook() { + __asm { + cmp eax, 4; + jnz end; + pushad; + } + + KeyDown(itemFastMoveKey); + + __asm { + test eax, eax; + popad; + jz end; + mov dword ptr [esp], 0x476920; + retn; +end: + call fo::funcoffs::setup_move_timer_win_; + retn; + } +} + void InventoryReset() { invenapcost = GetConfigInt("Misc", "InventoryApCost", 4); } @@ -866,6 +888,15 @@ void Inventory::init() { SafeWrite8(0x476569, 0x91); // xchg ecx, eax }; + itemFastMoveKey = GetConfigInt("Input", "ItemFastMoveKey", DIK_LCONTROL); + if (itemFastMoveKey > 0) { + HookCall(0x476897, do_move_timer_hook); + } + + if (GetConfigInt("Misc", "ItemCounterDefaultMax", 0)) { + BlockCall(0x4768A3); // mov ebx, 1 + } + // Move items out of bag/backpack and back into the main inventory list by dragging them to character's image // (similar to Fallout 1 behavior) HookCall(0x471457, &inven_pickup_hook); From 28962f428f6a8dad29a82d00db56a4442659185f Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 6 Jun 2018 06:33:46 +0800 Subject: [PATCH 25/29] Added ItemFastMoveKey and ItemCounterDefaultMax options to ddraw.ini. Set ReloadReserve to be disabled by default. --- artifacts/ddraw.ini | 6 ++++++ sfall/Modules/Inventory.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index f70ef0e50..b2b42710c 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -130,6 +130,9 @@ WindowScrollKey=0 ;A key to press to reload your currently equipped weapon ReloadWeaponKey=0 +;A key to hold down to let you move/drop a whole stack of items at once, skipping the 'Move Items' window +ItemFastMoveKey=0x1d + ;A key to press to open a debug game editor DebugEditorKey=0 @@ -529,6 +532,9 @@ StackEmptyWeapons=0 ;If the amount of ammo boxes in the inventory is less than or equal to the reserve, only one box will be used ReloadReserve=-1 +;Set to 1 to change the counter in the 'Move Items' window to start at the maximum number of items +ItemCounterDefaultMax=0 + ;Allows 9 options (lines of text) to be displayed correctly in a dialog window DialogOptions9Lines=1 diff --git a/sfall/Modules/Inventory.cpp b/sfall/Modules/Inventory.cpp index 783f8987f..2dd1c407e 100644 --- a/sfall/Modules/Inventory.cpp +++ b/sfall/Modules/Inventory.cpp @@ -880,7 +880,7 @@ void Inventory::init() { } // Do not call the 'Move Items' window when using drap and drop to reload weapons in the inventory - int ReloadReserve = GetConfigInt("Misc", "ReloadReserve", 1); + int ReloadReserve = GetConfigInt("Misc", "ReloadReserve", -1); if (ReloadReserve >= 0) { SafeWrite32(0x47655F, ReloadReserve); // mov eax, ReloadReserve SafeWrite32(0x476563, 0x097EC139); // cmp ecx, eax; jle 0x476570 From 76f88eae185ffd5783c665e2fb1b0ecf875609a0 Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Mon, 11 Jun 2018 08:14:52 +0300 Subject: [PATCH 26/29] Added new events to HOOK_INVENTORYMOVE. Added possible to get a pointer to an weapon item in HOOK_INVENWIELD before unweld it. (#163) Refactoring the hooks code of the inventory. --- sfall/FalloutEngine/EngineUtils.cpp | 18 + sfall/FalloutEngine/EngineUtils.h | 4 + sfall/FalloutEngine/Enums.h | 8 + sfall/Modules/HookScripts/InventoryHs.cpp | 390 ++++++++++++---------- 4 files changed, 236 insertions(+), 184 deletions(-) diff --git a/sfall/FalloutEngine/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index b2239b398..70ba63a10 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -74,7 +74,25 @@ void SkillSetTags(long* tags, long num) { fo::func::skill_set_tags(tags, num); } +int _fastcall GetItemType(GameObject* item) { + return fo::func::item_get_type(item); +} +_declspec(noinline) GameObject* GetItemPtrSlot(GameObject* critter, InvenType slot) { + GameObject* itemPtr = 0; + switch (slot) { + case fo::INVEN_TYPE_LEFT_HAND : + itemPtr = fo::func::inven_left_hand(critter); + break; + case fo::INVEN_TYPE_RIGHT_HAND : + itemPtr = fo::func::inven_right_hand(critter); + break; + case fo::INVEN_TYPE_WORN : + itemPtr = fo::func::inven_worn(critter); + break; + } + return itemPtr; +} //--------------------------------------------------------- //print text to surface diff --git a/sfall/FalloutEngine/EngineUtils.h b/sfall/FalloutEngine/EngineUtils.h index 9cf21f867..a1b0ad5f1 100644 --- a/sfall/FalloutEngine/EngineUtils.h +++ b/sfall/FalloutEngine/EngineUtils.h @@ -50,6 +50,10 @@ void SkillGetTags(long* result, long num); // wrapper for skill_set_tags with bounds checking void SkillSetTags(long* tags, long num); +int _fastcall GetItemType(GameObject* item); + +_declspec(noinline) GameObject* GetItemPtrSlot(GameObject* critter, InvenType slot); + // Print text to surface void PrintText(char *displayText, BYTE colorIndex, DWORD x, DWORD y, DWORD textWidth, DWORD destWidth, BYTE *surface); // gets the height of the currently selected font diff --git a/sfall/FalloutEngine/Enums.h b/sfall/FalloutEngine/Enums.h index b5e0dc2f2..412ae8092 100644 --- a/sfall/FalloutEngine/Enums.h +++ b/sfall/FalloutEngine/Enums.h @@ -579,6 +579,14 @@ enum ItemType : long item_type_key = 6, }; +// Inventory Equates +enum InvenType : long +{ + INVEN_TYPE_WORN = 0, + INVEN_TYPE_RIGHT_HAND = 1, + INVEN_TYPE_LEFT_HAND = 2, +}; + #define OBJFLAG_CAN_WEAR_ITEMS (0xf000000) #define OBJFLAG_HELD_IN_RIGHT (0x10000) diff --git a/sfall/Modules/HookScripts/InventoryHs.cpp b/sfall/Modules/HookScripts/InventoryHs.cpp index 75031fcc8..30d74acd0 100644 --- a/sfall/Modules/HookScripts/InventoryHs.cpp +++ b/sfall/Modules/HookScripts/InventoryHs.cpp @@ -14,67 +14,84 @@ namespace sfall static const DWORD RemoveObjHookRet = 0x477497; static void __declspec(naked) RemoveObjHook() { __asm { - push ecx; - mov ecx, [esp + 4]; - hookbegin(4); + mov ecx, [esp + 8]; // call addr mov args[0], eax; mov args[4], edx; mov args[8], ebx; mov args[12], ecx; pushad; - push HOOK_REMOVEINVENOBJ; - call RunHookScript; + } + + BeginHook(); + argCount = 4; + RunHookScript(HOOK_REMOVEINVENOBJ); + EndHook(); + + __asm { popad; - hookend; - push esi; push edi; push ebp; - sub esp, 0xc; + sub esp, 0x0C; jmp RemoveObjHookRet; } } static void __declspec(naked) MoveCostHook() { __asm { - hookbegin(3); - mov args[0], eax; - mov args[4], edx; + mov args[0], eax; + mov args[4], edx; call fo::funcoffs::critter_compute_ap_from_distance_ - mov args[8], eax; + mov args[8], eax; pushad; - push HOOK_MOVECOST; - call RunHookScript; + } + + BeginHook(); + argCount = 3; + RunHookScript(HOOK_MOVECOST); + EndHook(); + + __asm { popad; cmp cRet, 1; - jl end; - mov eax, rets[0]; -end: - hookend; + cmovge eax, rets[0]; retn; } } -static int __stdcall SwitchHandHook2(fo::GameObject* item, fo::GameObject* itemReplaced, DWORD addr) { - int tmp; - if (itemReplaced && fo::func::item_get_type(itemReplaced) == fo::item_type_weapon && fo::func::item_get_type(item) == fo::item_type_ammo) { +/* Common inventory move hook */ +static int __fastcall InventoryMoveHook_Script(DWORD itemReplace, DWORD item, int type) { + + BeginHook(); + argCount = 3; + + args[0] = type; // event type + args[1] = item; // item being dropped + args[2] = itemReplace; // item being replaced here + + RunHookScript(HOOK_INVENTORYMOVE); + EndHook(); + + return (cRet > 0) ? rets[0] : -1; +} + +static int __fastcall SwitchHandHook_Script(fo::GameObject* item, fo::GameObject* itemReplaced, DWORD addr) { + if (itemReplaced && fo::GetItemType(itemReplaced) == fo::item_type_weapon && fo::GetItemType(item) == fo::item_type_ammo) { return -1; // to prevent inappropriate hook call after dropping ammo on weapon } BeginHook(); argCount = 3; - args[0] = (addr < 0x47136D) ? 1 : 2; + args[0] = (addr < 0x47136D) ? 1 : 2; // slot: 1 - left, 2 - right args[1] = (DWORD)item; args[2] = (DWORD)itemReplaced; - RunHookScript(HOOK_INVENTORYMOVE); // moveinventory - tmp = PartyControl::SwitchHandHook(item); + RunHookScript(HOOK_INVENTORYMOVE); + int tmp = PartyControl::SwitchHandHook(item); if (tmp != -1) { cRetTmp = 0; SetHSReturn(tmp); } EndHook(); - if (cRet > 0) { - return rets[0]; - } - return -1; + + return (cRet > 0) ? rets[0] : -1; } /* @@ -82,73 +99,60 @@ static int __stdcall SwitchHandHook2(fo::GameObject* item, fo::GameObject* itemR If switch_hand_ function is not called, item is not placed anywhere (it remains in main inventory) */ static void _declspec(naked) SwitchHandHook() { - _asm { + __asm { pushad; - mov ecx, eax; - mov eax, [esp+32]; // back address + mov ecx, eax; // item being moved + mov edx, [edx]; // other item + mov eax, [esp + 32]; // back address push eax; - mov edx, [edx]; - push edx; // other item - push ecx; // item being moved - call SwitchHandHook2; - cmp eax, -1; + call SwitchHandHook_Script; + cmp eax, -1; // ret value popad; - jne skip; + jne skip; call fo::funcoffs::switch_hand_; skip: retn; } } - static const DWORD UseArmorHack_back = 0x4713A9; // normal operation static const DWORD UseArmorHack_skip = 0x471481; // skip code, prevent wearing armor // This hack is called when an armor is dropped into the armor slot at inventory screen static void _declspec(naked) UseArmorHack() { __asm { - cmp eax, 0; + //previous instruction 'test eax, eax' jne skip; // not armor - hookbegin(3); - mov args[0], 3; - mov eax, [esp+24]; // item - mov args[4], eax; - mov eax, ds:[FO_VAR_i_worn] - mov args[8], eax; pushad; - push HOOK_INVENTORYMOVE; - call RunHookScript; + mov ecx, ds:[FO_VAR_i_worn]; // replacement item + mov edx, [esp + 0x58 - 0x40 + 32]; // item + push 3; // event: armor slot + call InventoryMoveHook_Script; + cmp eax, -1; // ret value popad; - cmp cRet, 1; - jl back; - cmp rets[0], -1; jne skip; -back: - hookend; jmp UseArmorHack_back; skip: - hookend; jmp UseArmorHack_skip; } } static void _declspec(naked) MoveInventoryHook() { __asm { - hookbegin(3); - mov args[0], 0; - mov args[4], edx; - mov args[8], 0; // no item being replaced here.. pushad; - push HOOK_INVENTORYMOVE; - call RunHookScript; + xor ecx, ecx; // no item replace + mov ebx, ecx; + cmp dword ptr ds:[FO_VAR_curr_stack], 0; + jle noCont; + mov ecx, eax; // contaner ptr + mov ebx, 5; +noCont: + push ebx; // event: 0 - main backpack, 5 - contaner + call InventoryMoveHook_Script; // edx - item + cmp eax, -1; // ret value popad; - cmp cRet, 1; - jl skipcheck; - cmp rets[0], -1; - jne skipcall; -skipcheck: - call fo::funcoffs::item_add_force_ -skipcall: - hookend; + jne skip; + call fo::funcoffs::item_add_force_; +skip: retn; } } @@ -157,152 +161,171 @@ static void _declspec(naked) MoveInventoryHook() { // - allows to prevent item being dropped if 0 is returned with set_sfall_return // - called for every item when dropping multiple items in stack (except caps) // - when dropping caps it called always once -// - if 0 is returned while dropping caps, selected amount - 1 will still disappear from inventory -/* -static void __declspec(naked) InvenActionCursor_ObjDrop_Hook() { +// - if 0 is returned while dropping caps, selected amount - 1 will still disappear from inventory (fixed) +static DWORD nextHookDropSkip = 0; +static int dropResult = -1; +static void __declspec(naked) InvenActionCursorObjDropHook() { + if (nextHookDropSkip) { + nextHookDropSkip = 0; + dropResult = -1; + } else { + __asm { + pushad; + xor ecx, ecx; // no itemReplace + push 6; // event: item drop ground + call InventoryMoveHook_Script; // edx - item + mov dropResult, eax; // ret value + popad; + cmp dword ptr [esp], 0x47379A + 5; // caps call address + jz capsMultiDrop; + } + } + + if (dropResult == -1) { + _asm call fo::funcoffs::obj_drop_; + } + _asm retn; + +/* for only caps multi drop */ +capsMultiDrop: + if (dropResult == -1) { + nextHookDropSkip = 1; + _asm call fo::funcoffs::item_remove_mult_; + } else { + _asm mov dword ptr [esp], 0x473874; // no caps drop + } + _asm retn; +} + +static int __fastcall DropIntoContainer(DWORD ptrCont, DWORD item, DWORD addrCall) { + int type = 5; // event: move to container (Crafty compatibility) + + if (addrCall == 0x47147C + 5) { // drop out contaner + ptrCont = 0; + type = 0; // event: move to main backpack + } + return InventoryMoveHook_Script(ptrCont, item, type); +} + +static const DWORD DropIntoContainer_back = 0x47649D; // normal operation +static const DWORD DropIntoContainer_skip = 0x476503; +static void __declspec(naked) DropIntoContainerHack() { __asm { - hookbegin(3); - mov args[0], 5; - mov args[4], edx; // item being dropped - mov args[8], 0; // no item being replaced here.. pushad; - push HOOK_INVENTORYMOVE; - call RunHookScript; + mov ecx, ebp; // contaner ptr + mov edx, esi; // item + mov eax, [esp + 0x10 + 32]; // call address + push eax; + call DropIntoContainer; + cmp eax, -1; // ret value popad; - cmp cRet, 1; - jl skipcheck; - cmp rets[0], -1; - jne skipcall; -skipcheck: - call fo::funcoffs::obj_drop_; -skipcall: - hookend; - retn; + jne skipdrop; + jmp DropIntoContainer_back; +skipdrop: + mov eax, -1; + jmp DropIntoContainer_skip; } } -*/ static const DWORD DropAmmoIntoWeaponHack_back = 0x47658D; // proceed with reloading static const DWORD DropAmmoIntoWeaponHack_return = 0x476643; static void _declspec(naked) DropAmmoIntoWeaponHack() { __asm { - hookbegin(3); - mov args[0], 4; - mov eax, [esp]; - mov args[4], eax; - mov args[8], ebp; pushad; - push HOOK_INVENTORYMOVE; - call RunHookScript; + mov ecx, ebp; // weapon ptr + mov edx, [esp + 32]; // item var: ammo_ + push 4; // event: weapon reloading + call InventoryMoveHook_Script; + cmp eax, -1; // ret value popad; - cmp cRet, 1; - jl proceedreloading; - cmp rets[0], -1; - jne donothing; -proceedreloading: - hookend; - mov ebx, 1; // overwritten code + jne donothing; + mov ebx, 1; // overwritten code jmp DropAmmoIntoWeaponHack_back; donothing: - hookend; - mov eax, 0; + xor eax, eax; // result 0 jmp DropAmmoIntoWeaponHack_return; } } +/* Common InvenWield hook */ +static void InvenWieldHook_Script(int flag) { + BeginHook(); + argCount = 4; + args[3] = flag; // invenwield flag + RunHookScript(HOOK_INVENWIELD); + EndHook(); +} -static void _declspec(naked) invenWieldFunc_Hook() { +static void _declspec(naked) InvenWieldFuncHook() { using namespace fo; __asm { - hookbegin(4); mov args[0], eax; // critter mov args[4], edx; // item mov args[8], ebx; // slot - mov args[12], 1; // wield flag pushad; - cmp ebx, 1; // right hand slot? - je skip; - mov eax, edx; - call fo::funcoffs::item_get_type_; - cmp eax, item_type_armor; - jz skip; - mov args[8], 2; // INVEN_TYPE_LEFT_HAND -skip: - push HOOK_INVENWIELD; - call RunHookScript; - popad; - cmp cRet, 1; - jl defaulthandler; - cmp rets[0], -1; - je defaulthandler; - jmp end - defaulthandler : - call fo::funcoffs::invenWieldFunc_ - end : - hookend; - retn; } + + // right hand slot? + if (args[2] != INVEN_TYPE_RIGHT_HAND && GetItemType((GameObject*)args[1]) != item_type_armor) { + args[2] = INVEN_TYPE_LEFT_HAND; + } + + InvenWieldHook_Script(1); // wield flag + + _asm popad; + if (cRet == 0 || rets[0] == -1) { + _asm call funcoffs::invenWieldFunc_; + } + _asm retn; } // called when unwielding weapons -static void _declspec(naked) invenUnwieldFunc_Hook() { +static void _declspec(naked) InvenUnwieldFuncHook() { __asm { - hookbegin(4); - mov args[0], eax; // critter - mov args[4], 0; // item - mov args[8], edx; // slot - mov args[12], 0; // wield flag - cmp edx, 0; // left hand slot? - jne notlefthand; - mov args[8], 2; // left hand -notlefthand: + mov args[0], eax; // critter + mov args[8], edx; // slot pushad; - push HOOK_INVENWIELD; - call RunHookScript; - popad; - cmp cRet, 1; - jl defaulthandler; - cmp rets[0], -1; - je defaulthandler; - jmp end - defaulthandler : - call fo::funcoffs::invenUnwieldFunc_; -end: - hookend; - retn; } + + // set slot + if (args[2] == 0) { // left hand slot? + args[2] = fo::INVEN_TYPE_LEFT_HAND; + } + args[1] = (DWORD)fo::GetItemPtrSlot((fo::GameObject*)args[0], (fo::InvenType)args[2]); // get item + + InvenWieldHook_Script(0); // unwield flag + + _asm popad; + if (cRet == 0 || rets[0] == -1) { + _asm call fo::funcoffs::invenUnwieldFunc_; + } + _asm retn; } -static void _declspec(naked) correctFidForRemovedItem_Hook() { +static void _declspec(naked) CorrectFidForRemovedItemHook() { __asm { - hookbegin(4); mov args[0], eax; // critter mov args[4], edx; // item - mov args[8], 0; // slot - mov args[12], 0; // wield flag (armor by default) - test ebx, 0x02000000; // right hand slot? - jz notrighthand; - mov args[8], 1; // right hand -notrighthand: - test ebx, 0x01000000; // left hand slot? - jz notlefthand; - mov args[8], 2; // left hand -notlefthand: + mov args[8], ebx; // item flag pushad; - push HOOK_INVENWIELD; - call RunHookScript; - popad; - cmp cRet, 1; - jl defaulthandler; - cmp rets[0], -1; - je defaulthandler; - jmp end; -defaulthandler: - call fo::funcoffs::correctFidForRemovedItem_; -end: - hookend; - retn; } + + // set slot + if (args[2] & fo::ObjectFlag::Right_Hand) { // right hand slot + args[2] = fo::INVEN_TYPE_RIGHT_HAND; + } else if (args[2] & fo::ObjectFlag::Left_Hand) { // left hand slot + args[2] = fo::INVEN_TYPE_LEFT_HAND; + } else { + args[2] = fo::INVEN_TYPE_WORN; // armor slot + } + + InvenWieldHook_Script(0); // unwield flag (armor by default) + + _asm popad; + if (cRet == 0 || rets[0] == -1) { + _asm call fo::funcoffs::correctFidForRemovedItem_; + } + _asm retn; } void AdjustFidHook(DWORD vanillaFid) { @@ -318,7 +341,7 @@ void AdjustFidHook(DWORD vanillaFid) { void InitInventoryHookScripts() { LoadHookScript("hs_removeinvenobj", HOOK_REMOVEINVENOBJ); - MakeJump(0x477490, RemoveObjHook); + MakeJump(0x477492, RemoveObjHook); // old 0x477490 LoadHookScript("hs_movecost", HOOK_MOVECOST); HookCalls(MoveCostHook, { 0x417665, 0x44B88A }); @@ -329,19 +352,18 @@ void InitInventoryHookScripts() { 0x47136D // right slot }); MakeJump(0x4713A3, UseArmorHack); - //HookCall(0x4711B3, &DropIntoContainerHook); - //HookCall(0x47147C, &DropIntoContainerHook); + MakeJump(0x476491, DropIntoContainerHack); HookCall(0x471200, MoveInventoryHook); - //HookCall(0x4712C7, &DropAmmoIntoWeaponHook); - //HookCall(0x471351, &DropAmmoIntoWeaponHook); MakeJump(0x476588, DropAmmoIntoWeaponHack); - // TODO: consider adding item drop event into INVENTORYMOVE or different hook - //HookCalls(InvenActionCursor_ObjDrop_Hook, { 0x473851, 0x47386F }); + HookCalls(InvenActionCursorObjDropHook, { + 0x473851, 0x47386F, + 0x47379A // caps multi drop + }); LoadHookScript("hs_invenwield", HOOK_INVENWIELD); - HookCalls(invenWieldFunc_Hook, { 0x47275E, 0x495FDF }); - HookCalls(invenUnwieldFunc_Hook, { 0x45967D, 0x472A5A, 0x495F0B }); - HookCalls(correctFidForRemovedItem_Hook, { 0x45680C, 0x45C4EA }); + HookCalls(InvenWieldFuncHook, { 0x47275E, 0x495FDF }); + HookCalls(InvenUnwieldFuncHook, { 0x45967D, 0x472A5A, 0x495F0B }); + HookCalls(CorrectFidForRemovedItemHook, { 0x45680C, 0x45C4EA }); LoadHookScript("hs_adjustfid", HOOK_ADJUSTFID); Inventory::OnAdjustFid() += AdjustFidHook; From 177137f2ee0b758e4ab5332738185a0ae2c3a470 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 11 Jun 2018 13:40:09 +0800 Subject: [PATCH 27/29] Edited the description in hookscripts.txt for changes to HOOK_INVENTORYMOVE and HOKK_INVENWIELD. Fixed a bug in DisplaySecondWeaponRange that didn't display correct weapon range when the secondary mode is aimed (e.g. spear and throwing knife) Removed trilling spaces in previous commit. --- artifacts/ddraw.ini | 2 +- artifacts/scripting/hookscripts.txt | 10 +++++----- artifacts/scripting/sfall function notes.txt | 6 +++--- sfall/FalloutEngine/Enums.h | 4 ++-- sfall/Modules/HookScripts/InventoryHs.cpp | 10 +++++----- sfall/Modules/MiscPatches.cpp | 7 +++++-- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index b2b42710c..e5b8bb5bb 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -130,7 +130,7 @@ WindowScrollKey=0 ;A key to press to reload your currently equipped weapon ReloadWeaponKey=0 -;A key to hold down to let you move/drop a whole stack of items at once, skipping the 'Move Items' window +;A key to hold down to let you move/drop a whole stack of items at once without the 'Move Items' window ItemFastMoveKey=0x1d ;A key to press to open a debug game editor diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index 8cdc7ff0d..44d6033e2 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -189,7 +189,7 @@ Critter arg1 - The critter that just died HOOK_FINDTARGET (hs_findtarget.int) -Runs when the ai is trying to pick a target in combat. Fallout first chooses a list of 4 likely suspects, then normally sorts them in order of weakness/distance/etc depending on the ai caps of the attacker. This hook replaces that sorting function, allowing you to sort the targets in some arbitrary way. Use sfall_return to give the 4 targets, in order of preference. All 4 must be given if you want to override normal sorting; if you want to specify less than 4 targets fill in the extra spaces with 0's. If you do not give 4 targets, the npcs normal sorting mechanism will be used. +Runs when the ai is trying to pick a target in combat. Fallout first chooses a list of 4 likely suspects, then normally sorts them in order of weakness/distance/etc depending on the ai caps of the attacker. This hook replaces that sorting function, allowing you to sort the targets in some arbitrary way. Use sfall_return to give the 4 targets, in order of preference. All 4 must be given if you want to override normal sorting; if you want to specify less than 4 targets fill in the extra spaces with 0's. If you do not give 4 targets, the NPCs normal sorting mechanism will be used. The return values can include critters that weren't in the list of possible targets, but the additional targets may still be discarded later on in the combat turn if they are out of the attackers perception or the chance of a successful hit is too low. The list of possible targets often includes duplicated entries. @@ -312,7 +312,7 @@ int arg2 - The default max damage Item arg3 - The weapon used. (0 if unarmed) Critter arg4 - The critter doing the attacking int arg5 - The type of attack -int arg6 - non zero if this is an attack using a melee weapon +int arg6 - non-zero if this is an attack using a melee weapon int ret1 - Either the damage to be used, if ret2 isn't given, or the new minimum damage if it is int ret2 - The new maximum damage @@ -416,9 +416,9 @@ What you can do: - add AP costs for all inventory movement including reloading - apply or remove some special scripted effects depending on PC's armor -int arg1 - Target slot (0 - main backpack, 1 - left hand, 2 - right hand, 3 - armor slot, 4 - weapon, when reloading it by dropping ammo) +int arg1 - Target slot (0 - main backpack, 1 - left hand, 2 - right hand, 3 - armor slot, 4 - weapon, when reloading it by dropping ammo, 5 - container, like bag/backpack, 6 - dropping on the ground) Item arg2 - Item being moved -Item arg3 - Item being replaced or weapon being reloaded (can be 0) +Item arg3 - Item being replaced, weapon being reloaded, or container being filled (can be 0) int ret1 - Override setting (-1 - use engine handler, any other value - prevent relocation of item/reloading weapon) @@ -432,7 +432,7 @@ NOTE: when replacing a previously wielded armor or weapon, the unwielding hook w If you need to rely on this, try checking if armor/weapon already equipped when wielding hook is executed. Critter arg1 - critter -Obj arg2 - item being wielded or unwielded (weapon/armor), may be 0 when unwielding +Obj arg2 - item being wielded or unwielded (weapon/armor) int arg3 - slot (INVEN_TYPE_*) int arg4 - 1 when wielding, 0 when unwielding diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index b746acc4d..739fe8ed2 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -72,7 +72,7 @@ arrays are created and manipulated with the xxx_array functions. An array must f NOTE: the above description only applies when "arraysBehavior" is set to 0 in ddraw.ini. Refer to "arrays.txt" for detailed description of new arrays behavior. -force_aimed_shots and disable_aimed_shots allow overriding the normal rules regarding which weapons are allowed to make aimed attacks. (e.g. weapons that cause explosive damage normally cannot normally make aimed shots.) force_aimed_shots will allow a weapon to make aimed shots even if it normally couldn't, and disable_aimed_shots stops a weapon from making aimed shots even if it normally could. Both of these functions affect player and npcs alike. force_aimed_shots does not override the effects of the fast shot trait. The list of edited weapons is not saved over game loads, so you need to call the functions once at each reload. Use a pid of 0 to represent unarmed. +force_aimed_shots and disable_aimed_shots allow overriding the normal rules regarding which weapons are allowed to make aimed attacks. (e.g. weapons that cause explosive damage normally cannot normally make aimed shots.) force_aimed_shots will allow a weapon to make aimed shots even if it normally couldn't, and disable_aimed_shots stops a weapon from making aimed shots even if it normally could. Both of these functions affect player and NPCs alike. force_aimed_shots does not override the effects of the fast shot trait. The list of edited weapons is not saved over game loads, so you need to call the functions once at each reload. Use a pid of 0 to represent unarmed. get/set_critter_skill_points will get/set the number of additional points a critter has in a skill, on top of whatever they have from their stats and other bonuses. Note that skill points are part of the proto, so calling set_skill_points on a critter will affect all critters that share the same proto. @@ -101,10 +101,10 @@ array - array ID to be used with array-related functions (actually an integer) - returns 1 the first time it is called after a new game or game load, and 0 any time after. It works on an individual basis for each script, so one script wont interfere with others. It's primary use is for global scripts, so that they know when to call set_global_script_repeat, but it can be called from normal scripts too. > void inc_npc_level(string npc) -- takes an npc name as an argument. The npc must be in your party. This function ignores player level requirements and the minimum 3 player level delay between npc level gains. It also ignores the random element, regardless of sfall's NPCAutoLevel setting. +- takes an NPC name as an argument. The NPC must be in your party. This function ignores player level requirements and the minimum 3 player level delay between NPC level gains. It also ignores the random element, regardless of sfall's NPCAutoLevel setting. > int get_npc_level(string npc) -- also takes the npc name as an argument, and returns the npc's current level. Again, the npc needs to be in your party. +- also takes the NPC name as an argument, and returns the NPC's current level. Again, the NPC needs to be in your party. > void set_car_current_town(int town) - changes the current town index for the player's car diff --git a/sfall/FalloutEngine/Enums.h b/sfall/FalloutEngine/Enums.h index 412ae8092..dafc70073 100644 --- a/sfall/FalloutEngine/Enums.h +++ b/sfall/FalloutEngine/Enums.h @@ -420,8 +420,8 @@ enum Trait : long enum class ScenerySubType : long { DOOR = 0, - STAIRS = 1, - ELEVATOR = 2, + STAIRS = 1, + ELEVATOR = 2, LADDER_BOTTOM = 3, LADDER_TOP = 4, GENERIC = 5 diff --git a/sfall/Modules/HookScripts/InventoryHs.cpp b/sfall/Modules/HookScripts/InventoryHs.cpp index 30d74acd0..5f46ebfb8 100644 --- a/sfall/Modules/HookScripts/InventoryHs.cpp +++ b/sfall/Modules/HookScripts/InventoryHs.cpp @@ -179,7 +179,7 @@ static void __declspec(naked) InvenActionCursorObjDropHook() { cmp dword ptr [esp], 0x47379A + 5; // caps call address jz capsMultiDrop; } - } + } if (dropResult == -1) { _asm call fo::funcoffs::obj_drop_; @@ -270,7 +270,7 @@ static void _declspec(naked) InvenWieldFuncHook() { args[2] = INVEN_TYPE_LEFT_HAND; } - InvenWieldHook_Script(1); // wield flag + InvenWieldHook_Script(1); // wield flag _asm popad; if (cRet == 0 || rets[0] == -1) { @@ -312,11 +312,11 @@ static void _declspec(naked) CorrectFidForRemovedItemHook() { // set slot if (args[2] & fo::ObjectFlag::Right_Hand) { // right hand slot - args[2] = fo::INVEN_TYPE_RIGHT_HAND; + args[2] = fo::INVEN_TYPE_RIGHT_HAND; } else if (args[2] & fo::ObjectFlag::Left_Hand) { // left hand slot - args[2] = fo::INVEN_TYPE_LEFT_HAND; + args[2] = fo::INVEN_TYPE_LEFT_HAND; } else { - args[2] = fo::INVEN_TYPE_WORN; // armor slot + args[2] = fo::INVEN_TYPE_WORN; // armor slot } InvenWieldHook_Script(0); // unwield flag (armor by default) diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index 21a032f8b..8b94b79b5 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -368,8 +368,11 @@ static void __declspec(naked) objCanSeeObj_ShootThru_Fix() {//(EAX *objStruct, E static DWORD __fastcall GetWeaponSlotMode(DWORD itemPtr, DWORD mode) { int slot = (mode > 0) ? 1 : 0; auto itemButton = fo::var::itemButtonItems; - if ((DWORD)itemButton.vals[slot].item == itemPtr && (DWORD)itemButton.vals[slot].mode == 3) { - mode++; + if ((DWORD)itemButton[slot].item == itemPtr) { + int slotMode = itemButton[slot].mode; + if (slotMode == 3 || slotMode == 4) { + mode++; + } } return mode; } From d5a38eb3aa2149ad8b25e07dcaabefab85728343 Mon Sep 17 00:00:00 2001 From: "Mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Tue, 12 Jun 2018 07:13:42 +0300 Subject: [PATCH 28/29] Fix for inventory moving hook - an item drop into container when it is in the slot of the hands. (#167) --- sfall/Modules/HookScripts/InventoryHs.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sfall/Modules/HookScripts/InventoryHs.cpp b/sfall/Modules/HookScripts/InventoryHs.cpp index 5f46ebfb8..6e5f3eefb 100644 --- a/sfall/Modules/HookScripts/InventoryHs.cpp +++ b/sfall/Modules/HookScripts/InventoryHs.cpp @@ -115,16 +115,14 @@ static void _declspec(naked) SwitchHandHook() { } } -static const DWORD UseArmorHack_back = 0x4713A9; // normal operation +static const DWORD UseArmorHack_back = 0x4713AF; // normal operation (old 0x4713A9) static const DWORD UseArmorHack_skip = 0x471481; // skip code, prevent wearing armor // This hack is called when an armor is dropped into the armor slot at inventory screen static void _declspec(naked) UseArmorHack() { __asm { - //previous instruction 'test eax, eax' - jne skip; // not armor + mov ecx, ds:[FO_VAR_i_worn]; // replacement item (override code) + mov edx, [esp + 0x58 - 0x40]; // item pushad; - mov ecx, ds:[FO_VAR_i_worn]; // replacement item - mov edx, [esp + 0x58 - 0x40 + 32]; // item push 3; // event: armor slot call InventoryMoveHook_Script; cmp eax, -1; // ret value @@ -227,6 +225,14 @@ static void __declspec(naked) DropIntoContainerHack() { } } +static const DWORD DropIntoContainerRet = 0x471481; +static void __declspec(naked) DropIntoContainerHandSlotHack() { + __asm { + call fo::funcoffs::drop_into_container_; + jmp DropIntoContainerRet; + } +} + static const DWORD DropAmmoIntoWeaponHack_back = 0x47658D; // proceed with reloading static const DWORD DropAmmoIntoWeaponHack_return = 0x476643; static void _declspec(naked) DropAmmoIntoWeaponHack() { @@ -351,8 +357,10 @@ void InitInventoryHookScripts() { 0x4712E3, // left slot 0x47136D // right slot }); - MakeJump(0x4713A3, UseArmorHack); + MakeJump(0x4713A9, UseArmorHack); // old 0x4713A3 MakeJump(0x476491, DropIntoContainerHack); + MakeJump(0x471338, DropIntoContainerHandSlotHack); + MakeJump(0x4712AB, DropIntoContainerHandSlotHack); HookCall(0x471200, MoveInventoryHook); MakeJump(0x476588, DropAmmoIntoWeaponHack); HookCalls(InvenActionCursorObjDropHook, { From e14ac89463de1f98665d82181f87d83a88dbf7b0 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 12 Jun 2018 20:52:03 +0800 Subject: [PATCH 29/29] Added more info to the comments of various keys in [Input] section of ddraw.ini. --- artifacts/ddraw.ini | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index e5b8bb5bb..6b50a5c5a 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -107,7 +107,7 @@ SpeedModKey=-1 ;A key to press to toggle the speed tweak on or off ;Specify 0 if you don't want a toggle key, or a DX scancode otherwise -SpeedToggleKey=0x00 +SpeedToggleKey=0 ;The keys corresponding to the 10 speed slots ;Set to 0 to disable a slot, otherwise specify the DX scancode of the key you want to use @@ -128,12 +128,15 @@ SpeedKey9=0x00 WindowScrollKey=0 ;A key to press to reload your currently equipped weapon +;Set to 0 if you don't want a reload key, or a DX scancode otherwise ReloadWeaponKey=0 ;A key to hold down to let you move/drop a whole stack of items at once without the 'Move Items' window +;Set to 0 if you don't want to use a modifier key, or a DX scancode otherwise ItemFastMoveKey=0x1d -;A key to press to open a debug game editor +;A key to press to open a debug game editor (requires FalloutClient.exe from the modders pack) +;Set to 0 to disable, or a DX scancode otherwise DebugEditorKey=0 ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX