Refactored BonusHtHDamageFix/DisplayBonusDamage code in AmmoMod.cpp (from Mr.Stalin)

Fixed DisplayBonusDamage not being applied on Melee Damage stat in the character screen when BonusHtHDamageFix is enabled.
Reimplemented INTFACEUSE/INTFACELOOT/BARTER game mode flags, and backported inventory_redraw script function from 4.0.
This commit is contained in:
NovaRain
2018-10-11 11:19:22 +08:00
parent 25554ff0b2
commit e1aefcc1ed
14 changed files with 215 additions and 175 deletions
+19 -15
View File
@@ -1,19 +1,22 @@
//Recognised modes for set_shader_mode and get_game_mode
#define WORLDMAP (0x1)
#define LOCALMAP (0x2) //No point hooking this: would always be 1 at any point at which scripts are running
#define DIALOG (0x4)
#define ESCMENU (0x8)
#define SAVEGAME (0x10)
#define LOADGAME (0x20)
#define COMBAT (0x40)
#define OPTIONS (0x80)
#define HELP (0x100)
#define CHARSCREEN (0x200)
#define PIPBOY (0x400)
#define PCOMBAT (0x800)
#define INVENTORY (0x1000)
#define AUTOMAP (0x2000)
#define SKILLDEX (0x4000)
#define WORLDMAP (0x1)
#define LOCALMAP (0x2) //No point hooking this: would always be 1 at any point at which scripts are running
#define DIALOG (0x4)
#define ESCMENU (0x8)
#define SAVEGAME (0x10)
#define LOADGAME (0x20)
#define COMBAT (0x40)
#define OPTIONS (0x80)
#define HELP (0x100)
#define CHARSCREEN (0x200)
#define PIPBOY (0x400)
#define PCOMBAT (0x800)
#define INVENTORY (0x1000)
#define AUTOMAP (0x2000)
#define SKILLDEX (0x4000)
#define INTFACEUSE (0x8000)
#define INTFACELOOT (0x10000)
#define BARTER (0x20000)
//Valid arguments to register_hook
#define HOOK_TOHIT (0)
@@ -218,6 +221,7 @@
#define intface_is_hidden sfall_func0("intface_is_hidden")
#define intface_redraw sfall_func0("intface_redraw")
#define intface_show sfall_func0("intface_show")
#define inventory_redraw(invSide) sfall_func1("inventory_redraw", invSide)
#define item_weight(obj) sfall_func1("item_weight", obj)
#define outlined_object sfall_func0("outlined_object")
#define set_cursor_mode(mode) sfall_func1("set_cursor_mode", mode)
@@ -433,6 +433,10 @@ 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_func1("inventory_redraw", int invSide)
- redraws inventory list in the inventory/use inventory item on/loot/barter screens
- invSide specifies which side needs to be redrawn: 0 - the player, 1 - target (container/NPC in loot/barter screens)
> int sfall_func1("get_current_inven_size", object)
- returns the current inventory size of the container or the critter
+60 -110
View File
@@ -502,119 +502,69 @@ end:
jmp DamageFunctionReturn; // Otherwise, exit loop
}
}
////////////////////////////////////////////////////////////////////////////////
static const DWORD MeleeDmgDispExit = 0x435C11;
static const DWORD MeleeDmgPrintExit = 0x439926;
static const DWORD MeleeExit = 0x47226D;
static const DWORD UnarmedExit = 0x472556;
static const DWORD FixaEnd = 0x4784B0;
static const DWORD FixbEnd = 0x478553;
static __declspec(naked) void MeleeDmgDispFix() {
static __declspec(naked) void MeleeDmgDisplayPrintFix_hook() {
__asm {
call stat_level_; // Get Melee Damage
mov ecx,eax; // Store value
mov eax,dword ptr ds:[_obj_dude]; // Get pointer to PC
mov edx,PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
call perk_level_; // Get rank of Bonus HtH Damage
shl eax,0x1; // Multiply by 2
sub ecx,eax; // Subtract from Melee Damage
mov eax,ecx; // Move back to eax in preparation of push
jmp MeleeDmgDispExit;
call stat_level_; // Get Melee Damage
mov ecx, eax; // Store value
mov edx, PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
mov eax, dword ptr ds:[_obj_dude]; // Get pointer to PC
call perk_level_; // Get rank of Bonus HtH Damage
shl eax, 1; // Multiply by 2
sub ecx, eax; // Subtract from Melee Damage
mov eax, ecx; // Move back to eax in preparation of push
retn;
}
}
static __declspec(naked) void MeleeDmgPrintFix() {
static __declspec(naked) void CommonDmgRngDispFix_hook() {
__asm {
call stat_level_; // Get Melee Damage
mov ebx,eax; // Store value
mov eax,dword ptr ds:[_obj_dude]; // Get pointer to PC
mov edx,PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
call perk_level_; // Get rank of Bonus HtH Damage
shl eax,0x1; // Multiply by 2
sub ebx,eax; // Subtract from Melee Damage
mov eax,ebx; // Move back to eax in preparation of push
mov ebx,0x27a; // Facilitates printing to file
jmp MeleeDmgPrintExit;
mov ebx, eax; // Store pointer to critter
call stat_level_; // Get Melee Damage
xchg ebx, eax; // Store Melee Damage value
mov edx, PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
call perk_level_; // Get rank of Bonus HtH Damage
shl eax, 1; // Multiply by 2
sub ebx, eax; // Subtract from Melee Damage
mov eax, ebx; // Move back to eax in preparation of push
retn;
}
}
static __declspec(naked) void MeleeWeapDmgRngDispFix() {
static __declspec(naked) void HtHDamageFix1a_hack() {
__asm {
call stat_level_; // Get Melee Damage
mov ebx,eax; // Store Melee Damage value
mov edx,dword ptr ds:[_stack]; // Get pointer to critter
mov eax,dword ptr ds:[_obj_dude]; // Get pointer to PC
cmp eax,edx; // Is PC == critter?
jnz end; // exit if no
mov edx,PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
call perk_level_; // Otherwise, get rank of Bonus HtH Damage
shl eax,0x1; // Multiply by 2
sub ebx,eax; // Subtract from Melee Damage
xor edx, edx;
cmp ecx, dword ptr ds:[_obj_dude]; // Is the critter == PC?
jnz skip; // Skip if no
mov edx, PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
mov eax, ecx; // pointer to PC
call perk_level_; // Return Rank_of_Bonus_HtH_Damage_perk
shl eax, 1; // Rank_of_Bonus_HtH_Damage_perk *= 2
mov edx, eax; // Min_Damage = Rank_of_Bonus_HtH_Damage_perk
skip:
add edx, 1; // Min_Damage += 1
retn;
}
}
static __declspec(naked) void HtHDamageFix1b_hook() {
__asm {
call stat_level_; // Get Total_Melee_Damage
cmp ecx, dword ptr ds:[_obj_dude]; // Is the critter == PC?
jnz end; // Skip to exit if no
push eax;
mov edx, PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
mov eax, ecx; // pointer to PC
call perk_level_; // Return Rank_of_Bonus_HtH_Damage_perk
shl eax, 1; // Rank_of_Bonus_HtH_Damage_perk *= 2
add dword ptr [esp + 0x24 - 0x20 + 8], eax; // Min_Damage += Rank_of_Bonus_HtH_Damage_perk
pop eax;
end:
jmp MeleeExit;
retn;
}
}
static __declspec(naked) void UnarmedDmgRngDispFix() {
__asm {
mov ebx,eax; // Store Melee Damage value
mov edx,dword ptr ds:[_stack]; // Get pointer to critter
mov eax,dword ptr ds:[_obj_dude]; // Get pointer to PC
cmp eax,edx; // Is PC == critter?
jnz end; // exit if no
mov edx,PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
call perk_level_; // Otherwise, get rank of Bonus HtH Damage
shl eax,0x1; // Multiply by 2
sub ebx,eax; // Subtract to Melee Damage
end:
mov eax,ebx; // Move back to eax in prepartion of push
add eax,0x2; // Add 2 (max unarmed damage value)
push eax; // push to print string
mov eax,dword ptr ss:[esp+0x98];
jmp UnarmedExit;
}
}
static __declspec(naked) void HtHDamageFix1a() {
__asm {
mov eax,ecx; // stat_level_ argument: pointer to critter
mov edx,STAT_melee_dmg; // stat_level_ argument: STAT_melee_dmg
call stat_level_; // Get Total_Melee_Damage
add eax,2; // Total_Melee_Damage += 2
mov dword ptr ss:[esp],eax; // Max_Damage = Total_Melee_Damage
xor edx,edx;
mov eax,dword ptr ds:[_obj_dude]; // Get pointer to PC
cmp ecx,eax; // Is the critter == PC?
jnz ajmp; // Skip to ajmp if no
mov edx,PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
call perk_level_; // Return Rank_of_Bonus_HtH_Damage_perk
shl eax,0x1; // Rank_of_Bonus_HtH_Damage_perk *= 2
mov edx, eax; // Min_Damage = Rank_of_Bonus_HtH_Damage_perk
ajmp:
add edx,1; // Min_Damage += 1
mov dword ptr ss:[esp+0x4],edx; // Store Min_Damage
sub esi,0x8; // Set up for switch statement beyond jump
jmp FixaEnd;
}
}
static __declspec(naked) void HtHDamageFix1b() {
__asm {
call stat_level_; // Get Total_Melee_Damage
mov ebp, eax;
mov eax, dword ptr ds:[_obj_dude]; // Get pointer to PC
cmp ecx, eax; // Is the critter == PC?
jnz end; // Skip to exit if no
mov edx, PERK_bonus_hth_damage; // perk_level_ argument: PERK_bonus_hth_damage
call perk_level_; // Return Rank_of_Bonus_HtH_Damage_perk
shl eax, 0x1; // Rank_of_Bonus_HtH_Damage_perk *= 2
add dword ptr ss:[esp+0x4], eax; // Min_Damage += Rank_of_Bonus_HtH_Damage_perk
end:
jmp FixbEnd;
}
}
static void __declspec(naked) DisplayBonusRangedDmg_hook() {
__asm {
mov edx, PERK_bonus_ranged_damage;
@@ -633,7 +583,7 @@ static void __declspec(naked) DisplayBonusHtHDmg1_hook() {
mov eax, dword ptr ds:[_stack];
call perk_level_;
shl eax, 1;
add dword ptr [esp + 4 * 4], eax; // min_dmg + bonus
add dword ptr [esp + 4 * 4], eax; // min_dmg + perk bonus
jmp sprintf_;
}
}
@@ -688,23 +638,23 @@ void AmmoModInit() {
int DisplayBonusDmg = GetPrivateProfileIntA("Misc", "DisplayBonusDamage", 0, ini);
if (BonusHtHDmgFix) {
dlog("Applying Bonus HtH Damage Perk fix.", DL_INIT);
MakeJump(0x435C0C, MeleeDmgDispFix);
MakeJump(0x43991C, MeleeDmgPrintFix);
if (!DisplayBonusDmg) {
MakeJump(0x472266, MeleeWeapDmgRngDispFix);
MakeJump(0x47254B, UnarmedDmgRngDispFix);
if (!DisplayBonusDmg) { // Subtract damage from perk bonus (vanilla displaying)
HookCall(0x435C0C, MeleeDmgDisplayPrintFix_hook); // DisplayFix (ListDrvdStats_)
HookCall(0x439921, MeleeDmgDisplayPrintFix_hook); // PrintFix (Save_as_ASCII_)
HookCall(0x472266, CommonDmgRngDispFix_hook); // MeleeWeap (display_stats_)
HookCall(0x472546, CommonDmgRngDispFix_hook); // Unarmed (display_stats_)
}
MakeJump(0x478492, HtHDamageFix1a);
MakeJump(0x47854C, HtHDamageFix1b);
MakeCall(0x478492, HtHDamageFix1a_hack); // Unarmed (item_w_damage_)
HookCall(0x47854C, HtHDamageFix1b_hook); // MeleeWeap (item_w_damage_)
dlogr(" Done", DL_INIT);
}
if (DisplayBonusDmg) {
dlog("Applying Display Bonus Damage patch.", DL_INIT);
HookCall(0x4722DD, DisplayBonusRangedDmg_hook);
HookCall(0x4722DD, DisplayBonusRangedDmg_hook); // display_stats_
if (BonusHtHDmgFix) {
HookCall(0x472309, DisplayBonusHtHDmg1_hook);
MakeJump(0x472546, DisplayBonusHtHDmg2_hack);
HookCall(0x472309, DisplayBonusHtHDmg1_hook); // display_stats_
MakeJump(0x472546, DisplayBonusHtHDmg2_hack); // display_stats_
}
dlogr(" Done", DL_INIT);
}
+4 -4
View File
@@ -181,6 +181,8 @@ static DWORD __fastcall CheckSetSad(BYTE openFlag, DWORD valueMul) {
return result;
}
static const DWORD object_move_back0 = 0x417611;
static const DWORD object_move_back1 = 0x417616;
static void __declspec(naked) object_move_hack() {
__asm {
mov ecx, ds:[ecx + 0x3C]; // openFlag
@@ -188,11 +190,9 @@ static void __declspec(naked) object_move_hack() {
call CheckSetSad;
test eax, eax;
jz end;
push 0x417611; // fixed jump
retn;
jmp object_move_back0; // fixed jump
end:
push 0x417616; // default
retn;
jmp object_move_back1; // default
}
}
-22
View File
@@ -590,23 +590,6 @@ skip:
}
}
// simple hooks from 4.x LoadGameHook.cpp without new game mode flags
static void __declspec(naked) LootContainerWrapper() {
__asm {
call loot_container_;
jmp ResetBodyState;
}
}
static void __declspec(naked) BarterInventoryWrapper() {
__asm {
push [esp + 4];
call barter_inventory_;
call ResetBodyState;
retn 4;
}
}
static void __declspec(naked) inven_pickup_hack() {
__asm {
mov edx, ds:[_pud]
@@ -1561,11 +1544,6 @@ void BugsInit()
SafeWrite8(0x477EB0, 0x90);
MakeCall(0x479A2F, item_c_curr_size_hack);
SafeWrite8(0x479A34, 0x90);
// Reset object pointer after exiting loot/barter screens
HookCall(0x4746EC, LootContainerWrapper);
HookCall(0x4A4369, LootContainerWrapper);
HookCall(0x4A4565, LootContainerWrapper);
HookCall(0x4466C7, BarterInventoryWrapper);
dlogr(" Done", DL_INIT);
//}
+27
View File
@@ -614,6 +614,7 @@ const DWORD trait_get_ = 0x4B3B54;
const DWORD trait_init_ = 0x4B39F0;
const DWORD trait_level_ = 0x4B3BC8;
const DWORD trait_set_ = 0x4B3B48;
const DWORD use_inventory_on_ = 0x4717E4;
const DWORD _word_wrap_ = 0x4BC6F0;
const DWORD win_add_ = 0x4D6238;
const DWORD win_delete_ = 0x4D6468;
@@ -906,3 +907,29 @@ long __fastcall WordWrap(const char* text, int maxWidth, DWORD* buf, BYTE* count
call _word_wrap_
}
}
void __stdcall RedrawWin(DWORD winRef) {
__asm {
mov eax, winRef
call win_draw_
}
}
void __stdcall DisplayInventory(long inventoryOffset, long visibleOffset, long mode) {
__asm {
mov ebx, mode
mov edx, visibleOffset
mov eax, inventoryOffset
call display_inventory_
}
}
void __stdcall DisplayTargetInventory(long inventoryOffset, long visibleOffset, DWORD* targetInventory, long mode) {
__asm {
mov ecx, mode
mov ebx, targetInventory
mov edx, visibleOffset
mov eax, inventoryOffset
call display_target_inventory_
}
}
+7
View File
@@ -810,6 +810,7 @@ extern const DWORD trait_get_;
extern const DWORD trait_init_;
extern const DWORD trait_level_;
extern const DWORD trait_set_;
extern const DWORD use_inventory_on_;
extern const DWORD _word_wrap_;
extern const DWORD win_add_;
extern const DWORD win_delete_;
@@ -975,3 +976,9 @@ long __stdcall CreateWindowFunc(const char* winName, long x, long y, long width,
long __stdcall WinRegisterButton(DWORD winRef, long xPos, long yPos, long width, long height, long hoverOn, long hoverOff, long buttonDown, long buttonUp, BYTE* pictureUp, BYTE* pictureDown, long arg12, long buttonType);
long __fastcall WordWrap(const char* text, int maxWidth, DWORD* buf, BYTE* count);
void __stdcall RedrawWin(DWORD winRef);
void __stdcall DisplayInventory(long inventoryOffset, long visibleOffset, long mode);
void __stdcall DisplayTargetInventory(long inventoryOffset, long visibleOffset, DWORD* targetInventory, long mode);
-7
View File
@@ -577,13 +577,6 @@ void HideWin(int WinRef) {
}
}
*/
//-----------------------------------------------------------------------------------------------------------------------
void RedrawWin(int WinRef) {
__asm {
mov eax, WinRef
call win_draw_
}
}
/////////////////////////////////////////////////////////////////BUTTON FUNCTIONS////////////////////////////////////////////////////////////////////////
-1
View File
@@ -37,7 +37,6 @@ typedef struct WINinfo {
} WINinfo;
WINinfo *GetWinStruct(int WinRef);
void RedrawWin(int WinRef);
void PrintText(char *DisplayText, BYTE ColourIndex, DWORD Xpos, DWORD Ypos, DWORD TxtWidth, DWORD ToWidth, BYTE *ToSurface);
DWORD GetTextWidth(char *TextMsg);
DWORD GetMaxCharWidth();
+35
View File
@@ -451,6 +451,36 @@ static void __declspec(naked) HandleInventoryHook() {
}
}
static void __declspec(naked) UseInventoryOnHook() {
__asm {
or InLoop, INTFACEUSE;
call use_inventory_on_;
and InLoop, (-1 ^ INTFACEUSE);
retn;
}
}
static void __declspec(naked) LootContainerHook() {
__asm {
or InLoop, INTFACELOOT;
call loot_container_;
and InLoop, (-1 ^ INTFACELOOT);
jmp ResetBodyState; // reset object pointer used in calculating the weight/size of equipped and hidden items on NPCs after exiting loot/barter screens
//retn;
}
}
static void __declspec(naked) BarterInventoryHook() {
__asm {
or InLoop, BARTER;
push [esp + 4];
call barter_inventory_;
and InLoop, (-1 ^ BARTER);
call ResetBodyState;
retn 4;
}
}
static void __declspec(naked) AutomapHook() {
__asm {
or InLoop, AUTOMAP;
@@ -526,6 +556,11 @@ void LoadGameHookInit() {
HookCall(0x4434AC, SkilldexHook);
HookCall(0x44C7BD, SkilldexHook);
HookCall(0x443357, HandleInventoryHook);
HookCall(0x44C6FB, UseInventoryOnHook);
HookCall(0x4746EC, LootContainerHook);
HookCall(0x4A4369, LootContainerHook);
HookCall(0x4A4565, LootContainerHook);
HookCall(0x4466C7, BarterInventoryHook);
HookCall(0x44396D, AutomapHook);
HookCall(0x479519, AutomapHook);
}
+19 -16
View File
@@ -24,21 +24,24 @@ bool IsMapLoaded();
DWORD InWorldMap();
DWORD InCombat();
#define WORLDMAP (1<<0) // 0x1
#define LOCALMAP (1<<1) // 0x2 No point hooking this: would always be 1 at any point at which scripts are running
#define DIALOG (1<<2) // 0x4
#define ESCMENU (1<<3) // 0x8
#define SAVEGAME (1<<4) // 0x10
#define LOADGAME (1<<5) // 0x20
#define COMBAT (1<<6) // 0x40
#define OPTIONS (1<<7) // 0x80
#define HELP (1<<8) // 0x100
#define CHARSCREEN (1<<9) // 0x200
#define PIPBOY (1<<10) // 0x400
#define PCOMBAT (1<<11) // 0x800
#define INVENTORY (1<<12) // 0x1000
#define AUTOMAP (1<<13) // 0x2000
#define SKILLDEX (1<<14) // 0x4000
#define RESERVED (1<<31)
#define WORLDMAP (1<<0) // 0x1
#define LOCALMAP (1<<1) // 0x2 No point hooking this: would always be 1 at any point at which scripts are running
#define DIALOG (1<<2) // 0x4
#define ESCMENU (1<<3) // 0x8
#define SAVEGAME (1<<4) // 0x10
#define LOADGAME (1<<5) // 0x20
#define COMBAT (1<<6) // 0x40
#define OPTIONS (1<<7) // 0x80
#define HELP (1<<8) // 0x100
#define CHARSCREEN (1<<9) // 0x200
#define PIPBOY (1<<10) // 0x400
#define PCOMBAT (1<<11) // 0x800
#define INVENTORY (1<<12) // 0x1000
#define AUTOMAP (1<<13) // 0x2000
#define SKILLDEX (1<<14) // 0x4000
#define INTFACEUSE (1<<15) // 0x8000
#define INTFACELOOT (1<<16) // 0x10000
#define BARTER (1<<17) // 0x20000
#define RESERVED (1<<31)
DWORD GetCurrentLoops();
+12
View File
@@ -125,6 +125,17 @@ public:
}
}
bool asBool() const {
switch (_type) {
case DATATYPE_FLOAT:
return static_cast<int>(_val.f) != 0;
case DATATYPE_INT:
return _val.i != 0;
default:
return true;
}
}
float asFloat() const {
switch (_type) {
case DATATYPE_FLOAT:
@@ -376,6 +387,7 @@ static const SfallOpcodeMetadata opcodeMetaArray[] = {
{sf_get_current_inven_size, "get_current_inven_size", {DATATYPE_MASK_VALID_OBJ}},
{sf_get_flags, "get_flags", {DATATYPE_MASK_VALID_OBJ}},
{sf_get_outline, "get_outline", {DATATYPE_MASK_VALID_OBJ}},
{sf_inventory_redraw, "inventory_redraw", {DATATYPE_MASK_INT}},
{sf_item_weight, "item_weight", {DATATYPE_MASK_VALID_OBJ}},
{sf_set_cursor_mode, "set_cursor_mode", {DATATYPE_MASK_INT}},
{sf_set_flags, "set_flags", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}},
+27
View File
@@ -497,6 +497,33 @@ static void sf_display_stats() {
}
}
static void sf_inventory_redraw() {
int mode = -1;
DWORD loopFlag = GetCurrentLoops();
if (loopFlag & INVENTORY) {
mode = 0;
} else if (loopFlag & INTFACEUSE) {
mode = 1;
} else if (loopFlag & INTFACELOOT) {
mode = 2;
} else if (loopFlag & BARTER) {
mode = 3;
} else {
return;
}
if (!opHandler.arg(0).asBool()) {
int* stack_offset = (int*)_stack_offset;
stack_offset[*ptr_curr_stack * 4] = 0;
DisplayInventory(0, -1, mode);
} else if (mode >= 2) {
int* target_stack_offset = (int*)_target_stack_offset;
target_stack_offset[*ptr_target_curr_stack * 4] = 0;
DisplayTargetInventory(0, -1, (DWORD*)*ptr_target_pud, mode);
RedrawWin(*ptr_i_wid);
}
}
static void sf_create_win() {
int flags;
if (opHandler.numArgs() == 6) {
+1
View File
@@ -119,6 +119,7 @@ static const SfallMetarule metaruleArray[] = {
{"intface_is_hidden", sf_intface_is_hidden, 0, 0},
{"intface_redraw", sf_intface_redraw, 0, 0},
{"intface_show", sf_intface_show, 0, 0},
{"inventory_redraw", sf_inventory_redraw, 1, 1},
{"item_weight", sf_item_weight, 1, 1},
{"outlined_object", sf_outlined_object, 0, 0},
{"set_cursor_mode", sf_set_cursor_mode, 1, 1},