mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added the display of actual damage for unarmed attacks in inven
This commit is contained in:
+39
-23
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "FalloutEngine.h"
|
||||
#include "Logging.h"
|
||||
#include "Unarmed.h"
|
||||
|
||||
#include "ReplacementFuncs.h"
|
||||
|
||||
@@ -422,24 +423,37 @@ static void __declspec(naked) DisplayBonusHtHDmg1_hook() {
|
||||
}
|
||||
}
|
||||
|
||||
static bool bonusHtHDamageFix = false;
|
||||
static bool displayBonusDamage = false;
|
||||
|
||||
static long __fastcall GetHtHDamage(TGameObj* source, long &meleeDmg, long handOffset) {
|
||||
long min, max;
|
||||
|
||||
AttackType hit = Unarmed_GetStoredHitMode((handOffset == 0) ? HANDSLOT_Left : HANDSLOT_Right);
|
||||
long bonus = Unarmed_GetDamage(hit, min, max);
|
||||
meleeDmg += max + bonus;
|
||||
|
||||
long perkBonus = sfgame_perk_level(source, PERK_bonus_hth_damage) << 1;
|
||||
if (!displayBonusDamage) meleeDmg -= perkBonus;
|
||||
if (bonusHtHDamageFix && displayBonusDamage) min += perkBonus;
|
||||
|
||||
return min + bonus;
|
||||
}
|
||||
|
||||
static void __declspec(naked) DisplayBonusHtHDmg2_hack() {
|
||||
static const DWORD DisplayBonusHtHDmg2Exit = 0x47254E;
|
||||
static const DWORD DisplayBonusHtHDmg2Exit = 0x47254F;
|
||||
__asm {
|
||||
mov ecx, eax;
|
||||
call stat_level_;
|
||||
add eax, 2;
|
||||
push eax; // max dmg
|
||||
mov edx, PERK_bonus_hth_damage;
|
||||
mov eax, ecx;
|
||||
call perk_level_;
|
||||
shl eax, 1; // Multiply by 2
|
||||
inc eax; // min dmg (1 + bonus)
|
||||
call stat_level_; // get STAT_melee_dmg
|
||||
push eax; // max dmg (meleeDmg)
|
||||
mov edx, esp; // meleeDmg ref
|
||||
push edi; // handOffset
|
||||
call GetHtHDamage;
|
||||
push eax; // min dmg
|
||||
jmp DisplayBonusHtHDmg2Exit;
|
||||
}
|
||||
}
|
||||
|
||||
static bool bonusHtHDamageFix = false;
|
||||
|
||||
long DamageMod_GetHtHMinDamageBonus(TGameObj* source) {
|
||||
return (bonusHtHDamageFix)
|
||||
? sfgame_perk_level(source, PERK_bonus_hth_damage) << 1 // Rank_of_Bonus_HtH_Damage_perk *= 2
|
||||
@@ -459,13 +473,13 @@ void DamageMod_Init() {
|
||||
}
|
||||
}
|
||||
|
||||
int BonusHtHDmgFix = GetConfigInt("Misc", "BonusHtHDamageFix", 1);
|
||||
int DisplayBonusDmg = GetConfigInt("Misc", "DisplayBonusDamage", 0);
|
||||
bonusHtHDamageFix = GetConfigInt("Misc", "BonusHtHDamageFix", 1) != 0;
|
||||
displayBonusDamage = GetConfigInt("Misc", "DisplayBonusDamage", 0) != 0;
|
||||
|
||||
if (BonusHtHDmgFix) {
|
||||
bonusHtHDamageFix = true;
|
||||
if (bonusHtHDamageFix) {
|
||||
dlog("Applying Bonus HtH Damage Perk fix.", DL_INIT);
|
||||
if (DisplayBonusDmg == 0) { // Subtract damage from perk bonus (vanilla displaying)
|
||||
// Subtract damage from perk bonus (vanilla displaying)
|
||||
if (!displayBonusDamage) {
|
||||
const DWORD meleeDmgDispPrtAddr[] = {
|
||||
0x435C0C, // DisplayFix (ListDrvdStats_)
|
||||
0x439921 // PrintFix (Save_as_ASCII_)
|
||||
@@ -482,17 +496,19 @@ void DamageMod_Init() {
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
|
||||
if (DisplayBonusDmg) {
|
||||
if (displayBonusDamage) {
|
||||
dlog("Applying Display Bonus Damage patch.", DL_INIT);
|
||||
HookCall(0x4722DD, DisplayBonusRangedDmg_hook); // display_stats_
|
||||
if (BonusHtHDmgFix) {
|
||||
HookCall(0x472309, DisplayBonusHtHDmg1_hook); // display_stats_
|
||||
MakeJump(0x472546, DisplayBonusHtHDmg2_hack); // display_stats_
|
||||
if (bonusHtHDamageFix) {
|
||||
HookCall(0x472309, DisplayBonusHtHDmg1_hook); // MeleeWeap (display_stats_)
|
||||
}
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
|
||||
// Display actual damage values for unarmed attacks (display_stats_ hacks)
|
||||
MakeJump(0x472546, DisplayBonusHtHDmg2_hack);
|
||||
SafeWrite32(0x472558, 0x509EDC); // fmt: '%s %d-%d'
|
||||
SafeWrite8(0x472552, 0x98 + 4);
|
||||
SafeWrite8(0x47255F, 0x0C + 4);
|
||||
SafeWrite8(0x472568, 0x10 + 4);
|
||||
}
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,6 +739,17 @@ enum HandSlot : unsigned long
|
||||
HANDSLOT_Right = 1
|
||||
};
|
||||
|
||||
enum HandSlotMode : long
|
||||
{
|
||||
HANDMODE_Unset = 0,
|
||||
HANDMODE_Primary = 1,
|
||||
HANDMODE_Primary_Aimed = 2,
|
||||
HANDMODE_Secondary = 3,
|
||||
HANDMODE_Secondary_Aimed = 4,
|
||||
HANDMODE_Reload = 5,
|
||||
HANDMODE_UnkMode = 6
|
||||
};
|
||||
|
||||
enum RollResult
|
||||
{
|
||||
ROLL_CRITICAL_FAILURE = 0x0,
|
||||
|
||||
+19
-7
@@ -617,6 +617,18 @@ __declspec(noinline) TGameObj* __stdcall GetItemPtrSlot(TGameObj* critter, Inven
|
||||
return itemPtr;
|
||||
}
|
||||
|
||||
AttackType GetHandSlotPrimaryAttack(HandSlot slot) {
|
||||
return (AttackType)ptr_itemButtonItems[slot].primaryAttack;
|
||||
}
|
||||
|
||||
AttackType GetHandSlotSecondaryAttack(HandSlot slot) {
|
||||
return (AttackType)ptr_itemButtonItems[slot].secondaryAttack;
|
||||
}
|
||||
|
||||
HandSlotMode GetHandSlotMode(HandSlot slot) {
|
||||
return (HandSlotMode)ptr_itemButtonItems[slot].mode;
|
||||
}
|
||||
|
||||
long& GetActiveItemMode() {
|
||||
return ptr_itemButtonItems[*ptr_itemCurrentItem].mode;
|
||||
}
|
||||
@@ -627,13 +639,13 @@ TGameObj* GetActiveItem() {
|
||||
|
||||
AttackType GetSlotHitMode(HandSlot hand) { // 0 - left, 1 - right
|
||||
switch (ptr_itemButtonItems[hand].mode) {
|
||||
case 1:
|
||||
case 2: // called shot
|
||||
return (AttackType)ptr_itemButtonItems[hand].primaryAttack;
|
||||
case 3:
|
||||
case 4: // called shot
|
||||
return (AttackType)ptr_itemButtonItems[hand].secondaryAttack;
|
||||
case 5: // reload mode
|
||||
case HANDMODE_Primary:
|
||||
case HANDMODE_Primary_Aimed: // called shot
|
||||
return GetHandSlotPrimaryAttack(hand);
|
||||
case HANDMODE_Secondary:
|
||||
case HANDMODE_Secondary_Aimed: // called shot
|
||||
return GetHandSlotSecondaryAttack(hand);
|
||||
case HANDMODE_Reload:
|
||||
return (AttackType)(ATKTYPE_LWEAPON_RELOAD + hand);
|
||||
}
|
||||
return ATKTYPE_PUNCH;
|
||||
|
||||
@@ -587,6 +587,10 @@ long GetItemType(TGameObj* item);
|
||||
|
||||
__declspec(noinline) TGameObj* __stdcall GetItemPtrSlot(TGameObj* critter, InvenType slot);
|
||||
|
||||
AttackType GetHandSlotPrimaryAttack(HandSlot slot);
|
||||
AttackType GetHandSlotSecondaryAttack(HandSlot slot);
|
||||
HandSlotMode GetHandSlotMode(HandSlot slot);
|
||||
|
||||
long& GetActiveItemMode();
|
||||
|
||||
TGameObj* GetActiveItem();
|
||||
|
||||
@@ -203,8 +203,11 @@ WRAP_WATCOM_FUNC2(long, scr_ptr, long, scriptId, TScript**, scriptPtr) // Return
|
||||
WRAP_WATCOM_FUNC1(long, scr_remove, long, scriptID)
|
||||
WRAP_WATCOM_FUNC1(void, set_focus_func, void*, func)
|
||||
WRAP_WATCOM_FUNC1(long, skill_is_tagged, long, skill)
|
||||
WRAP_WATCOM_FUNC2(long, skill_level, TGameObj*, critter, long, statID)
|
||||
WRAP_WATCOM_FUNC2(long, stat_get_base, TGameObj*, critter, long, statID)
|
||||
WRAP_WATCOM_FUNC2(long, stat_get_base_direct, TGameObj*, critter, long, statID)
|
||||
WRAP_WATCOM_FUNC2(long, stat_get_bonus, TGameObj*, critter, long, statID)
|
||||
WRAP_WATCOM_FUNC3(long, stat_set_bonus, TGameObj*, critter, long, statID, long, amount)
|
||||
WRAP_WATCOM_FUNC2(void, skill_get_tags, long*, tags, long, num)
|
||||
WRAP_WATCOM_FUNC2(void, skill_set_tags, long*, tags, long, num)
|
||||
WRAP_WATCOM_FUNC2(long, stat_level, TGameObj*, critter, long, statId)
|
||||
|
||||
+4
-1
@@ -669,9 +669,12 @@ void Inventory_Init() {
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust the max text width of the total weight display on the inventory screen
|
||||
// Adjust the maximum text width of the total weight display on the inventory screen
|
||||
SafeWrite32(0x472632, widthWeight);
|
||||
|
||||
// Adjust the maximum text width of the unarmed attack display on the inventory screen
|
||||
SafeWrite8(0x472576, 150);
|
||||
|
||||
if (GetConfigInt("Misc", "SuperStimExploitFix", 0)) {
|
||||
Translate_Get("sfall", "SuperStimExploitMsg", "You cannot use this item on someone who is not injured!", superStimMsg);
|
||||
MakeCall(0x49C3D9, protinst_use_item_on_hack);
|
||||
|
||||
+83
-30
@@ -23,6 +23,12 @@
|
||||
|
||||
#include "DamageMod.h"
|
||||
|
||||
static struct {
|
||||
AttackType primaryHit;
|
||||
AttackType secondaryHit;
|
||||
long mode;
|
||||
} slotHitData[2];
|
||||
|
||||
class Hits {
|
||||
public:
|
||||
static const long count = 20;
|
||||
@@ -40,7 +46,6 @@ private:
|
||||
bool isPenetrate; // compute_damage_
|
||||
bool isSecondary;
|
||||
|
||||
// HitsData() : reqLevel(0), reqSkill(0), reqStat(), minDamage(1), maxDamage(2), bonusDamage(0), bonusCrit(0), costAP(3), isPenetrate(false), isSecondary(false) {}
|
||||
HitsData() {
|
||||
reqLevel = 0;
|
||||
reqSkill = 0;
|
||||
@@ -231,7 +236,7 @@ Hits unarmed;
|
||||
static bool UnarmedReqStats(AttackType hit) {
|
||||
if (unarmed.SkillLevel() >= unarmed.Hit(hit).reqSkill && (long)*ptr_Level_pc >= unarmed.Hit(hit).reqLevel) {
|
||||
for (size_t stat = 0; stat < STAT_base_count; stat++) {
|
||||
if (unarmed.Hit(hit).reqStat[stat] == 0) continue;
|
||||
if (unarmed.Hit(hit).reqStat[stat] <= 0) continue;
|
||||
if (unarmed.Hit(hit).reqStat[stat] > unarmed.DudeStat(stat)) {
|
||||
return false;
|
||||
}
|
||||
@@ -241,29 +246,20 @@ static bool UnarmedReqStats(AttackType hit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool Punching(bool isPrimary) {
|
||||
static AttackType GetPunchingHit(bool isPrimary) {
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
AttackType hit = unarmed.GetSortHit(i);
|
||||
if (unarmed.Hit(hit).isSecondary == isPrimary) continue;
|
||||
|
||||
if (UnarmedReqStats(hit)) {
|
||||
if (unarmed.Hit(hit).isSecondary) {
|
||||
ptr_itemButtonItems[HANDSLOT_Left].secondaryAttack = hit;
|
||||
} else {
|
||||
ptr_itemButtonItems[HANDSLOT_Left].primaryAttack = hit;
|
||||
if (unarmed.Hit(hit).isSecondary != isPrimary && UnarmedReqStats(hit)) return hit;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ATKTYPE_PUNCH;
|
||||
}
|
||||
|
||||
// Punch hits
|
||||
static void __fastcall check_unarmed_left_slot(long skillLevel) {
|
||||
unarmed.GetDudeStats(skillLevel);
|
||||
|
||||
if (!Punching(true)) ptr_itemButtonItems[HANDSLOT_Left].primaryAttack = ATKTYPE_PUNCH;
|
||||
if (!Punching(false)) ptr_itemButtonItems[HANDSLOT_Left].secondaryAttack = ATKTYPE_PUNCH;
|
||||
ptr_itemButtonItems[HANDSLOT_Left].primaryAttack = GetPunchingHit(true);
|
||||
ptr_itemButtonItems[HANDSLOT_Left].secondaryAttack = GetPunchingHit(false);
|
||||
}
|
||||
|
||||
static void __declspec(naked) intface_update_items_hack_punch() {
|
||||
@@ -273,27 +269,18 @@ static void __declspec(naked) intface_update_items_hack_punch() {
|
||||
}
|
||||
}
|
||||
|
||||
static bool Kicking(bool isPrimary) {
|
||||
static AttackType GetKickingHit(bool isPrimary) {
|
||||
for (size_t i = 6; i < 12; i++) {
|
||||
AttackType hit = unarmed.GetSortHit(i);
|
||||
if (unarmed.Hit(hit).isSecondary == isPrimary) continue;
|
||||
|
||||
if (UnarmedReqStats(hit)) {
|
||||
if (unarmed.Hit(hit).isSecondary) {
|
||||
ptr_itemButtonItems[HANDSLOT_Right].secondaryAttack = hit;
|
||||
} else {
|
||||
ptr_itemButtonItems[HANDSLOT_Right].primaryAttack = hit;
|
||||
if (unarmed.Hit(hit).isSecondary != isPrimary && UnarmedReqStats(hit)) return hit;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ATKTYPE_KICK;
|
||||
}
|
||||
|
||||
// Kick hits
|
||||
static void check_unarmed_right_slot() {
|
||||
if (!Kicking(true)) ptr_itemButtonItems[HANDSLOT_Right].primaryAttack = ATKTYPE_KICK;
|
||||
if (!Kicking(false)) ptr_itemButtonItems[HANDSLOT_Right].secondaryAttack = ATKTYPE_KICK;
|
||||
ptr_itemButtonItems[HANDSLOT_Right].primaryAttack = GetKickingHit(true);
|
||||
ptr_itemButtonItems[HANDSLOT_Right].secondaryAttack = GetKickingHit(false);
|
||||
}
|
||||
|
||||
static void __declspec(naked) intface_update_items_hack_kick() {
|
||||
@@ -350,6 +337,69 @@ long Unarmed_GetHitAPCost(AttackType hit) {
|
||||
return unarmed.Hit(hit).apCost;
|
||||
}
|
||||
|
||||
long Unarmed_GetDamage(AttackType hit, long &minOut, long &maxOut) {
|
||||
minOut = unarmed.Hit(hit).minDamage;
|
||||
maxOut = unarmed.Hit(hit).maxDamage;
|
||||
return unarmed.Hit(hit).bonusDamage;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AttackType GetPunchingHit() {
|
||||
unarmed.GetDudeStats(fo_skill_level(*ptr_obj_dude, SKILL_UNARMED_COMBAT));
|
||||
return GetPunchingHit(true);
|
||||
}
|
||||
|
||||
static AttackType GetKickingHit() {
|
||||
//unarmed.GetDudeStats(fo_skill_level(*ptr_obj_dude, SKILL_UNARMED_COMBAT));
|
||||
return GetKickingHit(true);
|
||||
}
|
||||
|
||||
static void SlotsStoreCurrentHitMode() {
|
||||
slotHitData[HANDSLOT_Left].primaryHit = GetHandSlotPrimaryAttack(HANDSLOT_Left);
|
||||
slotHitData[HANDSLOT_Left].secondaryHit = GetHandSlotSecondaryAttack(HANDSLOT_Left);
|
||||
slotHitData[HANDSLOT_Left].mode = GetHandSlotMode(HANDSLOT_Left);
|
||||
|
||||
slotHitData[HANDSLOT_Right].primaryHit = GetHandSlotPrimaryAttack(HANDSLOT_Right);
|
||||
slotHitData[HANDSLOT_Right].secondaryHit = GetHandSlotSecondaryAttack(HANDSLOT_Right);
|
||||
slotHitData[HANDSLOT_Right].mode = GetHandSlotMode(HANDSLOT_Right);
|
||||
}
|
||||
|
||||
AttackType Unarmed_GetStoredHitMode(HandSlot slot) {
|
||||
AttackType hit;
|
||||
|
||||
switch (slotHitData[slot].mode) {
|
||||
case HANDMODE_Primary:
|
||||
case HANDMODE_Primary_Aimed: // called shot
|
||||
hit = slotHitData[slot].primaryHit;
|
||||
break;
|
||||
case HANDMODE_Secondary:
|
||||
case HANDMODE_Secondary_Aimed: // called shot
|
||||
hit = slotHitData[slot].secondaryHit;
|
||||
break;
|
||||
}
|
||||
|
||||
if (hit < ATKTYPE_STRONGPUNCH && hit != ATKTYPE_PUNCH && hit != ATKTYPE_KICK) {
|
||||
hit = (slot == HANDSLOT_Left) ? GetPunchingHit() : GetKickingHit(); // get Primary
|
||||
|
||||
if (slot == HANDSLOT_Left) {
|
||||
slotHitData[HANDSLOT_Left].primaryHit = hit;
|
||||
slotHitData[HANDSLOT_Left].mode = HANDMODE_Primary;
|
||||
} else {
|
||||
slotHitData[HANDSLOT_Right].primaryHit = hit;
|
||||
slotHitData[HANDSLOT_Right].mode = HANDMODE_Primary;
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
static void __declspec(naked) handle_inventory_hook() {
|
||||
__asm {
|
||||
call SlotsStoreCurrentHitMode;
|
||||
jmp display_stats_;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void __declspec(naked) statPCAddExperienceCheckPMs_hook() {
|
||||
@@ -437,6 +487,9 @@ void Unarmed_Init() {
|
||||
MakeCall(0x4248B6, check_unarmed_penetrate, 5);
|
||||
SafeWrite16(0x4248C1, 0x01F8); // cmp eax, 1
|
||||
SafeWrite8(0x4248C8, CODETYPE_JumpShort);
|
||||
|
||||
// Store the current values of unarmed attack modes when opening the player's inventory
|
||||
HookCall(0x46E8D4, handle_inventory_hook);
|
||||
}
|
||||
|
||||
//void Unarmed_Exit() {
|
||||
|
||||
@@ -22,3 +22,6 @@ void Unarmed_Init();
|
||||
//void Unarmed_Exit();
|
||||
|
||||
long Unarmed_GetHitAPCost(AttackType hit);
|
||||
long Unarmed_GetDamage(AttackType hit, long &minOut, long &maxOut);
|
||||
|
||||
AttackType Unarmed_GetStoredHitMode(HandSlot slot);
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<CallingConvention>Cdecl</CallingConvention>
|
||||
<ForcedIncludeFiles>stdafx.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
|
||||
Reference in New Issue
Block a user