diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 9c24318e..e1c68211 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -372,7 +372,7 @@ NPCsTryToSpendExtraAP=0 ;Note that enabling this option can significantly affect the weapon choice of some NPCs in combat AIBestWeaponFix=0 -;Set to 1 to fix NPCs not checking chem_primary_desire setting in AI.txt for drug use preference +;Set to 1 to fix NPCs not taking chem_primary_desire in AI.txt as drug use preference when using drugs in their inventory AIDrugUsePerfFix=0 ;Allows the use of tiles over 80*36 in size. sfall will just split and resave them at startup diff --git a/artifacts/scripting/headers/define_extra.h b/artifacts/scripting/headers/define_extra.h index 26ef0cb6..29af1531 100644 --- a/artifacts/scripting/headers/define_extra.h +++ b/artifacts/scripting/headers/define_extra.h @@ -267,4 +267,49 @@ #define WPN_ANIM_MINIGUN (0x09) // (L) #define WPN_ANIM_ROCKET_LAUNCHER (0x0A) // (M) +// Compute attack result fields +#define C_ATTACK_SOURCE (0x00) +#define C_ATTACK_HIT_MODE (0x04) +#define C_ATTACK_WEAPON (0x08) +#define C_ATTACK_DAMAGE_SOURCE (0x10) // Amount +#define C_ATTACK_FLAGS_SOURCE (0x14) // see DAM_* values in define.h +#define C_ATTACK_ROUNDS (0x18) +#define C_ATTACK_TARGET (0x20) +#define C_ATTACK_BODY_PART (0x28) +#define C_ATTACK_DAMAGE_TARGET (0x2C) // Amount +#define C_ATTACK_FLAGS_TARGET (0x30) // see DAM_* +#define C_ATTACK_KNOCKBACK_VALUE (0x34) +#define C_ATTACK_MAIN_TARGET (0x38) +#define C_ATTACK_AROUND_NUMBER (0x3C) // The number of critters around the target +#define C_ATTACK_TARGET1 (0x40) +#define C_ATTACK_TARGET2 (0x44) +#define C_ATTACK_TARGET3 (0x48) +#define C_ATTACK_TARGET4 (0x4C) +#define C_ATTACK_TARGET5 (0x50) +#define C_ATTACK_TARGET6 (0x54) +#define C_ATTACK_BODY_PART1 (0x58) +#define C_ATTACK_BODY_PART2 (0x5C) +#define C_ATTACK_BODY_PART3 (0x60) +#define C_ATTACK_BODY_PART4 (0x64) +#define C_ATTACK_BODY_PART5 (0x68) +#define C_ATTACK_BODY_PART6 (0x6C) +#define C_ATTACK_DAMAGE_TARGET1 (0x70) // Amount +#define C_ATTACK_DAMAGE_TARGET2 (0x74) +#define C_ATTACK_DAMAGE_TARGET3 (0x78) +#define C_ATTACK_DAMAGE_TARGET4 (0x7C) +#define C_ATTACK_DAMAGE_TARGET5 (0x80) +#define C_ATTACK_DAMAGE_TARGET6 (0x84) +#define C_ATTACK_FLAGS_TARGET1 (0x88) // see DAM_* +#define C_ATTACK_FLAGS_TARGET2 (0x8C) +#define C_ATTACK_FLAGS_TARGET3 (0x90) +#define C_ATTACK_FLAGS_TARGET4 (0x94) +#define C_ATTACK_FLAGS_TARGET5 (0x98) +#define C_ATTACK_FLAGS_TARGET6 (0x9C) +#define C_ATTACK_KNOCKBACK_VALUE1 (0xA0) +#define C_ATTACK_KNOCKBACK_VALUE2 (0xA4) +#define C_ATTACK_KNOCKBACK_VALUE3 (0xA8) +#define C_ATTACK_KNOCKBACK_VALUE4 (0xAC) +#define C_ATTACK_KNOCKBACK_VALUE5 (0xB0) +#define C_ATTACK_KNOCKBACK_VALUE6 (0xB4) + #endif // DEFINE_EXTRA_H diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index d6734487..3294dde0 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -58,6 +58,7 @@ #define HOOK_DESCRIPTIONOBJ (34) #define HOOK_USESKILLON (35) #define HOOK_ONEXPLOSION (36) +#define HOOK_SUBCOMBATDAMAGE (37) //Valid arguments to list_begin #define LIST_CRITTERS (0) diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index 09fa4993..84ce3b70 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -166,7 +166,7 @@ int arg5 - The special effect flags for the target (use bwand DAM_* to chec int arg6 - The special effect flags for the attacker (use bwand DAM_* to check specific flags) int arg7 - The weapon used in the attack int arg8 - The bodypart that was struck -int arg9 - Damage Multiplier (this is divided by 2, so a value of 3 does 1.5x damage, and 8 does 4x damage. Usually it's 2, but with Silent Death perk and the corresponding attack conditions, it's 4; for critical hits, the value is taken from the critical table) +int arg9 - Damage Multiplier (this is divided by 2, so a value of 3 does 1.5x damage, and 8 does 4x damage. Usually it's 2; for critical hits, the value is taken from the critical table; with Silent Death perk and the corresponding attack conditions, the value will be doubled) int arg10 - Number of bullets actually hit the target (1 for melee attacks) int arg11 - The amount of knockback to the target int arg12 - Attack Type (see ATKTYPE_* constants) @@ -434,7 +434,7 @@ HOOK_INVENWIELD (hs_invenwield.int) Runs before wielding or unwielding an armor or a weapon by a critter (except when using inventory by PC). An example usage would be to change critter art depending on armor being used or to dynamically customize weapon animations. NOTE: when replacing a previously wielded armor or weapon, the unwielding hook will not be executed. -If you need to rely on this, try checking if armor/weapon already equipped when wielding hook is executed. +If you need to rely on this, try checking if armor/weapon is already equipped when wielding hook is executed. Critter arg1 - critter Obj arg2 - item being wielded or unwielded (weapon/armor) @@ -578,3 +578,28 @@ Critter arg6 - The target critter, may be 0 or equal to the attacker int arg7 - 1 when using throwing weapons (e.g. grenades), 0 otherwise int ret1 - overrides the found object on the checked tile, pass 0 to skip the object + +------------------------------------------- + +HOOK_SUBCOMBATDAMAGE (hs_subcombatdmg.int) + +This hook overrides the vanilla damage calculation formula. +Runs when: +1) Before the game calculates how much damage each target will get. This includes primary target as well as all extras (explosions and bursts). +2) AI decides whether it is safe to use area attack (burst, grenades), if he might hit friendlies. +Does not run for misses, non-combat damage like dynamite explosions, or if one of the damage formulas is selected in ddraw.ini. + +Critter arg1 - The attacker +Critter arg2 - The target +Obj arg3 - The weapon used in the attack +int arg4 - Attack Type (see ATKTYPE_* constants) +int arg5 - Number of bullets actually hit the target (1 for melee attacks) +int arg6 - Target's Damage Resistance (DR) value (affected by critical hit effects, perks, traits, and special unarmed attacks) +int arg7 - Target's Damage Threshold (DT) value (affected by critical hit effects, perks, traits, and special unarmed attacks) +int arg8 - Bonus ranged damage from the perk +int arg9 - Damage Multiplier (this is divided by 2, so a value of 3 does 1.5x damage, and 8 does 4x damage. Usually it's 2; for critical hits, the value is taken from the critical table; with Silent Death perk and the corresponding attack conditions, the value will be doubled) +int arg10 - Combat Difficulty multiplier (125 - rough, 100 - normal, 75 - wimpy) +int arg11 - The calculated amount of damage (usually 0, required when using multiple hook scripts to calculate damage and using the set_sfall_arg function) +mixed arg12 - Computed attack results (see C_ATTACK_* for offsets and use read_int(arg12 + offset) to get the data) + +int ret1 - The returned amount of damage diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index 12cebff9..512ab6b3 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -56,6 +56,10 @@ WRAP_WATCOM_FUNC1(long, item_w_anim_code, GameObject*, item) WRAP_WATCOM_FUNC2(long, item_w_anim_weap, GameObject*, item, DWORD, hitMode) WRAP_WATCOM_FUNC2(long, item_w_compute_ammo_cost, GameObject*, item, DWORD*, rounds) WRAP_WATCOM_FUNC1(long, item_w_curr_ammo, GameObject*, item) +WRAP_WATCOM_FUNC2(long, item_w_damage, GameObject*, critter, long, hitMode) +WRAP_WATCOM_FUNC1(long, item_w_dam_div, GameObject*, item) +WRAP_WATCOM_FUNC1(long, item_w_dam_mult, GameObject*, item) +WRAP_WATCOM_FUNC1(long, item_w_dr_adjust, GameObject*, item) WRAP_WATCOM_FUNC1(long, item_w_rounds, GameObject*, item) WRAP_WATCOM_FUNC1(long, item_w_max_ammo, GameObject*, item) WRAP_WATCOM_FUNC1(long, item_weight, GameObject*, item) diff --git a/sfall/Modules/AmmoMod.cpp b/sfall/Modules/AmmoMod.cpp index 4fe4502e..07995221 100644 --- a/sfall/Modules/AmmoMod.cpp +++ b/sfall/Modules/AmmoMod.cpp @@ -20,31 +20,35 @@ #include "..\FalloutEngine\Fallout2.h" #include "..\Logging.h" +#include "HookScripts.h" #include "AmmoMod.h" -namespace sfall +namespace sfall { using namespace fo; int AmmoMod::formula; -static const DWORD DamageFunctionReturn = 0x424A63; - // Damage Fix v5 (with v5.1 Damage Multiplier tweak) by Glovz 2014.04.16.xx.xx -// TODO: remove or rewrite in C++ -static __declspec(naked) void DamageGlovz() { +// TODO: rewrite in C++ +void AmmoMod::DamageGlovz(fo::ComputeAttackResult &ctd, DWORD* accumulatedDamage, int rounds, int armorDT, int armorDR, int bonusRangedDamage, int multiplyDamage, int difficulty) { + if (rounds <= 0) return; + + int ammoY = fo::func::item_w_dam_div(ctd.weapon); // ammoY value (divisor) + int ammoX = fo::func::item_w_dam_mult(ctd.weapon); // ammoX value + int ammoDRM = fo::func::item_w_dr_adjust(ctd.weapon); // ammoDRM value + int mValue; + __asm { - mov ebx, dword ptr ss:[esp + 0x1C]; // get the number of hits - xor ecx, ecx; // set the loop counter to 0 - cmp ebx, 0; // compare the number of hits to 0 - jle end; // exit + mov esi, ctd; + mov edi, accumulatedDamage; begin: - mov dword ptr ss:[esp + 0x30], 0; // clear value - mov edx, dword ptr ds:[esi + 4]; // get pointer to weapon being used by an attacker (I think) + mov mValue, 0; // clear value + mov edx, dword ptr ds:[esi + 4]; // get the hit mode of weapon being used by an attacker mov eax, dword ptr ds:[esi]; // get pointer to critter attacking call fo::funcoffs::item_w_damage_; // get the raw damage value - mov ebx, dword ptr ss:[esp + 0x18]; // get the bonus ranged damage value + mov ebx, bonusRangedDamage; // get the bonus ranged damage value cmp ebx, 0; // compare the range bonus damage value to 0 jle rdJmp; // if the RB value is less than or equal to 0 then goto rdJmp add eax, ebx; // add the RB value to the RD value @@ -52,47 +56,46 @@ rdJmp: cmp eax, 0; // compare the new damage value to 0 jle noDamageJmp; // goto noDamageJmp mov ebx, eax; // set the ND value - mov edx, dword ptr ss:[esp + 0x28]; // get the armorDT value + mov edx, armorDT; // get the armorDT value cmp edx, 0; // compare the armorDT value to 0 jle bJmp; // if the armorDT value is less than or equal to 0 then goto bJmp - mov eax, dword ptr ds:[esi + 0x8]; // get pointer to critters ammo being used in their weapon (I think) - call fo::funcoffs::item_w_dam_div_; // get the ammoY value + mov eax, dword ptr ammoY; // get the ammoY value cmp eax, 0; // compare the ammoY value to 0 jg aJmp; // if the ammoY value is greater than 0 then goto aJmp mov eax, 1; // set the ammoY value to 1 aJmp: - xor ebp, ebp; // clear value + xor ecx, ecx; // clear value (old ebp) cmp edx, eax; // compare the dividend with the divisor jl lrThan; // the dividend is less than the divisor then goto lrThan jg grThan; // the dividend is greater than the divisor then goto grThan jmp setOne; // if the two values are equal then goto setOne lrThan: - mov ebp, edx; // store the dividend value temporarily + mov ecx, edx; // store the dividend value temporarily imul edx, 2; // multiply dividend value by 2 sub edx, eax; // subtract divisor value from the dividend value cmp edx, 0; // compare the result to 0 jl setZero; // if the result is less than 0 then goto setZero jg setOne; // if the result is greater than 0 then goto setOne - mov edx, ebp; // restore dividend value + mov edx, ecx; // restore dividend value and edx, 1; // if true (1) then odd if false (0) then even jz setZero; // if the result is equal to 0 then setZero jmp setOne; // if the result is not 0 then goto setOne grThan: - mov ebp, eax; // assign the divisor value + mov ecx, eax; // assign the divisor value xor eax, eax; // clear value bbbJmp: inc eax; // add 1 to the quotient value - sub edx, ebp; // subtract the divisor value from the dividend value - cmp edx, ebp; // compare the remainder value to the divisor value + sub edx, ecx; // subtract the divisor value from the dividend value + cmp edx, ecx; // compare the remainder value to the divisor value jge bbbJmp; // if the remainder value is greater or equal to the divisor value then goto bbbJmp jz endDiv; // if the remainder value is equal to 0 then goto endDiv imul edx, 2; // multiply temp remainder value by 2 - sub edx, ebp; // subtract the divisor value from the temp remainder + sub edx, ecx; // subtract the divisor value from the temp remainder cmp edx, 0; // compare the result to 0 jl endDiv; // if the result is less than 0 then goto endDiv jg addOne; // if the result is greater than 0 then goto addOne - mov ebp, eax; // assign the quotient value - and ebp, 1; // if true (1) then odd if false (0) then even + mov ecx, eax; // assign the quotient value + and ecx, 1; // if true (1) then odd if false (0) then even jz endDiv; // if the result is equal to zero goto endDiv addOne: inc eax; // add 1 to the quotient value @@ -103,31 +106,31 @@ setOne: setZero: xor eax, eax; // clear value endDiv: - cmp dword ptr ss:[esp + 0x30], 2; // compare value to 2 + cmp mValue, 2; // compare value to 2 je divTwo; // goto divTwo - cmp dword ptr ss:[esp + 0x30], 3; // compare value to 3 + cmp mValue, 3; // compare value to 3 je divThree; // goto divThree - cmp dword ptr ss:[esp + 0x30], 4; // compare value to 4 + cmp mValue, 4; // compare value to 4 je divFour; // goto divFour - cmp dword ptr ss:[esp + 0x30], 5; // compare value to 5 + cmp mValue, 5; // compare value to 5 je divFive; // goto divFive - cmp dword ptr ss:[esp + 0x30], 6; // compare value to 6 + cmp mValue, 6; // compare value to 6 je divSix; // goto divSix - cmp dword ptr ss:[esp + 0x30], 7; // compare value to 7 + cmp mValue, 7; // compare value to 7 (added for v5.1 tweak) je divSeven; // goto divSeven sub ebx, eax; // subtract the new armorDT value from the RD value jmp cJmp; // goto cJmp bJmp: - mov edx, dword ptr ss:[esp + 0x2C]; // get the armorDR value + mov edx, armorDR; // get the armorDR value cmp edx, 0; // compare the armorDR value to 0 jle dJmp; // if the armorDR value is less than or equal to 0 then goto dJmp cJmp: cmp ebx, 0; // compare the new damage value to 0 jle noDamageJmp; // goto noDamageJmp - mov edx, dword ptr ss:[esp + 0x2C]; // get the armorDR value + mov edx, armorDR; // get the armorDR value cmp edx, 0; // compare the armorDR value to 0 jle eJmp; // if the armorDR value is less than or equal to 0 then goto eJmp - mov eax, dword ptr ss:[esp + 0x20]; // get the CD value + mov eax, difficulty; // get the CD value cmp eax, 100; // compare the CD value to 100 jg sdrJmp; // if the CD value is greater than 100 then goto sdrJmp je aSubCJmp; // if the CD value is equal to 100 then goto aSubCJmp @@ -136,47 +139,43 @@ cJmp: sdrJmp: sub edx, 20; // subtract 20 from the armorDR value aSubCJmp: - mov eax, dword ptr ds:[esi + 0x8]; // get pointer to ammo being used in the critters weapon (I think) - call fo::funcoffs::item_w_dr_adjust_; // get the ammoDRM value + mov eax, dword ptr ammoDRM; // get the ammoDRM value cmp eax, 0; // compare the ammoDRM value to 0 jl adrJmp; // if the ammoDRM value is less than 0 then goto adrJmp je bSubCJmp; // if the ammoDRM value is equal to 0 then goto bSubCJmp - xor ebp, ebp; // clear value - sub ebp, eax; // subtract ammoDRM value from 0 - mov eax, ebp; // set new ammoDRM value + xor ecx, ecx; // clear value + sub ecx, eax; // subtract ammoDRM value from 0 + mov eax, ecx; // set new ammoDRM value adrJmp: add edx, eax; // add the ammoDRM value to the armorDR value bSubCJmp: - mov eax, dword ptr ds:[esi + 0x8]; // get pointer to ammo being used in the critters weapon (I think) - call fo::funcoffs::item_w_dam_mult_; // get the ammoX value + mov eax, dword ptr ammoX; // get the ammoX value cmp eax, 0; // compare the ammoX value to 0 jg cSubCJmp; // if the ammoX value is greater than 0 then goto cSubCJmp; mov eax, 1; // set the ammoX value to 1 cSubCJmp: - mov dword ptr ss:[esp + 0x30], 2; // set value to 2 + mov mValue, 2; // set value to 2 jmp aJmp; // goto aJmp divTwo: mov edx, ebx; // set temp value imul edx, eax; // multiply the ND value by the armorDR value mov eax, 100; // set divisor value to 100 - mov dword ptr ss:[esp + 0x30], 3; // set value to 3 + mov mValue, 3; // set value to 3 jmp aJmp; // goto aJmp divThree: sub ebx, eax; // subtract the damage resisted value from the ND value jmp eJmp; // goto eJmp dJmp: - mov eax, dword ptr ds:[esi + 0x8]; // get pointer to ammo being used in the critters weapon (I think) - call fo::funcoffs::item_w_dam_mult_; // get the ammoX value + mov eax, dword ptr ammoX; // get the ammoX value cmp eax, 1; // compare the ammoX value to 1 jle bSubDJmp; // if the ammoX value is less than or equal to 1 then goto bSubDJmp; - mov eax, dword ptr ds:[esi + 0x8]; // get pointer to critters ammo being used in their weapon (I think) - call fo::funcoffs::item_w_dam_div_; // get the ammoY value + mov eax, dword ptr ammoY; // get the ammoY value cmp eax, 1; // compare the ammoY value to 1 jle aSubDJmp; // if the ammoY value is less than or equal to 1 then goto aSubDJmp mov edx, ebx; // set temp value imul edx, 15; // multiply the ND value by 15 mov eax, 100; // set divisor value to 100 - mov dword ptr ss:[esp + 0x30], 4; // set value to 4 + mov mValue, 4; // set value to 4 jmp aJmp; // goto aJmp divFour: add ebx, eax; // add the quotient value to the ND value @@ -185,27 +184,26 @@ aSubDJmp: mov edx, ebx; // set temp value imul edx, 20; // multiply the ND value by 20 mov eax, 100; // set divisor value to 100 - mov dword ptr ss:[esp + 0x30], 5; // set value to 5 + mov mValue, 5; // set value to 5 jmp aJmp; // goto aJmp divFive: add ebx, eax; // add the quotient value to the ND value jmp eJmp; // goto eJmp bSubDJmp: - mov eax, dword ptr ds:[esi + 0x8]; // get pointer to critters ammo being used in their weapon (I think) - call fo::funcoffs::item_w_dam_div_; // get the ammoY value + mov eax, dword ptr ammoY; // get the ammoY value cmp eax, 1; // compare the ammoY value to 1 jle eJmp; // goto eJmp mov edx, ebx; // set temp value imul edx, 10; // multiply the ND value by 10 mov eax, 100; // set divisor value to 100 - mov dword ptr ss:[esp + 0x30], 6; // set value to 6 + mov mValue, 6; // set value to 6 jmp aJmp; // goto aJmp divSix: add ebx, eax; // add the quotient value to the ND value eJmp: cmp ebx, 0; // compare the new damage value to 0 jle noDamageJmp; // goto noDamageJmp - mov eax, dword ptr ss:[esp + 0x24]; // get the CM value + mov eax, multiplyDamage; // get the Critical Multiplier (CM) value cmp eax, 2; // compare the CM value to 2 jle addNDJmp; // if the CM value is less than or equal to 2 then goto addNDJmp cmp AmmoMod::formula, 2; // check selected damage formula (added for v5.1 tweak) @@ -219,7 +217,7 @@ tweak: imul edx, eax; // multiply the temp ND value by the CM value imul edx, 25; // multiply the temp ND value by 25 mov eax, 100; // set divisor value to 100 - mov dword ptr ss:[esp + 0x30], 7; // set value to 7 + mov mValue, 7; // set value to 7 jmp aJmp; // goto aJmp divSeven: add ebx, eax; // add the critical damage value to the ND value @@ -227,108 +225,59 @@ divSeven: addNDJmp: add dword ptr ds:[edi], ebx; // accumulate damage noDamageJmp: - mov eax, dword ptr ss:[esp + 0x1C]; // get the number of hits - inc ecx; // the counter value increments by one - cmp ecx, eax; // is the counter value less than the number of hits - jl begin; // goto begin -end: - jmp DamageFunctionReturn; // exit + dec dword ptr rounds; // decrease the hit counter value by one + jnz begin; // compare the number of hits to 0 } } // YAAM -// TODO: rewrite in C++ -static __declspec(naked) void DamageYAAM() { - __asm { - mov eax, dword ptr ds:[esi + 0x8]; // Get pointer to critter's weapon - mov edx, dword ptr ss:[esp + 0x24]; // Get Critical Multiplier (passed in as argument to function) - call fo::funcoffs::item_w_dam_mult_; // Retrieve Ammo Dividend - imul edx, eax; // Damage Multipler = Critical Multipler * Ammo Dividend - mov eax, dword ptr ds:[esi + 0x8]; // Get pointer to critter's weapon - call fo::funcoffs::item_w_dam_div_; // Retrieve Ammo Divisor - imul ebp, eax; // Ammo Divisor = 1 * Ammo Divisor (ebp set to 1 earlier in function) - mov ebx, dword ptr ss:[esp + 0x1C]; // Get number of hits - xor ecx, ecx; // Set loop counter to zero - mov dword ptr ss:[esp + 0x24], edx; // Store Damage Multiplier - test ebx, ebx; // Is number of hits <= 0? - jle end; // If yes, jump beyond damage calculation loop -ajmp: // Start of damage calculation loop - mov edx, dword ptr ds:[esi + 0x4]; // Get pointer to weapon (?) - mov eax, dword ptr ds:[esi]; // Get pointer to critter (?) - mov ebx, dword ptr ss:[esp + 0x18]; // Get Bonus Ranged Damage - call fo::funcoffs::item_w_damage_; // Retrieve Raw Damage - add ebx, eax; // Raw Damage = Raw Damage + Bonus Ranged Damage - mov edx, dword ptr ss:[esp + 0x28]; // Get armor DT - mov eax, dword ptr ds:[esi + 0x8]; // Get pointer to critter's weapon - call fo::funcoffs::item_w_dr_adjust_; // Retrieve ammo DT (well, it's really Retrieve ammo DR, but since we're treating ammo DR as ammo DT...) - sub edx, eax; // DT = armor DT - ammo DT - test edx, edx; // Is DT >= 0? - jge bjmp; // If yes, skip the next instruction - xor edx, edx; // Otherwise, set DT = 0 -bjmp: - sub ebx, edx; // Raw Damage = Raw Damage - DT - test ebx, ebx; // Is Raw Damage <= 0? - jle cjmp; // If yes, skip damage calculation and go to bottom of loop - imul ebx, dword ptr ss:[esp + 0x24]; // Otherwise, Raw Damage = Raw Damage * Damage Multiplier - test ebp, ebp; // Is Ammo Divisor == 0? - je djmp; // If yes, avoid divide by zero error - mov edx, ebx; - mov eax, ebx; - sar edx, 31; - idiv ebp; - mov ebx, eax; // Otherwise, Raw Damage = Raw Damage / Ammo Divisor -djmp: - mov edx, ebx; - mov eax, ebx; - sar edx, 31; - sub eax, edx; - sar eax, 1; // Raw Damage = Raw Damage / 2 (related to critical hit damage multiplier bonus) - mov edx, dword ptr ss:[esp + 0x20]; // Get combat difficulty setting (75 if wimpy, 100 if normal or if attacker is player, 125 if rough) - imul edx, eax; // Raw Damage = Raw Damage * combat difficulty setting - mov ebx, 100; - mov eax, edx; - sar edx, 31; - idiv ebx; - mov ebx, eax; // Raw Damage = Raw Damage / 100 - mov edx, dword ptr ss:[esp + 0x28]; // Get armor DT - mov eax, dword ptr ds:[esi + 0x8]; // Get pointer to critter's weapon - call fo::funcoffs::item_w_dr_adjust_; // Retrieve ammo DT - sub edx, eax; // DT = armor DT - ammo DT - test edx, edx; // Is DT >= 0? - jge ejmp; // If yes, set DT = 0 - mov eax, 10; - imul eax, edx; // Otherwise, DT = DT * 10 (note that this should be a negative value) - jmp fjmp; -ejmp: - xor eax, eax; -fjmp: - mov edx, dword ptr ss:[esp + 0x2C]; // Get armor DR - add edx, eax; // DR = armor DR + DT (note that DT should be less than or equal to zero) - test edx, edx; // Is DR >= 0? - jge gjmp; - xor edx, edx; // If no, set DR = 0 - jmp hjmp; -gjmp: - cmp edx, 100; // Otherwise, is DR >= 100? - jge ijmp; // If yes, damage will be zero, so stop calculating and go to bottom of loop -hjmp: - imul edx, ebx; // Otherwise, Resisted Damage = DR * Raw Damage - mov dword ptr ss:[esp + 0x30], 100; - mov eax, edx; - sar edx, 31; - idiv dword ptr ss:[esp + 0x30]; // Resisted Damage = Resisted Damage / 100 - sub ebx, eax; // Raw Damage = Raw Damage - Resisted Damage -cjmp: - test ebx, ebx; // Is Raw Damage <= 0? - jle ijmp; // If yes, don't accumulate damage - add dword ptr ds:[edi], ebx; // Otherwise, Accumulated Damage = Accumulated Damage + Raw Damage -ijmp: - mov eax, dword ptr ss:[esp + 0x1C]; // Get number of hits - inc ecx; // counter += 1 - cmp ecx, eax; // Is counter < number of hits? - jl ajmp; // If yes, go back to start of damage calcuation loop (calculate damage for next hit) -end: - jmp DamageFunctionReturn; // Otherwise, exit loop +void AmmoMod::DamageYAAM(fo::ComputeAttackResult &ctd, DWORD* accumulatedDamage, int rounds, int armorDT, int armorDR, int bonusRangedDamage,int multiplyDamage, int difficulty) { + int ammoDiv = fo::func::item_w_dam_div(ctd.weapon); // Retrieve Ammo Divisor + int ammoMult = fo::func::item_w_dam_mult(ctd.weapon); // Retrieve Ammo Dividend + + multiplyDamage *= ammoMult; // Damage Multipler = Critical Multipler * Ammo Dividend + int ammoDivisor = 1 * ammoDiv; // Ammo Divisor = 1 * Ammo Divisor + + int ammoDT = fo::func::item_w_dr_adjust(ctd.weapon); // Retrieve ammo DT (well, it's really Retrieve ammo DR, but since we're treating ammo DR as ammo DT...) + + // Start of damage calculation loop + for (int i = 0; i < rounds; i++) { // Check number of hits + int rawDamage = fo::func::item_w_damage(ctd.attacker, ctd.hitMode); // Retrieve Raw Damage + rawDamage += bonusRangedDamage; // Raw Damage = Raw Damage + Bonus Ranged Damage + + int calcDT = armorDT - ammoDT; // DT = armor DT - ammo DT + if (calcDT < 0) calcDT = 0; + + rawDamage -= calcDT; // Raw Damage = Raw Damage - DT + if (rawDamage <= 0) continue; // Is Raw Damage <= 0? If yes, skip damage calculation and go to bottom of loop + + rawDamage *= multiplyDamage; // Raw Damage = Raw Damage * Damage Multiplier + if (ammoDivisor != 0) { // avoid divide by zero error + rawDamage /= ammoDivisor; // Raw Damage = Raw Damage / Ammo Divisor + } + rawDamage /= 2; // Raw Damage = Raw Damage / 2 (related to critical hit damage multiplier bonus) + rawDamage *= difficulty; // Raw Damage = Raw Damage * combat difficulty setting (75 if wimpy, 100 if normal or if attacker is player, 125 if rough) + rawDamage /= 100; // Raw Damage = Raw Damage / 100 + + calcDT = armorDT - ammoDT; // DT = armor DT - ammo DT + if (calcDT >= 0) { // Is DT >= 0? + calcDT = 0; // If yes, set DT = 0 + } else { + calcDT *= 10; // Otherwise, DT = DT * 10 (note that this should be a negative value) + } + + int calcDR = armorDR + calcDT; // DR = armor DR + DT (note that DT should be less than or equal to zero) + if (calcDR >= 100) { // Is DR >= 100? + continue; // If yes, damage will be zero, so stop calculating and go to bottom of loop + } else if (calcDR < 0) { // Is DR >= 0? + calcDR = 0; // If no, set DR = 0 + } + + int resistedDamage = calcDR * rawDamage; // Otherwise, Resisted Damage = DR * Raw Damage + resistedDamage /= 100; // Resisted Damage = Resisted Damage / 100 + rawDamage -= resistedDamage; // Raw Damage = Raw Damage - Resisted Damage + + if (rawDamage > 0) *accumulatedDamage += rawDamage; // Accumulated Damage = Accumulated Damage + Raw Damage } } //////////////////////////////////////////////////////////////////////////////// @@ -446,17 +395,13 @@ void AmmoMod::init() { switch (formula) { case 1: case 2: - MakeJump(0x424995, DamageGlovz); - break; - /*case 3: - MakeJump(0x424995, DamageFunction3); - break; - case 4: - MakeJump(0x424995, DamageFunction4); - break;*/ case 5: - MakeJump(0x424995, DamageYAAM); + if (!HookScripts::IsInjectHook(HOOK_SUBCOMBATDAMAGE)) { + HookScripts::InjectingHook(HOOK_SUBCOMBATDAMAGE); + } break; + default: + formula = 0; } } diff --git a/sfall/Modules/AmmoMod.h b/sfall/Modules/AmmoMod.h index a3d7c987..4b8d7afa 100644 --- a/sfall/Modules/AmmoMod.h +++ b/sfall/Modules/AmmoMod.h @@ -29,6 +29,8 @@ public: void init(); static int formula; + static void DamageGlovz(fo::ComputeAttackResult &ctd, DWORD* accumulatedDamage, int rounds, int armorDT, int armorDR, int bonusRangedDamage, int multiplyDamage, int difficulty); + static void DamageYAAM(fo::ComputeAttackResult &ctd, DWORD* accumulatedDamage, int rounds, int armorDT, int armorDR, int bonusRangedDamage,int multiplyDamage, int difficulty); }; } diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index 23c5a679..b9a607b8 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -2172,7 +2172,7 @@ void BugFixes::init() // Display a pop-up messages box about death from radiation HookCall(0x42D733, process_rads_hook); - // Fix for AI not checking chem_primary_desire setting in AI.txt for drug use preference + // Fix for AI not taking chem_primary_desire in AI.txt as drug use preference when using drugs in their inventory if (GetConfigInt("Misc", "AIDrugUsePerfFix", 0)) { dlog("Applying AI drug use preference fix.", DL_INIT); MakeCall(0x42869D, ai_check_drugs_hack_break); diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index add90814..198c730c 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -81,6 +81,7 @@ static HooksInjectInfo injectHooks[] = { {HOOK_DESCRIPTIONOBJ, Inject_DescriptionObjHook, false}, {HOOK_USESKILLON, Inject_UseSkillOnHook, false}, {HOOK_ONEXPLOSION, Inject_OnExplosionHook, false}, + {HOOK_SUBCOMBATDAMAGE, Inject_SubCombatDamageHook, false}, }; bool HookScripts::injectAllHooks; diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index cebf3d7b..b80f62d3 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -63,6 +63,7 @@ enum HookType HOOK_DESCRIPTIONOBJ = 34, HOOK_USESKILLON = 35, HOOK_ONEXPLOSION = 36, + HOOK_SUBCOMBATDAMAGE = 37, HOOK_COUNT };