From 0a8a28b80c051d7fa0037e76f8632d8d2fb7b23c Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 6 Sep 2021 07:44:38 +0800 Subject: [PATCH] Moved some functions from AI.cpp to AIHelpers.cpp --- artifacts/scripting/hookscripts.md | 6 ++-- sfall/FalloutEngine/Enums.h | 23 ++++++------ sfall/Game/AI/AIHelpers.cpp | 57 ++++++++++++++++++++++++++++++ sfall/Game/AI/AIHelpers.h | 26 ++++++++++++++ sfall/Modules/AI.cpp | 38 ++------------------ sfall/Modules/AI.h | 5 --- sfall/ReplacementFuncs.h | 12 +++++++ sfall/ddraw.vcxproj | 2 ++ sfall/ddraw.vcxproj.filters | 9 +++++ sfall/main.cpp | 14 +------- 10 files changed, 127 insertions(+), 65 deletions(-) create mode 100644 sfall/Game/AI/AIHelpers.cpp create mode 100644 sfall/Game/AI/AIHelpers.h diff --git a/artifacts/scripting/hookscripts.md b/artifacts/scripting/hookscripts.md index 7b61b8be..8d5fa6d6 100644 --- a/artifacts/scripting/hookscripts.md +++ b/artifacts/scripting/hookscripts.md @@ -143,7 +143,8 @@ int ret0 - The new AP cost #### `HOOK_DEATHANIM1 (hs_deathanim1.int)` -Runs before Fallout tries to calculate the death animation. Lets you switch out which weapon Fallout sees.
+Runs before Fallout tries to calculate the death animation. Lets you switch out which weapon Fallout sees. + Does not run for critters in the knockdown/out state. ``` @@ -161,7 +162,8 @@ int ret0 - The pid of an object to override the attacking weapon with #### `HOOK_DEATHANIM2 (hs_deathanim2.int)` Runs after Fallout has calculated the death animation. Lets you set your own custom frame id, so more powerful than `HOOK_DEATHANIM1`, but performs no validation.
-When using `critter_dmg` function, this script will also run. In that case weapon pid will be -1 and attacker will point to an object with `obj_art_fid == 0x20001F5`.
+When using `critter_dmg` function, this script will also run. In that case weapon pid will be -1 and attacker will point to an object with `obj_art_fid == 0x20001F5`. + Does not run for critters in the knockdown/out state. ``` diff --git a/sfall/FalloutEngine/Enums.h b/sfall/FalloutEngine/Enums.h index 3c7d81dc..ba3a6002 100644 --- a/sfall/FalloutEngine/Enums.h +++ b/sfall/FalloutEngine/Enums.h @@ -525,15 +525,14 @@ enum class ScenerySubType : long enum Stat : long { - STAT_st = 0, - STAT_pe = 1, - STAT_en = 2, - STAT_ch = 3, - STAT_iq = 4, - STAT_ag = 5, - STAT_lu = 6, - /// strength, perception, endurance, charisma, intelligence, agility, - /// luck, // luck MUST be the last basic stat + STAT_st = 0, // strength + STAT_pe = 1, // perception + STAT_en = 2, // endurance + STAT_ch = 3, // charisma + STAT_iq = 4, // intelligence + STAT_ag = 5, // agility + STAT_lu = 6, // luck + // derived stats STAT_max_hit_points = 7, STAT_max_move_points = 8, @@ -562,14 +561,18 @@ enum Stat : long STAT_rad_resist = 31, STAT_poison_resist = 32, // poison_resist MUST be the last derived stat + // non-derived stats STAT_age = 33, STAT_gender = 34, // gender MUST be the last non-derived stat + STAT_current_hp = 35, STAT_current_poison = 36, STAT_current_rad = 37, - STAT_real_max_stat = 38 + + STAT_real_max_stat = 38, + STAT_base_count = 7 }; namespace Scripts { diff --git a/sfall/Game/AI/AIHelpers.cpp b/sfall/Game/AI/AIHelpers.cpp new file mode 100644 index 00000000..d429e9cb --- /dev/null +++ b/sfall/Game/AI/AIHelpers.cpp @@ -0,0 +1,57 @@ +/* + * sfall + * Copyright (C) 2008-2021 The sfall team + * + */ + +//#include "..\..\main.h" +#include "..\..\FalloutEngine\Fallout2.h" + +#include "..\..\Modules\AI.h" + +#include "..\items.h" + +#include "AIHelpers.h" + +namespace game +{ +namespace ai +{ + +namespace sf = sfall; + +// Returns the friendly critter or any blocking object in the line of fire +fo::GameObject* AIHelpers::CheckShootAndFriendlyInLineOfFire(fo::GameObject* object, long targetTile, long team) { + if (object && object->IsCritter() && object->critter.teamNum != team) { // is not friendly fire + long objTile = object->tile; + if (objTile == targetTile) return nullptr; + + if (object->flags & fo::ObjectFlag::MultiHex) { + long dir = fo::func::tile_dir(objTile, targetTile); + objTile = fo::func::tile_num_in_direction(objTile, dir, 1); + if (objTile == targetTile) return nullptr; // just in case + } + // continue checking the line of fire from object tile to targetTile + fo::GameObject* obj = object; // for ignoring the object (multihex) when building the path + fo::func::make_straight_path_func(object, objTile, targetTile, 0, (DWORD*)&obj, 0x20, (void*)fo::funcoffs::obj_shoot_blocking_at_); + + object = CheckShootAndFriendlyInLineOfFire(obj, targetTile, team); + } + return object; // friendly critter, any object or null +} + +// Returns the friendly critter in the line of fire +fo::GameObject* AIHelpers::CheckFriendlyFire(fo::GameObject* target, fo::GameObject* attacker) { + fo::GameObject* object = nullptr; + fo::func::make_straight_path_func(attacker, attacker->tile, target->tile, 0, (DWORD*)&object, 0x20, (void*)fo::funcoffs::obj_shoot_blocking_at_); + object = CheckShootAndFriendlyInLineOfFire(object, target->tile, attacker->critter.teamNum); + return (object && object->IsCritter()) ? object : nullptr; // 0 - if there are no friendly critters +} + +bool AIHelpers::AttackInRange(fo::GameObject* source, fo::GameObject* weapon, long distance) { + if (Items::item_weapon_range(source, weapon, fo::AttackType::ATKTYPE_RWEAPON_PRIMARY) >= distance) return true; + return (Items::item_weapon_range(source, weapon, fo::AttackType::ATKTYPE_RWEAPON_SECONDARY) >= distance); +} + +} +} diff --git a/sfall/Game/AI/AIHelpers.h b/sfall/Game/AI/AIHelpers.h new file mode 100644 index 00000000..f5102992 --- /dev/null +++ b/sfall/Game/AI/AIHelpers.h @@ -0,0 +1,26 @@ +/* + * sfall + * Copyright (C) 2008-2021 The sfall team + * + */ + +#pragma once + +namespace game +{ +namespace ai +{ + +class AIHelpers { +public: + // Returns the friendly critter or any blocking object in the line of fire + static fo::GameObject* CheckShootAndFriendlyInLineOfFire(fo::GameObject* object, long targetTile, long team); + + // Returns the friendly critter in the line of fire + static fo::GameObject* CheckFriendlyFire(fo::GameObject* target, fo::GameObject* attacker); + + static bool AttackInRange(fo::GameObject* source, fo::GameObject* weapon, long distance); +}; + +} +} diff --git a/sfall/Modules/AI.cpp b/sfall/Modules/AI.cpp index 156d7bf5..183e8cf1 100644 --- a/sfall/Modules/AI.cpp +++ b/sfall/Modules/AI.cpp @@ -22,6 +22,7 @@ #include "..\FalloutEngine\Fallout2.h" #include "LoadGameHook.h" +#include "..\Game\AI\AIHelpers.h" #include "..\Game\combatAI.h" #include "..\Game\items.h" @@ -35,39 +36,6 @@ using namespace fo::Fields; static std::unordered_map targets; static std::unordered_map sources; -// Returns the friendly critter or any blocking object in the line of fire -fo::GameObject* AI::CheckShootAndFriendlyInLineOfFire(fo::GameObject* object, long targetTile, long team) { - if (object && object->IsCritter() && object->critter.teamNum != team) { // is not friendly fire - long objTile = object->tile; - if (objTile == targetTile) return nullptr; - - if (object->flags & fo::ObjectFlag::MultiHex) { - long dir = fo::func::tile_dir(objTile, targetTile); - objTile = fo::func::tile_num_in_direction(objTile, dir, 1); - if (objTile == targetTile) return nullptr; // just in case - } - // continue checking the line of fire from object tile to targetTile - fo::GameObject* obj = object; // for ignoring the object (multihex) when building the path - fo::func::make_straight_path_func(object, objTile, targetTile, 0, (DWORD*)&obj, 0x20, (void*)fo::funcoffs::obj_shoot_blocking_at_); - - object = CheckShootAndFriendlyInLineOfFire(obj, targetTile, team); - } - return object; // friendly critter, any object or null -} - -// Returns the friendly critter in the line of fire -fo::GameObject* AI::CheckFriendlyFire(fo::GameObject* target, fo::GameObject* attacker) { - fo::GameObject* object = nullptr; - fo::func::make_straight_path_func(attacker, attacker->tile, target->tile, 0, (DWORD*)&object, 0x20, (void*)fo::funcoffs::obj_shoot_blocking_at_); - object = CheckShootAndFriendlyInLineOfFire(object, target->tile, attacker->critter.teamNum); - return (object && object->IsCritter()) ? object : nullptr; // 0 - if there are no friendly critters -} - -bool AI::AttackInRange(fo::GameObject* source, fo::GameObject* weapon, long distance) { - if (game::Items::item_weapon_range(source, weapon, fo::AttackType::ATKTYPE_RWEAPON_PRIMARY) >= distance) return true; - return (game::Items::item_weapon_range(source, weapon, fo::AttackType::ATKTYPE_RWEAPON_SECONDARY) >= distance); -} - //////////////////////////////////////////////////////////////////////////////// static void __declspec(naked) ai_try_attack_hook_FleeFix() { @@ -281,7 +249,7 @@ static long __fastcall ai_try_attack_switch_fix(fo::GameObject* target, long &hi // is using a close range weapon? long wType = fo::func::item_w_subtype(item, fo::AttackType::ATKTYPE_RWEAPON_PRIMARY); if (wType <= fo::AttackSubType::MELEE) { // unarmed and melee weapons, check the distance before switching - if (!AI::AttackInRange(source, item, fo::func::obj_dist(source, target))) return -1; // target out of range, exit ai_try_attack_ + if (!game::ai::AIHelpers::AttackInRange(source, item, fo::func::obj_dist(source, target))) return -1; // target out of range, exit ai_try_attack_ } return 1; // all good, execute vanilla behavior of ai_switch_weapons_ function } @@ -526,7 +494,7 @@ fix: //////////////////////////////////////////////////////////////////////////////// static bool __fastcall RollFriendlyFire(fo::GameObject* target, fo::GameObject* attacker) { - if (AI::CheckFriendlyFire(target, attacker)) { + if (game::ai::AIHelpers::CheckFriendlyFire(target, attacker)) { long dice = fo::func::roll_random(1, 10); return (fo::func::stat_level(attacker, fo::STAT_iq) >= dice); // true - is friendly } diff --git a/sfall/Modules/AI.h b/sfall/Modules/AI.h index 6dae5c5e..6472ddba 100644 --- a/sfall/Modules/AI.h +++ b/sfall/Modules/AI.h @@ -30,11 +30,6 @@ public: const char* name() { return "AI"; } void init(); - static fo::GameObject* CheckShootAndFriendlyInLineOfFire(fo::GameObject* object, long targetTile, long team); - static fo::GameObject* CheckFriendlyFire(fo::GameObject* target, fo::GameObject* attacker); - - static bool AttackInRange(fo::GameObject* source, fo::GameObject* weapon, long distance); - static fo::GameObject* __stdcall AIGetLastAttacker(fo::GameObject* target); static fo::GameObject* __stdcall AIGetLastTarget(fo::GameObject* source); }; diff --git a/sfall/ReplacementFuncs.h b/sfall/ReplacementFuncs.h index 02d79e4e..6dbf983e 100644 --- a/sfall/ReplacementFuncs.h +++ b/sfall/ReplacementFuncs.h @@ -15,3 +15,15 @@ #include "Game\skills.h" #include "Game\stats.h" #include "Game\tilemap.h" + +__inline void InitReplacementHacks() { + game::gui::Render::init(); + game::gui::Text::init(); + + game::CombatAI::init(); + game::Inventory::init(); + game::Items::init(); + game::Skills::init(); + game::Stats::init(); + game::Tilemap::init(); +} diff --git a/sfall/ddraw.vcxproj b/sfall/ddraw.vcxproj index 20175f03..9b14d50f 100644 --- a/sfall/ddraw.vcxproj +++ b/sfall/ddraw.vcxproj @@ -292,6 +292,7 @@ + @@ -406,6 +407,7 @@ + diff --git a/sfall/ddraw.vcxproj.filters b/sfall/ddraw.vcxproj.filters index 0e928307..8daa8cee 100644 --- a/sfall/ddraw.vcxproj.filters +++ b/sfall/ddraw.vcxproj.filters @@ -25,6 +25,9 @@ {e19ca1b6-f754-47a9-9a6d-5ce44592d8ab} + + {6ce67248-1c25-4dae-967c-3078b65838e1} + @@ -358,6 +361,9 @@ Game\GUI + + Game\AI + @@ -660,6 +666,9 @@ Game\GUI + + Game\AI + diff --git a/sfall/main.cpp b/sfall/main.cpp index 48e32213..ba64238f 100644 --- a/sfall/main.cpp +++ b/sfall/main.cpp @@ -100,19 +100,7 @@ DWORD HRPAddress(DWORD addr) { return (hrpDLLBaseAddr | (addr & 0xFFFFF)); } -char falloutConfigName[65] = {0}; - -void InitReplacementHacks() { - game::gui::Render::init(); - game::gui::Text::init(); - - game::CombatAI::init(); - game::Inventory::init(); - game::Items::init(); - game::Skills::init(); - game::Stats::init(); - game::Tilemap::init(); -} +char falloutConfigName[65]; static void InitModules() { dlogr("In InitModules", DL_MAIN);