From 0980967cee5a3d58116f7e1e80b6eb0914997f2f Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 19 Feb 2019 21:33:42 +0800 Subject: [PATCH] Changed the implementation of BarBoxes.cpp (from Mr.Stalin) Added "add_iface_tag" script function. --- artifacts/scripting/headers/sfall.h | 3 +- artifacts/scripting/sfall function notes.txt | 8 +- sfall/FalloutEngine/VariableOffsets.h | 1 + sfall/Modules/BarBoxes.cpp | 241 ++++++++++-------- sfall/Modules/BarBoxes.h | 4 +- .../Modules/Scripting/Handlers/Interface.cpp | 10 +- sfall/Modules/Scripting/Handlers/Interface.h | 2 + sfall/Modules/Scripting/Handlers/Metarule.cpp | 1 + 8 files changed, 162 insertions(+), 108 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 693a3eb3..b46bc7d0 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -237,7 +237,8 @@ #define party_member_list_critters party_member_list(0) #define party_member_list_all party_member_list(1) - +// sfall_funcX macros +#define add_iface_tag sfall_func0("add_iface_tag") #define art_cache_clear sfall_func0("art_cache_clear") #define attack_is_aimed sfall_func0("attack_is_aimed") #define car_gas_amount sfall_func0("car_gas_amount") diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 0d3fc9d7..6e0b6ad2 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -498,9 +498,13 @@ Some utility/math functions are available: > 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 (4 + the value of BoxBarCount 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 (4 + the value of BoxBarCount in ddraw.ini) or the number of the last custom box added using the add_ifaca_tag function - The text is limited to 19 characters -- available colors: 0 - green, 1 - red, 2 - white, 3 - yellow, 4 - dark yellow, 5 - blue, 6 - purple +- available colors: 0 - green, 1 - red, 2 - white, 3 - yellow, 4 - dark yellow, 5 - blue, 6 - purple, 7 - dull pink + +> int sfall_func0("add_iface_tag") +- adds one custom box to the current boxes, and returns the number of the added tag (-1 if the tags limit is exceeded) +- The maximum number of boxes is limited to 126 tags > void sfall_func1("inventory_redraw", int invSide) - redraws inventory list in the inventory/use inventory item on/loot/barter screens diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index d4e521d5..a8aeacbb 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -222,6 +222,7 @@ // colors #define FO_VAR_BlueColor 0x6A38EF #define FO_VAR_DarkGreenColor 0x6A3A90 +#define FO_VAR_DullPinkColor 0x6AB718 #define FO_VAR_GoodColor 0x6AB4EF #define FO_VAR_GreenColor 0x6A3CB0 #define FO_VAR_PeanutButter 0x6A82F3 diff --git a/sfall/Modules/BarBoxes.cpp b/sfall/Modules/BarBoxes.cpp index 0251f2ce..43b13336 100644 --- a/sfall/Modules/BarBoxes.cpp +++ b/sfall/Modules/BarBoxes.cpp @@ -25,28 +25,26 @@ namespace sfall { -int BarBoxes::boxCount; // total count box -static int actualBoxCount; -static int sizeBox; +int BarBoxes::boxCount; // current box count +static int totalBoxCount, actualBoxCount; // total boxes and w/o vanilla +static int initCount = 5; // init config counter (5 - vanilla box) +static int sizeBox, setBoxIndex = 5; #define sSize (12) -struct sBox { +static struct sBox { DWORD msg; DWORD colour; void* mem; -}; +} *boxes; -#define tSize (25) -struct tBox { - bool hasText; - DWORD color; - char text[tSize - 5]; -}; - -static sBox* boxes; -static tBox* boxText; -static bool* boxesEnabled; -static DWORD* colorBakup; +#define tSize (24) +static struct tBox { + bool hasText; + char color; + char cfgColor; + bool isActive; + char text[tSize - 4]; +} *boxText; static bool setCustomBoxText; @@ -58,13 +56,14 @@ static const DWORD DisplayBoxesRet1 = 0x4615A8; static const DWORD DisplayBoxesRet2 = 0x4615BE; static void __declspec(naked) DisplayBoxesHack() { __asm { - mov edx, [boxesEnabled]; - mov ebx, 0; + mov edx, [boxText]; + xor ebx, ebx; start: - mov al, byte ptr [edx][ebx]; + imul eax, ebx, tSize; + mov al, byte ptr [edx][eax + 3]; // .isActive test al, al; jz next; - lea eax, [ebx + 5]; + lea eax, [ebx + 5]; // index box call fo::funcoffs::add_bar_box_; add esi, eax; next: @@ -83,27 +82,27 @@ fail: static void __declspec(naked) BarBoxesTextHack() { __asm { push ecx; // ecx = BoxIndex - sub ecx, 5; + sub ecx, 5; // subtract vanilla boxes imul ecx, tSize; mov esi, [boxText]; // boxText addr cmp byte ptr [esi][ecx], 1; // .hasText - jnz end; + je customText; + add esp, 4; + jmp fo::funcoffs::getmsg_; +customText: // get color - mov ebx, dword ptr [esi][ecx + 1]; // .color + movzx ebx, byte ptr [esi][ecx + 1]; // .color // set text - lea eax, [esi + ecx + 5]; // .text + lea eax, [esi + ecx + 4]; // .text // set color - pop ecx; + pop ecx; // restore BoxIndex imul ecx, sSize; mov esi, [boxes]; // boxes addr cmp dword ptr [esi][ecx + 4], 2; // .colour jb skip; - mov [esp + 0x440 - 0x20], ebx; // Color + mov [esp + 0x440 - 0x20], ebx; // set to Color skip: retn; -end: - add esp, 4; - jmp fo::funcoffs::getmsg_; } } @@ -111,7 +110,7 @@ static const DWORD SetIndexBoxRet = 0x4612E8; static void __declspec(naked) BarBoxesIndexHack() { __asm { mov eax, ds:[0x4612E2]; // fontnum - mov ecx, 5; // start index + mov ecx, setBoxIndex; // start index mov edx, ecx; jmp SetIndexBoxRet; } @@ -129,9 +128,10 @@ exitLoop: } } -static void ReconstructBarBoxes() { +static void ReconstructBarBoxes(int count) { + SafeWrite8(0x46140B, count); __asm { - call fo::funcoffs::refresh_box_bar_win_; + //call fo::funcoffs::refresh_box_bar_win_; call fo::funcoffs::reset_box_bar_win_; call fo::funcoffs::construct_box_bar_win_; } @@ -139,28 +139,28 @@ static void ReconstructBarBoxes() { static void ResetBoxes() { for (int i = 0; i < actualBoxCount; i++) { - boxesEnabled[i] = false; - boxes[i + 5].colour = colorBakup[i]; + boxText[i].isActive = false; + boxText[i].hasText = false; + boxes[i + 5].colour = boxText[i].cfgColor; } + if (setBoxIndex == 5) return; - if (!setCustomBoxText) return; - - //Restore boxes - SafeWrite32(0x461343, 0x00023D05); // call getmsg_ - ReconstructBarBoxes(); - SafeWrite8(0x461243, 0x31); - SafeWrite32(0x461244, 0x249489D2); - - setCustomBoxText = false; + // Restore boxes + setBoxIndex = 5; // set start + //SafeWrite32(0x461343, 0x00023D05); // call getmsg_ + ReconstructBarBoxes(totalBoxCount); + //SafeWrite8(0x461243, 0x31); + //SafeWrite32(0x461244, 0x249489D2); } void BarBoxes::SetText(int box, const char* text, DWORD color) { + setBoxIndex = box; boxes[box].colour = color; box -= 5; boxText[box].hasText = true; strncpy_s(boxText[box].text, text, _TRUNCATE); - DWORD clr; + char clr; switch (color) { case 2: clr = fo::var::WhiteColor; @@ -177,101 +177,140 @@ void BarBoxes::SetText(int box, const char* text, DWORD color) { case 6: clr = fo::var::GoodColor; break; + case 7: + clr = *(BYTE*)FO_VAR_DullPinkColor; + break; default: clr = fo::var::GreenColor; } boxText[box].color = clr; - bool* enabled = new bool[actualBoxCount]; - for (int i = 0; i < actualBoxCount; i++) { - enabled[i] = boxesEnabled[i]; - boxesEnabled[i] = false; - } - if (!setCustomBoxText) { + setCustomBoxText = true; MakeCall(0x461342, BarBoxesTextHack); // construct_box_bar_win_ MakeJump(0x461243, BarBoxesIndexHack); // construct_box_bar_win_ - setCustomBoxText = true; } - - ReconstructBarBoxes(); - - for (int i = 0; i < actualBoxCount; i++) { - boxesEnabled[i] = enabled[i]; - } - delete[] enabled; - - __asm call fo::funcoffs::refresh_box_bar_win_; + ReconstructBarBoxes(setBoxIndex + 1); } -void BarBoxes::init() { - - boxCount = 5 + GetConfigInt("Misc", "BoxBarCount", 5); - if (boxCount < 10) boxCount = 10; - if (boxCount > 100) boxCount = 100; - - actualBoxCount = boxCount - 5; - sizeBox = sSize * boxCount; - - boxes = new sBox[boxCount](); - boxText = new tBox[actualBoxCount](); - boxesEnabled = new bool[actualBoxCount](); - colorBakup = new DWORD[actualBoxCount](); - - memcpy(boxes, (void*)0x518FE8, sSize * 5); - - for (int i = 5; i < boxCount; i++) { - boxes[i].msg = 100 + i; - } - - auto boxBarColors = GetConfigString("Misc", "BoxBarColours", "", actualBoxCount + 1); - int size = boxBarColors.size(); - for (int i = 0; i < size; i++) { - if (boxBarColors[i] == '1') { - boxes[i + 5].colour = 1; - colorBakup[i] = 1; - } - } - +static void SetEngine(int count) { SafeWriteBatch((DWORD)boxes + 8, bboxMemAddr); //.mem SafeWrite32(0x4612FE, (DWORD)boxes + 4); //.colour SafeWrite32(0x46133C, (DWORD)boxes); //.msg - SafeWrite8(0x46127C, boxCount); - SafeWrite8(0x46140B, boxCount); + sizeBox = sizeof(sBox) * count; - if (boxCount > 10) { - MakeJump(0x461493, BarBoxesSizeHack); + static bool onlyOnce = false; + if (onlyOnce) return; + + if (count > 10) { + MakeJump(0x461493, BarBoxesSizeHack); // deconstruct_box_bar_win_ + onlyOnce = true; } else { SafeWrite8(0x461495, sizeBox); } +} + +void BarBoxes::init() { + + initCount += GetConfigInt("Misc", "BoxBarCount", 5); + if (initCount < 5) initCount = 5; // exclude the influence of negative values from the config + if (initCount > 100) initCount = 100; + + actualBoxCount = initCount - 5; + + boxes = new sBox[initCount](); + boxText = new tBox[actualBoxCount](); + + memcpy(boxes, (void*)0x518FE8, sSize * 5); + for (int i = 5; i < initCount; i++) { + boxes[i].msg = 100 + i; + } + + auto boxBarColors = GetConfigString("Misc", "BoxBarColours", "", actualBoxCount + 1); + for (size_t i = 0; i < boxBarColors.size(); i++) { + if (boxBarColors[i] == '1') { + boxes[i + 5].colour = 1; // red color + boxText[i].cfgColor = 1; + } + } + + SetEngine(initCount); + SafeWrite8(0x46127C, initCount); // for only init + SafeWrite8(0x46140B, initCount); + MakeJump(0x4615A3, DisplayBoxesHack); - LoadGameHook::OnGameReset() += ResetBoxes; + totalBoxCount = boxCount = initCount; + + LoadGameHook::OnGameReset() += []() { + ResetBoxes(); + if (initCount != totalBoxCount) { + boxCount = initCount; + actualBoxCount = initCount - 5; + } + }; +} + +long BarBoxes::AddExtraBox() { + if (boxCount < totalBoxCount) { + actualBoxCount++; + boxCount++; + return MaxBox(); // just return the number of the previously added box + } + if (totalBoxCount > 126) return -1; // limit is exceeded + + void* data; + __asm { + mov eax, 2730; + call fo::funcoffs::mem_malloc_; + mov data, eax; + } + if (data == nullptr) return -1; // error on memory allocation + memcpy(data, boxes[1].mem, 2730); // copy image box to a new allocated memory + + sBox* boxes_new = new sBox[totalBoxCount + 1]; + memcpy(boxes_new, boxes, sizeof(sBox) * totalBoxCount); + delete[] boxes; + boxes = boxes_new; + + boxes[totalBoxCount].mem = data; + boxes[totalBoxCount].msg = 100; // set default text for added box + boxes[totalBoxCount].colour = 0; + boxCount = ++totalBoxCount; + + tBox* boxText_new = new tBox[actualBoxCount + 1]; + memcpy(boxText_new, boxText, sizeof(tBox) * actualBoxCount); + delete[] boxText; + boxText = boxText_new; + + memset((void*)&boxText[actualBoxCount], 0, sizeof(tBox)); + actualBoxCount++; + + SetEngine(totalBoxCount); + return MaxBox(); // current number of added box } bool BarBoxes::GetBox(int i) { if (i < 5 || i > BarBoxes::MaxBox()) return false; - return boxesEnabled[i - 5]; + return boxText[i - 5].isActive; } void BarBoxes::AddBox(int i) { if (i < 5 || i > BarBoxes::MaxBox()) return; - boxesEnabled[i - 5] = 1; - _asm call fo::funcoffs::refresh_box_bar_win_; + boxText[i - 5].isActive = true; + __asm call fo::funcoffs::refresh_box_bar_win_; } void BarBoxes::RemoveBox(int i) { if (i < 5 || i > BarBoxes::MaxBox()) return; - boxesEnabled[i - 5] = 0; - _asm call fo::funcoffs::refresh_box_bar_win_; + boxText[i - 5].isActive = false; + __asm call fo::funcoffs::refresh_box_bar_win_; } void BarBoxes::exit() { delete[] boxes; delete[] boxText; - delete[] boxesEnabled; - delete[] colorBakup; } } diff --git a/sfall/Modules/BarBoxes.h b/sfall/Modules/BarBoxes.h index b7a16cde..078f2f66 100644 --- a/sfall/Modules/BarBoxes.h +++ b/sfall/Modules/BarBoxes.h @@ -12,13 +12,13 @@ public: void init(); void exit() override; - static int MaxBox() { return boxCount - 1; } + static int MaxBox() { return boxCount - 1; } static void SetText(int box, const char* text, DWORD color); static bool GetBox(int); static void AddBox(int); static void RemoveBox(int); - + static long AddExtraBox(); }; } diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index b4d54876..d963eaff 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -303,6 +303,12 @@ end: } } +void sf_add_iface_tag(OpcodeContext &ctx) { + int result = BarBoxes::AddExtraBox(); + if (result == -1) ctx.printOpcodeError("add_iface_tag() - cannot add new tag as the maximum limit of 126 tags has been reached."); + ctx.setReturn(result); +} + void sf_show_iface_tag(OpcodeContext &ctx) { int tag = ctx.arg(0).asInt(); if (tag == 3 || tag == 4) { @@ -396,10 +402,10 @@ void sf_display_stats(OpcodeContext& ctx) { void sf_set_iface_tag_text(OpcodeContext& ctx) { int boxTag = ctx.arg(0).asInt(); - int maxBox = BarBoxes::MaxBox(); + if (boxTag > 4 && boxTag <= maxBox) { - BarBoxes::SetText(boxTag, ctx.arg(1).asString(), ctx.arg(2).asInt()); + BarBoxes::SetText(boxTag, ctx.arg(1).strValue(), ctx.arg(2).asInt()); } else { ctx.printOpcodeError("set_iface_tag_text() - tag value must be in the range of 5 to %d.", maxBox); } diff --git a/sfall/Modules/Scripting/Handlers/Interface.h b/sfall/Modules/Scripting/Handlers/Interface.h index 3b2700d1..260463c6 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.h +++ b/sfall/Modules/Scripting/Handlers/Interface.h @@ -67,6 +67,8 @@ void __declspec() op_set_viewport_x(); void __declspec() op_set_viewport_y(); +void sf_add_iface_tag(OpcodeContext&); + void sf_show_iface_tag(OpcodeContext&); void sf_hide_iface_tag(OpcodeContext&); diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index aeca9081..11fc7f8b 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -78,6 +78,7 @@ static const SfallMetarule* currentMetarule; - arg1, arg2, ... - argument types for automatic validation */ static const SfallMetarule metarules[] = { + {"add_iface_tag", sf_add_iface_tag, 0, 0}, {"art_cache_clear", sf_art_cache_flush, 0, 0}, {"attack_is_aimed", sf_attack_is_aimed, 0, 0}, {"car_gas_amount", sf_car_gas_amount, 0, 0},