BarBoxes: Set used count (#180)

* Added BarBoxesCount option to set the number of additional notification boxes to the interface.
* Expanded is_iface_tag_active function to check tag value of 0/1/2 (sneak/poisoned/radiated)
This commit is contained in:
Mr.Stalin
2018-07-21 08:47:05 +08:00
committed by NovaRain
parent 3b780110ea
commit 95f95e7b38
6 changed files with 171 additions and 174 deletions
+1
View File
@@ -12,6 +12,7 @@
#define FO_VAR_art_name 0x56C9E4 #define FO_VAR_art_name 0x56C9E4
#define FO_VAR_art_vault_guy_num 0x5108A4 #define FO_VAR_art_vault_guy_num 0x5108A4
#define FO_VAR_art_vault_person_nums 0x5108A8 #define FO_VAR_art_vault_person_nums 0x5108A8
#define FO_VAR_bboxslot 0x5970E0
#define FO_VAR_bckgnd 0x5707A4 #define FO_VAR_bckgnd 0x5707A4
#define FO_VAR_black_palette 0x663FD0 #define FO_VAR_black_palette 0x663FD0
#define FO_VAR_BlueColor 0x6A38EF #define FO_VAR_BlueColor 0x6A38EF
+110 -67
View File
@@ -29,70 +29,78 @@ static const DWORD DisplayBoxesRet1 = 0x4615A8;
static const DWORD DisplayBoxesRet2 = 0x4615BE; static const DWORD DisplayBoxesRet2 = 0x4615BE;
static const DWORD SetIndexBoxRet = 0x4612E8; static const DWORD SetIndexBoxRet = 0x4612E8;
int BarBoxes::boxCount; // total count box
static int actualBoxCount;
static int sizeBox;
#define sSize (12) #define sSize (12)
struct sBox { struct sBox {
DWORD msg; DWORD msg;
DWORD colour; DWORD colour;
void* mem; void* mem;
}; };
static sBox boxes[10];
static DWORD boxesEnabled[5];
#define tSize (28) #define tSize (25)
struct tBox { struct tBox {
DWORD hasText; bool hasText;
DWORD color; DWORD color;
char text[tSize - 8]; char text[tSize - 5];
}; };
static tBox boxText[5];
static DWORD clrBakup[5]; static sBox* boxes;
static tBox* boxText;
static bool* boxesEnabled;
static DWORD* colorBakup;
static bool setCustomBoxText; static bool setCustomBoxText;
static const DWORD bboxMemAddr[] = { static const DWORD bboxMemAddr[] = {
0x461266, 0x4612AC, 0x461374, 0x4613E8, 0x461479, 0x46148C, 0x4616BB, 0x461266, 0x4612AC, 0x461374, 0x4613E8, 0x461479, 0x46148C, 0x4616BB,
}; };
static void __declspec(naked) DisplayBoxesHook() { static void __declspec(naked) DisplayBoxesHack() {
__asm { __asm {
mov ebx, 0; mov edx, [boxesEnabled];
mov ebx, 0;
start: start:
mov eax, boxesEnabled[ebx * 4]; mov al, byte ptr [edx][ebx];
test eax, eax; test al, al;
jz next; jz next;
lea eax, [ebx + 5]; lea eax, [ebx + 5];
call fo::funcoffs::add_bar_box_; call fo::funcoffs::add_bar_box_;
add esi, eax; add esi, eax;
next: next:
inc ebx; inc ebx;
cmp ebx, 5; cmp ebx, actualBoxCount;
jne start; jne start;
cmp esi, 1; // engine code
jle fail; cmp esi, 1;
jmp DisplayBoxesRet1; jle fail;
jmp DisplayBoxesRet1;
fail: fail:
jmp DisplayBoxesRet2; jmp DisplayBoxesRet2;
} }
} }
static void __declspec(naked) BarBoxesTextHack() { static void __declspec(naked) BarBoxesTextHack() {
__asm { __asm {
//mov ecx, [esp + 0x440 - 0x1C]; push ecx; // ecx = BoxIndex
push ecx; // ecx = BoxIndex sub ecx, 5;
sub ecx, 5;
imul ecx, tSize; imul ecx, tSize;
cmp boxText[ecx], 1; // .hasText mov esi, [boxText]; // boxText addr
jnz end; cmp byte ptr [esi][ecx], 1; // .hasText
jnz end;
// get color // get color
mov ebx, boxText[ecx + 4]; // .color mov ebx, dword ptr [esi][ecx + 1]; // .color
// set text // set text
lea eax, [boxText + ecx + 8]; // .text lea eax, [esi + ecx + 5]; // .text
// set color // set color
pop ecx; pop ecx;
imul ecx, sSize; imul ecx, sSize;
cmp boxes[ecx + 4], 2; // .colour mov esi, [boxes]; // boxes addr
jb skip; cmp dword ptr [esi][ecx + 4], 2; // .colour
mov [esp + 0x440 - 0x20], ebx; // Color jb skip;
mov [esp + 0x440 - 0x20], ebx; // Color
skip: skip:
retn; retn;
end: end:
@@ -110,6 +118,18 @@ static void __declspec(naked) BarBoxesIndexHack() {
} }
} }
static const DWORD SizeLoopBoxRet = 0x461477;
static const DWORD ExitLoopBoxRet = 0x461498;
static void __declspec(naked) BarBoxesSizeHack() {
__asm {
cmp edx, sizeBox;
jz exitLoop;
jmp SizeLoopBoxRet;
exitLoop:
jmp ExitLoopBoxRet;
}
}
static void ReconstructBarBoxes() { static void ReconstructBarBoxes() {
__asm { __asm {
call fo::funcoffs::refresh_box_bar_win_; call fo::funcoffs::refresh_box_bar_win_;
@@ -119,9 +139,9 @@ static void ReconstructBarBoxes() {
} }
static void ResetBoxes() { static void ResetBoxes() {
for (int i = 0; i < 5; i++) { for (int i = 0; i < actualBoxCount; i++) {
boxesEnabled[i] = 0; boxesEnabled[i] = false;
boxes[i + 5].colour = clrBakup[i]; boxes[i + 5].colour = colorBakup[i];
} }
if (!setCustomBoxText) return; if (!setCustomBoxText) return;
@@ -138,7 +158,7 @@ static void ResetBoxes() {
void BarBoxes::SetText(int box, const char* text, DWORD color) { void BarBoxes::SetText(int box, const char* text, DWORD color) {
boxes[box].colour = color; boxes[box].colour = color;
box -= 5; box -= 5;
boxText[box].hasText = 1; boxText[box].hasText = true;
strncpy_s(boxText[box].text, text, _TRUNCATE); strncpy_s(boxText[box].text, text, _TRUNCATE);
DWORD clr; DWORD clr;
@@ -163,10 +183,10 @@ void BarBoxes::SetText(int box, const char* text, DWORD color) {
} }
boxText[box].color = clr; boxText[box].color = clr;
int enabled[5]; bool* enabled = new bool[actualBoxCount];
for (int i = 0; i < 5; i++) { for (int i = 0; i < actualBoxCount; i++) {
enabled[i] = boxesEnabled[i]; enabled[i] = boxesEnabled[i];
boxesEnabled[i] = 0; boxesEnabled[i] = false;
} }
if (!setCustomBoxText) { if (!setCustomBoxText) {
@@ -177,59 +197,82 @@ void BarBoxes::SetText(int box, const char* text, DWORD color) {
ReconstructBarBoxes(); ReconstructBarBoxes();
for (int i = 0; i < 5; i++) { for (int i = 0; i < actualBoxCount; i++) {
boxesEnabled[i] = enabled[i]; boxesEnabled[i] = enabled[i];
} }
delete[] enabled;
__asm call fo::funcoffs::refresh_box_bar_win_; __asm call fo::funcoffs::refresh_box_bar_win_;
} }
void BarBoxes::init() { void BarBoxes::init() {
SafeWriteBatch<DWORD>((DWORD)boxes + 8, bboxMemAddr); //.mem
SafeWrite32(0x4612FE, (DWORD)boxes + 4); //.colour
SafeWrite32(0x46133C, (DWORD)boxes); //.msg
int size = sSize * 10; boxCount = 5 + GetConfigInt("Misc", "BoxBarCount", 5);
memset(boxes, 0, size); if (boxCount < 10) boxCount = 10;
memset(boxesEnabled, 0, 5 * 4); 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); memcpy(boxes, (void*)0x518FE8, sSize * 5);
for (int i = 5; i < 10; i++) { for (int i = 5; i < boxCount; i++) {
boxes[i].msg = 100 + i; boxes[i].msg = 100 + i;
} }
SafeWrite8(0x46127C, 10); auto boxBarColors = GetConfigString("Misc", "BoxBarColours", "", actualBoxCount + 1);
SafeWrite8(0x46140B, 10); int size = boxBarColors.size();
SafeWrite8(0x461495, size); for (int i = 0; i < size; i++) {
if (boxBarColors[i] == '1') {
MakeJump(0x4615A3, DisplayBoxesHook); boxes[i + 5].colour = 1;
auto boxBarColors = GetConfigString("Misc", "BoxBarColours", "", 6); colorBakup[i] = 1;
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;
}
} }
} }
SafeWriteBatch<DWORD>((DWORD)boxes + 8, bboxMemAddr); //.mem
SafeWrite32(0x4612FE, (DWORD)boxes + 4); //.colour
SafeWrite32(0x46133C, (DWORD)boxes); //.msg
SafeWrite8(0x46127C, boxCount);
SafeWrite8(0x46140B, boxCount);
if (boxCount > 10) {
MakeJump(0x461493, BarBoxesSizeHack);
} else {
SafeWrite8(0x461495, sizeBox);
}
MakeJump(0x4615A3, DisplayBoxesHack);
LoadGameHook::OnGameReset() += ResetBoxes; LoadGameHook::OnGameReset() += ResetBoxes;
} }
int _stdcall GetBox(int i) { bool BarBoxes::GetBox(int i) {
if (i < 5 || i > 9) return 0; if (i < 5 || i > BarBoxes::MaxBox()) return false;
return boxesEnabled[i - 5]; return boxesEnabled[i - 5];
} }
void _stdcall AddBox(int i) { void BarBoxes::AddBox(int i) {
if (i < 5 || i > 9) return; if (i < 5 || i > BarBoxes::MaxBox()) return;
boxesEnabled[i - 5] = 1; boxesEnabled[i - 5] = 1;
_asm call fo::funcoffs::refresh_box_bar_win_;
} }
void _stdcall RemoveBox(int i) { void BarBoxes::RemoveBox(int i) {
if (i < 5 || i > 9) return; if (i < 5 || i > BarBoxes::MaxBox()) return;
boxesEnabled[i - 5] = 0; boxesEnabled[i - 5] = 0;
_asm call fo::funcoffs::refresh_box_bar_win_;
}
void BarBoxes::exit() {
delete[] boxes;
delete[] boxText;
delete[] boxesEnabled;
delete[] colorBakup;
} }
} }
+10 -4
View File
@@ -4,15 +4,21 @@ namespace sfall
{ {
class BarBoxes : public Module { class BarBoxes : public Module {
private:
static int boxCount;
public: public:
const char* name() { return "BarBoxes"; } const char* name() { return "BarBoxes"; }
void init(); void init();
void exit() override;
static int MaxBox() { return boxCount - 1; }
static void SetText(int box, const char* text, DWORD color); static void SetText(int box, const char* text, DWORD color);
static bool GetBox(int);
static void AddBox(int);
static void RemoveBox(int);
}; };
int _stdcall GetBox(int i);
void _stdcall AddBox(int i);
void _stdcall RemoveBox(int i);
} }
+44 -97
View File
@@ -305,104 +305,50 @@ end:
} }
} }
void __declspec(naked) op_show_iface_tag() { void sf_show_iface_tag(OpcodeContext &ctx) {
__asm { int tag = ctx.arg(0).asInt();
pushad; if (tag == 3 || tag == 4) {
mov ecx, eax; _asm mov eax, tag;
call fo::funcoffs::interpretPopShort_; _asm call fo::funcoffs::pc_flag_on_;
mov edx, eax; } else {
mov eax, ecx; BarBoxes::AddBox(tag);
call fo::funcoffs::interpretPopLong_;
cmp dx, VAR_TYPE_INT;
jnz end;
cmp eax, 3;
je falloutfunc;
cmp eax, 4;
je falloutfunc;
push eax;
call AddBox;
call fo::funcoffs::refresh_box_bar_win_;
jmp end;
falloutfunc:
call fo::funcoffs::pc_flag_on_;
end:
popad;
retn;
} }
} }
void __declspec(naked) op_hide_iface_tag() { void sf_hide_iface_tag(OpcodeContext &ctx) {
__asm { int tag = ctx.arg(0).asInt();
pushad; if (tag == 3 || tag == 4) {
mov ecx, eax; _asm mov eax, tag;
call fo::funcoffs::interpretPopShort_; _asm call fo::funcoffs::pc_flag_off_;
mov edx, eax; } else {
mov eax, ecx; BarBoxes::RemoveBox(tag);
call fo::funcoffs::interpretPopLong_;
cmp dx, VAR_TYPE_INT;
jnz end;
cmp eax, 3;
je falloutfunc;
cmp eax, 4;
je falloutfunc;
push eax;
call RemoveBox;
call fo::funcoffs::refresh_box_bar_win_;
jmp end;
falloutfunc:
call fo::funcoffs::pc_flag_off_;
end:
popad;
retn;
} }
} }
void __declspec(naked) op_is_iface_tag_active() { void sf_is_iface_tag_active(OpcodeContext &ctx) {
__asm { bool result = false;
pushad; int tag = ctx.arg(0).asInt();
sub esp, 4; if (tag >= 0 && tag < 5) {
mov ebx, eax; if (tag == 1 || tag == 2) { // Poison/Radiation
call fo::funcoffs::interpretPopShort_; tag += 2;
mov edx, eax; int* boxslot = (int*)FO_VAR_bboxslot;
mov eax, ebx; for (int i = 0; i < 6; i++) {
call fo::funcoffs::interpretPopLong_; int value = boxslot[i];
cmp dx, VAR_TYPE_INT; if (value == tag || value == -1) {
jnz fail; result = (value != -1);
cmp eax, 3; break;
je falloutfunc; }
cmp eax, 4; }
je falloutfunc; } else { // Sneak/Level/Addict
push eax; fo::GameObject* obj = fo::var::obj_dude;
call GetBox; fo::Proto* proto = fo::GetProto(obj->protoId);
mov edx, eax; int flagBit = 1 << tag;
jmp end; result = ((proto->critter.critterFlags & flagBit) != 0);
falloutfunc: }
mov ecx, eax; } else {
mov eax, dword ptr ds:[FO_VAR_obj_dude]; result = BarBoxes::GetBox(tag);
mov edx, esp;
mov eax, [eax + 0x64];
call fo::funcoffs::proto_ptr_;
mov edx, 1;
shl edx, cl;
mov ecx, [esp];
mov eax, [ecx + 0x20];
and eax, edx;
jz fail;
xor edx, edx;
inc edx;
jmp end;
fail:
xor edx, edx;
end:
mov eax, ebx;
call fo::funcoffs::interpretPushLong_;
mov eax, ebx;
mov edx, VAR_TYPE_INT;
call fo::funcoffs::interpretPushShort_;
add esp, 4;
popad;
retn;
} }
ctx.setReturn(result);
} }
void sf_intface_redraw(OpcodeContext& ctx) { void sf_intface_redraw(OpcodeContext& ctx) {
@@ -410,17 +356,17 @@ void sf_intface_redraw(OpcodeContext& ctx) {
} }
void sf_intface_show(OpcodeContext& ctx) { void sf_intface_show(OpcodeContext& ctx) {
__asm call fo::funcoffs::intface_show_ __asm call fo::funcoffs::intface_show_;
} }
void sf_intface_hide(OpcodeContext& ctx) { void sf_intface_hide(OpcodeContext& ctx) {
__asm call fo::funcoffs::intface_hide_ __asm call fo::funcoffs::intface_hide_;
} }
void sf_intface_is_hidden(OpcodeContext& ctx) { void sf_intface_is_hidden(OpcodeContext& ctx) {
int isHidden; int isHidden;
__asm { __asm {
call fo::funcoffs::intface_is_hidden_ call fo::funcoffs::intface_is_hidden_;
mov isHidden, eax; mov isHidden, eax;
} }
ctx.setReturn(isHidden); ctx.setReturn(isHidden);
@@ -433,7 +379,7 @@ void sf_tile_refresh_display(OpcodeContext& ctx) {
void sf_get_cursor_mode(OpcodeContext& ctx) { void sf_get_cursor_mode(OpcodeContext& ctx) {
int cursorMode; int cursorMode;
__asm { __asm {
call fo::funcoffs::gmouse_3d_get_mode_ call fo::funcoffs::gmouse_3d_get_mode_;
mov cursorMode, eax; mov cursorMode, eax;
} }
ctx.setReturn(cursorMode); ctx.setReturn(cursorMode);
@@ -453,10 +399,11 @@ void sf_display_stats(OpcodeContext& ctx) {
void sf_set_iface_tag_text(OpcodeContext& ctx) { void sf_set_iface_tag_text(OpcodeContext& ctx) {
int boxTag = ctx.arg(0).asInt(); int boxTag = ctx.arg(0).asInt();
if (boxTag > 4 && boxTag < 10) { 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).asString(), ctx.arg(2).asInt());
} else { } else {
ctx.printOpcodeError("set_iface_tag_text() - tag value must be in the range of 5 to 9."); ctx.printOpcodeError("set_iface_tag_text() - tag value must be in the range of 5 to %d.", maxBox);
} }
} }
+3 -3
View File
@@ -67,11 +67,11 @@ void __declspec() op_set_viewport_x();
void __declspec() op_set_viewport_y(); void __declspec() op_set_viewport_y();
void __declspec() op_show_iface_tag(); void sf_show_iface_tag(OpcodeContext&);
void __declspec() op_hide_iface_tag(); void sf_hide_iface_tag(OpcodeContext&);
void __declspec() op_is_iface_tag_active(); void sf_is_iface_tag_active(OpcodeContext&);
void sf_intface_redraw(OpcodeContext&); void sf_intface_redraw(OpcodeContext&);
+3 -3
View File
@@ -64,6 +64,9 @@ typedef std::unordered_map<int, const SfallOpcodeInfo*> OpcodeInfoMapType;
// } // }
static SfallOpcodeInfo opcodeInfoArray[] = { static SfallOpcodeInfo opcodeInfoArray[] = {
{0x16c, "key_pressed", sf_key_pressed, 1, true}, {0x16c, "key_pressed", sf_key_pressed, 1, true},
{0x1dc, "show_iface_tag", sf_show_iface_tag, 1, false, {ARG_INT}},
{0x1dd, "hide_iface_tag", sf_hide_iface_tag, 1, false, {ARG_INT}},
{0x1de, "is_iface_tag_active", sf_is_iface_tag_active, 1, true, {ARG_INT}},
{0x1ec, "sqrt", sf_sqrt, 1, true, {ARG_NUMBER}}, {0x1ec, "sqrt", sf_sqrt, 1, true, {ARG_NUMBER}},
{0x1ed, "abs", sf_abs, 1, true, {ARG_NUMBER}}, {0x1ed, "abs", sf_abs, 1, true, {ARG_NUMBER}},
{0x1ee, "sin", sf_sin, 1, true, {ARG_NUMBER}}, {0x1ee, "sin", sf_sin, 1, true, {ARG_NUMBER}},
@@ -326,9 +329,6 @@ void InitNewOpcodes() {
opcodes[i] = op_call_offset; opcodes[i] = op_call_offset;
} }
} }
opcodes[0x1dc] = op_show_iface_tag;
opcodes[0x1dd] = op_hide_iface_tag;
opcodes[0x1de] = op_is_iface_tag_active;
opcodes[0x1df] = op_get_bodypart_hit_modifier; opcodes[0x1df] = op_get_bodypart_hit_modifier;
opcodes[0x1e0] = op_set_bodypart_hit_modifier; opcodes[0x1e0] = op_set_bodypart_hit_modifier;
opcodes[0x1e1] = op_set_critical_table; opcodes[0x1e1] = op_set_critical_table;