diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 6114f980..7af34260 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 9ebda0e4..0f96d09a 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 3f9b7cca..4f44dd7a 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 fe41348b..281ceb79 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 24cd5b92..aa6dbd91 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 @@ fail: } } +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); + 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 - SafeWrite32(0x461479, (DWORD)boxes + 8); - SafeWrite32(0x46148C, (DWORD)boxes + 8); - SafeWrite32(0x4616BB, (DWORD)boxes + 8); - - memset(boxes, 0, 12 * 10); + 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 5d7b2ed9..e73d7aab 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 f41d5de4..aa8506a6 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 69ce8d1c..1b7b6577 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 e3ab6ad4..94c7a453 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}},