diff --git a/sfall/Game/combatAI.cpp b/sfall/Game/combatAI.cpp index 0fd2de4b..355d4459 100644 --- a/sfall/Game/combatAI.cpp +++ b/sfall/Game/combatAI.cpp @@ -67,7 +67,7 @@ void __stdcall CombatAI::ai_check_drugs(fo::GameObject* source) { long minHP = (hpPercent * fo::func::stat_level(source, fo::Stat::STAT_max_hit_points)) / 100; - // [FIX] for AI not checking minimum hp properly for using stimpaks (prevents premature fleeing) + // [FIX] for AI not checking minimum hp properly for using healing drugs (prevents premature fleeing) if (cap->min_hp > minHP) minHP = cap->min_hp; while (fo::func::stat_level(source, fo::Stat::STAT_current_hp) < minHP && source->critter.movePoints >= aiUseItemAPCost) { @@ -110,7 +110,7 @@ void __stdcall CombatAI::ai_check_drugs(fo::GameObject* source) { while (item->protoId != cap->chem_primary_desire[counter]) if (++counter > 2) break; if (counter <= 2) break; // there is a match - // [FIX] for AI not taking chem_primary_desire in AI.txt as a preference when using drugs in the inventory + // [FIX] for AI not taking chem_primary_desire in AI.txt as a preference list when using drugs in the inventory if (drugUsePerfFixMode == 1) { item = fo::func::inven_find_type(source, fo::ItemType::item_type_drug, &slot); if (!item) { @@ -121,7 +121,7 @@ void __stdcall CombatAI::ai_check_drugs(fo::GameObject* source) { } } while (counter < 3); } else { - // if the durg is equal to the first item of preference, then check the next two (vanilla behavior) + // if the drug is equal to the item in the preference list, then check the next (vanilla behavior) while (item->protoId == cap->chem_primary_desire[counter]) if (++counter > 2) break; } @@ -153,7 +153,7 @@ void __stdcall CombatAI::ai_check_drugs(fo::GameObject* source) { } } // search for drugs on the map - if (lastItem || (!drugWasUsed /*&& noInvenDrug*/)) { + if (lastItem || (!drugWasUsed && noInvenDrug)) { do { if (!lastItem) lastItem = fo::func::ai_search_environ(source, fo::ItemType::item_type_drug); if (!lastItem) lastItem = fo::func::ai_search_environ(source, fo::ItemType::item_type_misc_item); @@ -191,10 +191,25 @@ static void __declspec(naked) ai_check_drugs_hack() { } } +static void __declspec(naked) ai_can_use_drug_hack() { + __asm { + push ecx; // item + call Items::IsHealingItem; + pop ecx; + test al, al; + retn; + } +} + void CombatAI::init() { - // Replace ai_check_drugs_ function + // Replace ai_check_drugs_ function for code fixes and checking healing items sf::MakeJump(fo::funcoffs::ai_check_drugs_, ai_check_drugs_hack); // 0x428480 + // Change ai_can_use_drug_ function code to check healing items + sf::MakeCall(0x429BDE, ai_can_use_drug_hack, 6); + sf::SafeWrite8(0x429BE9, sf::CodeType::JumpNZ); // jz > jnz + sf::SafeWrite8(0x429BF1, sf::CodeType::JumpShort); // jnz > jmp + drugUsePerfFixMode = sf::IniReader::GetConfigInt("Misc", "AIDrugUsePerfFix", 0); if (drugUsePerfFixMode > 0) sf::dlogr("Applying AI drug use preference fix.", DL_FIX); } diff --git a/sfall/Game/items.cpp b/sfall/Game/items.cpp index f0b0ab62..a01bd07e 100644 --- a/sfall/Game/items.cpp +++ b/sfall/Game/items.cpp @@ -26,16 +26,23 @@ static constexpr int reloadCostAP = 2; // engine default reload AP cost static std::array healingItemPids = {fo::PID_STIMPAK, fo::PID_SUPER_STIMPAK, fo::PID_HEALING_POWDER}; -void Items::SetHealingPID(long index, long pid) { - /*if (index >= 0 && index < 3)*/ healingItemPids[index] = pid; +long Items::GetHealingPID(long index) { + return healingItemPids[index]; } -bool Items::IsHealingItem(fo::GameObject* item) { - if (std::find(healingItemPids.cbegin(), healingItemPids.cend(), item->protoId) != healingItemPids.cend()) return true; +void Items::SetHealingPID(long index, long pid) { + healingItemPids[index] = pid; +} + +bool __fastcall Items::IsHealingItem(fo::GameObject* item) { + //for each (long pid in healingItemPids) if (pid == item->protoId) return true; + if (healingItemPids[0] == item->protoId || healingItemPids[1] == item->protoId || healingItemPids[2] == item->protoId) { + return true; + } fo::Proto* proto; if (fo::GetProto(item->protoId, &proto)) { - return ((proto->item.flagsExt & fo::ItemFlags::HealingItem) != 0); // TODO: check asm code + return (proto->item.flagsExt & fo::ItemFlags::HealingItem) != 0; } return false; } @@ -54,8 +61,10 @@ bool Items::UseDrugItemFunc(fo::GameObject* source, fo::GameObject* item) { // Implementation of item_d_take_ engine function with the HOOK_USEOBJON hook long Items::item_d_take_drug(fo::GameObject* source, fo::GameObject* item) { - if (sf::UseObjOnHook_Invoke(source, item, source) == -1) return -1; - return fo::func::item_d_take_drug(source, item); + if (sf::UseObjOnHook_Invoke(source, item, source) == -1) { // default handler + return fo::func::item_d_take_drug(source, item); + } + return -1; // cancel the drug use } long Items::item_count(fo::GameObject* who, fo::GameObject* item) { diff --git a/sfall/Game/items.h b/sfall/Game/items.h index fc22f677..df25839e 100644 --- a/sfall/Game/items.h +++ b/sfall/Game/items.h @@ -13,9 +13,10 @@ class Items { public: static void init(); + static long GetHealingPID(long index); static void SetHealingPID(long index, long pid); - static bool IsHealingItem(fo::GameObject* item); + static bool __fastcall IsHealingItem(fo::GameObject* item); // True - use failed static bool UseDrugItemFunc(fo::GameObject* source, fo::GameObject* item); diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index f96757a7..d70ced29 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -3645,7 +3645,7 @@ void BugFixes::init() //if (drugUsePerfFix > 0) { // dlog("Applying AI drug use preference fix.", DL_FIX); // if (drugUsePerfFix == 1) { - // // Fix for AI not taking chem_primary_desire in AI.txt as drug use preference when using drugs in their inventory + // // Fix for AI not taking chem_primary_desire in AI.txt as a preference list when using drugs in the inventory // MakeCall(0x42869D, ai_check_drugs_hack_break); // MakeCall(0x4286AB, ai_check_drugs_hack_check, 1); // MakeCall(0x4286C7, ai_check_drugs_hack_use); diff --git a/sfall/Modules/FileSystem.cpp b/sfall/Modules/FileSystem.cpp index cc8808f0..04476801 100644 --- a/sfall/Modules/FileSystem.cpp +++ b/sfall/Modules/FileSystem.cpp @@ -712,6 +712,11 @@ void FileSystem::init() { MakeJump(0x47CCE2, FSLoadHook); // LoadGame_ LoadGameHook::OnGameReset() += FileSystemReset; + + // Fix crash if the filename contains a '%' character (relevant to SFX files) + // xfopen_ - remove sprintf_ function calls that do nothing (probably just checking the filename for the '%' formatting char?) + BlockCall(0x4DEF12); + BlockCall(0x4DEF84); } } diff --git a/sfall/main.cpp b/sfall/main.cpp index 68a8145f..a9761adf 100644 --- a/sfall/main.cpp +++ b/sfall/main.cpp @@ -118,11 +118,17 @@ static void InitModules() { // initialize all modules manager.add(); // fixes should be applied at the beginning + manager.add(); manager.add(); manager.add(); manager.add(); manager.add(); manager.add(); + + manager.add(); + manager.add(); + manager.add(); + manager.add(); manager.add(); manager.add(); @@ -136,8 +142,7 @@ static void InitModules() { manager.add(); manager.add(); manager.add(); - manager.add(); - manager.add(); + manager.add(); manager.add(); manager.add(); @@ -151,12 +156,10 @@ static void InitModules() { manager.add(); // should be loaded before PartyControl manager.add(); manager.add(); - manager.add(); manager.add(); manager.add(); - manager.add(); manager.add(); - // + manager.add(); manager.add(); manager.add();