diff --git a/MPClient/DebugEditor.Designer.cs b/MPClient/DebugEditor.Designer.cs index 73b61bc9..c8af1d46 100644 --- a/MPClient/DebugEditor.Designer.cs +++ b/MPClient/DebugEditor.Designer.cs @@ -180,6 +180,7 @@ this.Controls.Add(this.dataGridView1); this.MinimumSize = new System.Drawing.Size(450, 300); this.Name = "DebugEditor"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "sfall Debug Editor"; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.DebugEditor_FormClosing); ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); diff --git a/MPClient/EditorWindow.Designer.cs b/MPClient/EditorWindow.Designer.cs index 052916b1..fa6b3804 100644 --- a/MPClient/EditorWindow.Designer.cs +++ b/MPClient/EditorWindow.Designer.cs @@ -111,6 +111,7 @@ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; this.MinimumSize = new System.Drawing.Size(300, 200); this.Name = "EditorWindow"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Edit Values"; ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); this.ResumeLayout(false); diff --git a/artifacts/mods/gl_partycontrol.int b/artifacts/mods/gl_partycontrol.int index 9bcc1f98..864e2ed3 100644 Binary files a/artifacts/mods/gl_partycontrol.int and b/artifacts/mods/gl_partycontrol.int differ diff --git a/artifacts/mods/gl_partycontrol.ssl b/artifacts/mods/gl_partycontrol.ssl index 559b7f16..fe6d42b2 100644 --- a/artifacts/mods/gl_partycontrol.ssl +++ b/artifacts/mods/gl_partycontrol.ssl @@ -109,8 +109,8 @@ procedure invenwield_handler begin event := get_sfall_arg; // Fix weapon duplication when equipping in combat - if (event and AllowControl(obj_pid(critter))) then begin - set_flags(item, get_flags(item) bwand bwnot(FLAG_LEFT_HAND bwor FLAG_RIGHT_HAND)); + if (event and slot == INVEN_TYPE_RIGHT_HAND and AllowControl(obj_pid(critter))) then begin + set_flags(item, get_flags(item) bwand bwnot(FLAG_LEFT_HAND)); end end diff --git a/sfall/Modules/Combat.cpp b/sfall/Modules/Combat.cpp index 64a77452..87de50f0 100644 --- a/sfall/Modules/Combat.cpp +++ b/sfall/Modules/Combat.cpp @@ -21,6 +21,7 @@ #include "..\main.h" #include "..\FalloutEngine\Fallout2.h" +#include "HookScripts.h" #include "LoadGameHook.h" #include "Objects.h" @@ -48,6 +49,87 @@ static bool hookedAimedShot; static std::vector disabledAS; static std::vector forcedAS; +static DWORD __fastcall add_check_for_item_ammo_cost(register fo::GameObject* weapon, DWORD hitMode) { + DWORD rounds = 1; + + DWORD anim = fo::func::item_w_anim_weap(weapon, hitMode); + if (anim == fo::Animation::ANIM_fire_burst || anim == fo::Animation::ANIM_fire_continuous) { + rounds = fo::func::item_w_rounds(weapon); // ammo in burst + } + if (HookScripts::IsInjectHook(HOOK_AMMOCOST)) { + AmmoCostHook_Script(1, weapon, &rounds); // get rounds cost from hook + } else if (rounds == 1) { + fo::func::item_w_compute_ammo_cost(weapon, &rounds); + } + DWORD currAmmo = fo::func::item_w_curr_ammo(weapon); + + DWORD cost = 1; // default cost + if (currAmmo > 0) { + cost = rounds / currAmmo; + if (rounds % currAmmo) cost++; // round up + } + return (cost > currAmmo) ? 0 : 1; // 0 - this will force "Out of ammo", 1 - this will force success (enough ammo) +} + +// adds check for weapons which require more than 1 ammo for single shot (super cattle prod & mega power fist) and burst rounds +static void __declspec(naked) combat_check_bad_shot_hook() { + __asm { + push edx; + push ecx; // weapon + mov edx, edi; // hitMode + call add_check_for_item_ammo_cost; + pop ecx; + pop edx; + retn; + } +} + +// check if there is enough ammo to shoot +static void __declspec(naked) ai_search_inven_weap_hook() { + using namespace fo; + __asm { + push ecx; + mov ecx, eax; // weapon + mov edx, ATKTYPE_RWEAPON_PRIMARY; // hitMode + call add_check_for_item_ammo_cost; + mov ebx, eax; // result + mov ecx, esi; + mov edx, ATKTYPE_RWEAPON_SECONDARY; + call add_check_for_item_ammo_cost; + and eax, ebx; // enough ammo? + pop ecx; + retn; + } +} + +static DWORD __fastcall divide_burst_rounds_by_ammo_cost(fo::GameObject* weapon, register DWORD currAmmo, DWORD burstRounds) { + DWORD rounds = 1; // default multiply + + if (HookScripts::IsInjectHook(HOOK_AMMOCOST)) { + rounds = burstRounds; // rounds in burst + AmmoCostHook_Script(2, weapon, &rounds); + } + + DWORD cost = burstRounds * rounds; // so much ammo is required for this burst + if (cost > currAmmo) cost = currAmmo; // if cost ammo more than current ammo, set it to current + + return (cost / rounds); // divide back to get proper number of rounds for damage calculations +} + +static void __declspec(naked) compute_spray_hack() { + __asm { + push edx; // weapon + push ecx; // current ammo in weapon + xchg ecx, edx; + push eax; // eax - rounds in burst attack, need to set ebp + call divide_burst_rounds_by_ammo_cost; + mov ebp, eax; // overwriten code + pop ecx; + pop edx; + retn; + } +} + static double ApplyModifiers(std::vector* mods, fo::GameObject* object, double val) { for (DWORD i = 0; i < mods->size(); i++) { KnockbackModifier* mod = &(*mods)[i]; @@ -308,6 +390,11 @@ void Combat::init() { // Actually disables all secondary attacks for the critter, regardless of whether the weapon has a burst attack MakeCall(0x429E44, ai_pick_hit_mode_hack, 1); // NoBurst + if (GetConfigInt("Misc", "CheckWeaponAmmoCost", 0)) { + HookCall(0x4266E9, combat_check_bad_shot_hook); + MakeCall(0x4234B3, compute_spray_hack, 1); + HookCall(0x429A37, ai_search_inven_weap_hook); + } LoadGameHook::OnGameReset() += Combat_OnGameLoad; } diff --git a/sfall/Modules/Inventory.cpp b/sfall/Modules/Inventory.cpp index 15cda2d7..1dafd318 100644 --- a/sfall/Modules/Inventory.cpp +++ b/sfall/Modules/Inventory.cpp @@ -388,68 +388,6 @@ static void __declspec(naked) inven_ap_cost_hack() { } } -static DWORD __fastcall add_check_for_item_ammo_cost(register fo::GameObject* weapon, DWORD hitMode) { - DWORD rounds = 1; - DWORD anim = fo::func::item_w_anim_weap(weapon, hitMode); - if (anim == fo::Animation::ANIM_fire_burst || anim == fo::Animation::ANIM_fire_continuous) { - rounds = fo::func::item_w_rounds(weapon); // ammo in burst - } - - if (HookScripts::IsInjectHook(HOOK_AMMOCOST)) { - AmmoCostHook_Script(1, weapon, &rounds); // get rounds cost from hook - } - - DWORD currAmmo = fo::func::item_w_curr_ammo(weapon); - - DWORD cost = 1; // default cost - if (currAmmo > 0) cost = (DWORD)ceilf((float)rounds / currAmmo); - - return (cost > currAmmo) ? 0 : 1; // 0 - this will force "Out of ammo", 1 - this will force success (enough ammo) -} - -// adds check for weapons which require more than 1 ammo for single shot (super cattle prod & mega power fist) and burst rounds -static void __declspec(naked) combat_check_bad_shot_hook() { - __asm { - push edx; - push ebx; - push ecx; // weapon - mov edx, edi; // hitMode - call add_check_for_item_ammo_cost; - pop ecx; - pop ebx; - pop edx; - retn; - } -} - -static DWORD __fastcall divide_burst_rounds_by_ammo_cost(fo::GameObject* weapon, register DWORD currAmmo, DWORD burstRounds) { - DWORD rounds = 1; // default multiply - - if (HookScripts::IsInjectHook(HOOK_AMMOCOST)) { - rounds = burstRounds; // rounds in burst - AmmoCostHook_Script(2, weapon, &rounds); - } - - DWORD cost = burstRounds * rounds; // so much ammo is required for this burst - if (cost > currAmmo) cost = currAmmo; // if cost ammo more than current ammo, set it to current - - return (cost / rounds); // divide back to get proper number of rounds for damage calculations -} - -static void __declspec(naked) compute_spray_hack() { - __asm { - push edx; // weapon - push ecx; // current ammo in weapon - xchg ecx, edx; - push eax; // eax - rounds in burst attack, need to set ebp - call divide_burst_rounds_by_ammo_cost; - mov ebp, eax; // overwriten code - pop ecx; - pop edx; - retn; - } -} - static void __declspec(naked) SetDefaultAmmo() { using namespace fo; using namespace Fields; @@ -783,11 +721,6 @@ void Inventory::init() { MakeCall(0x49C3D9, SuperStimFix); } - if (GetConfigInt("Misc", "CheckWeaponAmmoCost", 0)) { - HookCall(0x4266E9, combat_check_bad_shot_hook); - MakeCall(0x4234B3, compute_spray_hack, 1); - } - reloadWeaponKey = GetConfigInt("Input", "ReloadWeaponKey", 0); if (GetConfigInt("Misc", "StackEmptyWeapons", 0)) {