mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Refactored HOOK_WITHINPERCEPTION code as 4.x
Renamed engine function reimplementations with "sfgame_" prefix. Added AIpref defines and AIcap struct.
This commit is contained in:
@@ -747,6 +747,79 @@ namespace WinFlags {
|
||||
};
|
||||
}
|
||||
|
||||
namespace AIpref {
|
||||
enum distance : long
|
||||
{
|
||||
DIST_stay_close = 0,
|
||||
DIST_charge = 1,
|
||||
DIST_snipe = 2,
|
||||
DIST_on_your_own = 3,
|
||||
DIST_stay = 4
|
||||
};
|
||||
|
||||
enum disposition : long
|
||||
{
|
||||
DISP_none = -1,
|
||||
DISP_custom = 0,
|
||||
DISP_coward = 1,
|
||||
DISP_defensive = 2,
|
||||
DISP_aggressive = 3,
|
||||
DISP_berserk = 4
|
||||
};
|
||||
|
||||
enum attack_who : long
|
||||
{
|
||||
ATKWHO_whomever_attacking_me = 0,
|
||||
ATKWHO_strongest = 1,
|
||||
ATKWHO_weakest = 2,
|
||||
ATKWHO_whomever = 3,
|
||||
ATKWHO_closest = 4,
|
||||
};
|
||||
|
||||
enum run_away_mode : long
|
||||
{
|
||||
AWAY_none = -1, // get the value from the cap.min_hp (in cai_get_min_hp_)
|
||||
AWAY_coward = 0, // 0%
|
||||
AWAY_finger_hurts = 1, // 25% of the lost amount of health
|
||||
AWAY_bleeding = 2, // 40% of the lost amount of health
|
||||
AWAY_not_feeling_good = 3, // 60% of the lost amount of health
|
||||
AWAY_tourniquet = 4, // 75% of the lost amount of health
|
||||
AWAY_never = 5 // 100%
|
||||
};
|
||||
|
||||
enum weapon_pref : long
|
||||
{
|
||||
WEAPON_no_pref = 0,
|
||||
WEAPON_melee = 1,
|
||||
WEAPON_melee_over_ranged = 2,
|
||||
WEAPON_ranged_over_melee = 3,
|
||||
WEAPON_ranged = 4,
|
||||
WEAPON_unarmed = 5,
|
||||
WEAPON_unarmed_over_thrown = 6, // not available in party member control panel
|
||||
WEAPON_random = 7 // not available in party member control panel
|
||||
};
|
||||
|
||||
enum area_attack_mode : long
|
||||
{
|
||||
AREA_no_pref = -1, // special logic for NPC (not available in party member control panel)
|
||||
AREA_always = 0,
|
||||
AREA_sometimes = 1, // use random value from cap.secondary_freq
|
||||
AREA_be_sure = 2, // 85% hit chance
|
||||
AREA_be_careful = 3, // 50% hit chance
|
||||
AREA_be_absolutely_sure = 4, // 95% hit chance
|
||||
};
|
||||
|
||||
enum chem_use_mode : long
|
||||
{
|
||||
CHEM_clean = 0,
|
||||
CHEM_stims_when_hurt_little = 1,
|
||||
CHEM_stims_when_hurt_lots = 2,
|
||||
CHEM_sometimes = 3,
|
||||
CHEM_anytime = 4,
|
||||
CHEM_always = 5,
|
||||
};
|
||||
}
|
||||
|
||||
enum QueueType : long
|
||||
{
|
||||
drug_effect_event = 0, // critter use drug
|
||||
|
||||
@@ -891,6 +891,43 @@ struct LSData {
|
||||
char mapName[16];
|
||||
};
|
||||
|
||||
struct AIcap {
|
||||
long name;
|
||||
long packet_num;
|
||||
long max_dist;
|
||||
long min_to_hit;
|
||||
long min_hp;
|
||||
long aggression;
|
||||
long hurt_too_much;
|
||||
long secondary_freq;
|
||||
long called_freq;
|
||||
long font;
|
||||
long color;
|
||||
long outline_color;
|
||||
long chance;
|
||||
long combat_message_data[24];
|
||||
long area_attack_mode;
|
||||
long run_away_mode;
|
||||
long best_weapon;
|
||||
long distance;
|
||||
long attack_who;
|
||||
long chem_use;
|
||||
long chem_primary_desire;
|
||||
long chem_primary_desire1;
|
||||
long chem_primary_desire2;
|
||||
long disposition;
|
||||
long body_type;
|
||||
long general_type;
|
||||
|
||||
inline AIpref::distance getDistance() {
|
||||
return (AIpref::distance)distance;
|
||||
}
|
||||
inline AIpref::run_away_mode getRunAwayMode() {
|
||||
return (AIpref::run_away_mode)run_away_mode;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Queue {
|
||||
DWORD time;
|
||||
long type;
|
||||
|
||||
@@ -386,7 +386,7 @@ void UpdateHeroArt() {
|
||||
}
|
||||
|
||||
// inventory function - setup pc FrmID and store at address _i_fid
|
||||
(*ptr_obj_dude)->artFid = Inventory_adjust_fid(); // adjust_fid_
|
||||
(*ptr_obj_dude)->artFid = sfgame_adjust_fid(); // adjust_fid_
|
||||
|
||||
*ptr_inven_dude = iD;
|
||||
*ptr_i_rhand = iR;
|
||||
|
||||
+50
-38
@@ -240,8 +240,8 @@ static void __declspec(naked) AfterHitRollHook() {
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of item_w_mp_cost_ engine function with the hook
|
||||
long __fastcall sf_item_w_mp_cost(TGameObj* source, long hitMode, long isCalled) {
|
||||
// Implementation of item_w_mp_cost_ engine function with the HOOK_CALCAPCOST hook
|
||||
long __fastcall sfgame_item_w_mp_cost(TGameObj* source, long hitMode, long isCalled) {
|
||||
long cost = fo_item_w_mp_cost(source, hitMode, isCalled);
|
||||
|
||||
BeginHook();
|
||||
@@ -921,7 +921,7 @@ skip:
|
||||
}
|
||||
|
||||
void __stdcall KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey) {
|
||||
if (!IsGameLoaded()) {
|
||||
if (!IsGameLoaded() || !HookHasScript(HOOK_KEYPRESS)) {
|
||||
return;
|
||||
}
|
||||
BeginHook();
|
||||
@@ -935,7 +935,7 @@ void __stdcall KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey) {
|
||||
}
|
||||
|
||||
void __stdcall MouseClickHook(DWORD button, bool pressed) {
|
||||
if (!IsGameLoaded()) {
|
||||
if (!IsGameLoaded() || !HookHasScript(HOOK_MOUSECLICK)) {
|
||||
return;
|
||||
}
|
||||
BeginHook();
|
||||
@@ -1003,15 +1003,13 @@ defaultHandler:
|
||||
}
|
||||
|
||||
// 4.x backport
|
||||
static long __fastcall PerceptionRangeHook_Script(TGameObj* watcher, TGameObj* target, int type) {
|
||||
long result = fo_is_within_perception(watcher, target);
|
||||
|
||||
static __forceinline long __stdcall PerceptionRangeHook_Script(TGameObj* watcher, TGameObj* target, int type, long result) {
|
||||
BeginHook();
|
||||
argCount = 4;
|
||||
|
||||
args[0] = (DWORD)watcher;
|
||||
args[1] = (DWORD)target;
|
||||
args[2] = result;
|
||||
args[2] = result; // engine result
|
||||
args[3] = type;
|
||||
|
||||
RunHookScript(HOOK_WITHINPERCEPTION);
|
||||
@@ -1022,9 +1020,18 @@ static long __fastcall PerceptionRangeHook_Script(TGameObj* watcher, TGameObj* t
|
||||
return result;
|
||||
}
|
||||
|
||||
// Implementation of is_within_perception_ engine function with the hook
|
||||
long __fastcall sf_is_within_perception(TGameObj* watcher, TGameObj* target) { // TODO: add type arg
|
||||
return PerceptionRangeHook_Script(watcher, target, 0);
|
||||
static long __stdcall PerceptionRangeHook_ScriptCheck(TGameObj* watcher, TGameObj* target, long result) { // TODO: add type arg
|
||||
if (!HookHasScript(HOOK_WITHINPERCEPTION)) return result;
|
||||
return PerceptionRangeHook_Script(watcher, target, 0, result);
|
||||
}
|
||||
|
||||
static long __fastcall PerceptionRange_Hook(TGameObj* watcher, TGameObj* target, int type) {
|
||||
return PerceptionRangeHook_Script(watcher, target, type, fo_is_within_perception(watcher, target));
|
||||
}
|
||||
|
||||
// Implementation of is_within_perception_ engine function with the HOOK_WITHINPERCEPTION hook
|
||||
long __stdcall sfgame_is_within_perception(TGameObj* watcher, TGameObj* target) { // TODO: add type arg
|
||||
return PerceptionRangeHook_ScriptCheck(watcher, target, fo_is_within_perception(watcher, target));
|
||||
}
|
||||
|
||||
static void __declspec(naked) PerceptionRangeHook() {
|
||||
@@ -1032,7 +1039,7 @@ static void __declspec(naked) PerceptionRangeHook() {
|
||||
push ecx;
|
||||
push 0;
|
||||
mov ecx, eax;
|
||||
call PerceptionRangeHook_Script;
|
||||
call PerceptionRange_Hook;
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
@@ -1043,7 +1050,7 @@ static void __declspec(naked) PerceptionRangeSeeHook() {
|
||||
push ecx;
|
||||
push 1;
|
||||
mov ecx, eax;
|
||||
call PerceptionRangeHook_Script;
|
||||
call PerceptionRange_Hook;
|
||||
pop ecx;
|
||||
cmp eax, 2;
|
||||
jne nevermind; // normal return
|
||||
@@ -1060,7 +1067,7 @@ static void __declspec(naked) PerceptionRangeHearHook() {
|
||||
push ecx;
|
||||
push 2;
|
||||
mov ecx, eax;
|
||||
call PerceptionRangeHook_Script;
|
||||
call PerceptionRange_Hook;
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
@@ -1071,7 +1078,7 @@ static void __declspec(naked) PerceptionSearchTargetHook() {
|
||||
push ecx;
|
||||
push 3;
|
||||
mov ecx, eax;
|
||||
call PerceptionRangeHook_Script;
|
||||
call PerceptionRange_Hook;
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
@@ -1468,6 +1475,22 @@ static void __declspec(naked) CorrectFidForRemovedItemHook() {
|
||||
}
|
||||
}
|
||||
|
||||
// Custom implementation of correctFidForRemovedItem_ engine function with the HOOK_INVENWIELD hook
|
||||
long __stdcall sfgame_correctFidForRemovedItem(TGameObj* critter, TGameObj* item, long flags) {
|
||||
long result = 1;
|
||||
if (HookHasScript(HOOK_INVENWIELD)) {
|
||||
long slot = INVEN_TYPE_WORN;
|
||||
if (flags & ObjectFlag::Right_Hand) { // right hand slot
|
||||
slot = INVEN_TYPE_RIGHT_HAND;
|
||||
} else if (flags & ObjectFlag::Left_Hand) { // left hand slot
|
||||
slot = INVEN_TYPE_LEFT_HAND;
|
||||
}
|
||||
result = InvenWieldHook_Script(critter, item, slot, 0, 0);
|
||||
}
|
||||
if (result) fo_correctFidForRemovedItem(critter, item, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __declspec(naked) item_drop_all_hack() {
|
||||
using namespace ObjectFlag;
|
||||
__asm {
|
||||
@@ -1578,22 +1601,6 @@ noArmor:
|
||||
}
|
||||
}
|
||||
|
||||
// internal function implementation with hook
|
||||
long __stdcall CorrectFidForRemovedItem_wHook(TGameObj* critter, TGameObj* item, long flags) {
|
||||
long result = 1;
|
||||
if (!hooks[HOOK_INVENWIELD].empty()) {
|
||||
long slot = INVEN_TYPE_WORN;
|
||||
if (flags & ObjectFlag::Right_Hand) { // right hand slot
|
||||
slot = INVEN_TYPE_RIGHT_HAND;
|
||||
} else if (flags & ObjectFlag::Left_Hand) { // left hand slot
|
||||
slot = INVEN_TYPE_LEFT_HAND;
|
||||
}
|
||||
result = InvenWieldHook_Script(critter, item, slot, 0, 0);
|
||||
}
|
||||
if (result) fo_correctFidForRemovedItem(critter, item, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 4.x backport
|
||||
void __stdcall AdjustFidHook(DWORD vanillaFid) {
|
||||
BeginHook();
|
||||
@@ -1613,13 +1620,14 @@ void __stdcall AdjustFidHook(DWORD vanillaFid) {
|
||||
static unsigned long previousGameMode = 0;
|
||||
|
||||
void __stdcall GameModeChangeHook(DWORD exit) {
|
||||
BeginHook();
|
||||
argCount = 2;
|
||||
args[0] = exit;
|
||||
args[1] = previousGameMode;
|
||||
RunHookScript(HOOK_GAMEMODECHANGE);
|
||||
EndHook();
|
||||
|
||||
if (HookHasScript(HOOK_GAMEMODECHANGE)) {
|
||||
BeginHook();
|
||||
argCount = 2;
|
||||
args[0] = exit;
|
||||
args[1] = previousGameMode;
|
||||
RunHookScript(HOOK_GAMEMODECHANGE);
|
||||
EndHook();
|
||||
}
|
||||
previousGameMode = GetLoopFlags();
|
||||
}
|
||||
// END HOOKS
|
||||
@@ -1657,6 +1665,10 @@ void __stdcall SetHSReturn(DWORD value) {
|
||||
}
|
||||
}
|
||||
|
||||
bool __stdcall HookHasScript(int hookId) {
|
||||
return (!hooks[hookId].empty());
|
||||
}
|
||||
|
||||
void __stdcall RegisterHook(TProgram* script, int id, int procNum, bool specReg) {
|
||||
if (id >= numHooks || (id > HOOK_ADJUSTFID && id < HOOK_GAMEMODECHANGE)) return;
|
||||
for (std::vector<sHookScript>::iterator it = hooks[id].begin(); it != hooks[id].end(); ++it) {
|
||||
|
||||
+9
-5
@@ -70,20 +70,24 @@ void LoadHookScripts();
|
||||
void InitHookScripts();
|
||||
void HookScriptClear();
|
||||
|
||||
bool __stdcall HookHasScript(int hookId);
|
||||
|
||||
void __stdcall GameModeChangeHook(DWORD exit);
|
||||
void __stdcall KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey);
|
||||
void __stdcall MouseClickHook(DWORD button, bool pressed);
|
||||
|
||||
int __fastcall AmmoCostHook_Script(DWORD hookType, TGameObj* weapon, DWORD &rounds);
|
||||
|
||||
long __stdcall CorrectFidForRemovedItem_wHook(TGameObj* critter, TGameObj* item, long flags);
|
||||
void InvenUnwield_HookDrop();
|
||||
void InvenUnwield_HookMove();
|
||||
|
||||
void __stdcall AdjustFidHook(DWORD vanillaFid);
|
||||
|
||||
// Implementation of item_w_mp_cost_ engine function with the hook
|
||||
long __fastcall sf_item_w_mp_cost(TGameObj* source, long hitMode, long isCalled);
|
||||
// Custom implementation of correctFidForRemovedItem_ engine function with the HOOK_INVENWIELD hook
|
||||
long __stdcall sfgame_correctFidForRemovedItem(TGameObj* critter, TGameObj* item, long flags);
|
||||
|
||||
// Implementation of is_within_perception_ engine function with the hook
|
||||
long __fastcall sf_is_within_perception(TGameObj* watcher, TGameObj* target);
|
||||
// Implementation of item_w_mp_cost_ engine function with the HOOK_CALCAPCOST hook
|
||||
long __fastcall sfgame_item_w_mp_cost(TGameObj* source, long hitMode, long isCalled);
|
||||
|
||||
// Implementation of is_within_perception_ engine function with the HOOK_WITHINPERCEPTION hook
|
||||
long __stdcall sfgame_is_within_perception(TGameObj* watcher, TGameObj* target);
|
||||
|
||||
+9
-9
@@ -63,7 +63,7 @@ void InventoryKeyPressedHook(DWORD dxKey, bool pressed) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DWORD __stdcall Inventory_item_total_size(TGameObj* critter) {
|
||||
DWORD __stdcall sfgame_item_total_size(TGameObj* critter) {
|
||||
int totalSize = fo_item_c_curr_size(critter);
|
||||
|
||||
if (critter->TypeFid() == OBJ_TYPE_CRITTER) {
|
||||
@@ -89,7 +89,7 @@ DWORD __stdcall Inventory_item_total_size(TGameObj* critter) {
|
||||
// Differences from vanilla:
|
||||
// - doesn't use art_vault_guy_num as default art, uses current critter FID instead
|
||||
// - calls AdjustFidHook that allows to hook into FID calculation
|
||||
DWORD __stdcall Inventory_adjust_fid() {
|
||||
DWORD __stdcall sfgame_adjust_fid() {
|
||||
DWORD fid;
|
||||
if ((*ptr_inven_dude)->TypeFid() == OBJ_TYPE_CRITTER) {
|
||||
DWORD indexNum;
|
||||
@@ -140,7 +140,7 @@ static void __declspec(naked) adjust_fid_hack() {
|
||||
__asm {
|
||||
push ecx;
|
||||
push edx;
|
||||
call Inventory_adjust_fid; // return fid
|
||||
call sfgame_adjust_fid; // return fid
|
||||
pop edx;
|
||||
pop ecx;
|
||||
retn;
|
||||
@@ -175,7 +175,7 @@ static __declspec(naked) void critterIsOverloaded_hack() {
|
||||
jz skip;
|
||||
push ebx;
|
||||
mov ebx, eax; // ebx = MaxSize
|
||||
call Inventory_item_total_size;
|
||||
call sfgame_item_total_size;
|
||||
cmp eax, ebx;
|
||||
setg al; // if CurrSize > MaxSize
|
||||
and eax, 0xFF;
|
||||
@@ -189,7 +189,7 @@ end:
|
||||
static int __fastcall CanAddedItems(TGameObj* critter, TGameObj* item, int count) {
|
||||
int sizeMax = CritterGetMaxSize(critter);
|
||||
if (sizeMax > 0) {
|
||||
int totalSize = Inventory_item_total_size(critter) + (fo_item_size(item) * count);
|
||||
int totalSize = sfgame_item_total_size(critter) + (fo_item_size(item) * count);
|
||||
if (totalSize > sizeMax) return -6; // TODO: Switch this to a lower number, and add custom error messages.
|
||||
}
|
||||
return 0;
|
||||
@@ -235,10 +235,10 @@ static int __fastcall BarterAttemptTransaction(TGameObj* critter, TGameObj* tabl
|
||||
int size = CritterGetMaxSize(critter);
|
||||
if (size == 0) return 1;
|
||||
|
||||
int sizeTable = Inventory_item_total_size(table);
|
||||
int sizeTable = sfgame_item_total_size(table);
|
||||
if (sizeTable == 0) return 1;
|
||||
|
||||
size -= Inventory_item_total_size(critter);
|
||||
size -= sfgame_item_total_size(critter);
|
||||
return (sizeTable <= size) ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ static void __cdecl DisplaySizeStats(TGameObj* critter, const char* &message, DW
|
||||
}
|
||||
|
||||
sizeMax = limitMax;
|
||||
size = Inventory_item_total_size(critter);
|
||||
size = sfgame_item_total_size(critter);
|
||||
|
||||
const char* msg = MsgSearch(ptr_inventry_message_file, 35);
|
||||
message = (msg != nullptr) ? msg : "";
|
||||
@@ -379,7 +379,7 @@ static void __declspec(naked) gdControlUpdateInfo_hack() {
|
||||
call CritterGetMaxSize;
|
||||
push eax; // sizeMax
|
||||
push ebx;
|
||||
call Inventory_item_total_size;
|
||||
call sfgame_item_total_size;
|
||||
push eax; // size
|
||||
mov eax, ebx;
|
||||
mov edx, STAT_carry_amt;
|
||||
|
||||
+2
-2
@@ -28,10 +28,10 @@ void __fastcall SetInvenApCost(int cost);
|
||||
// This function returns the size of the occupied inventory space for the object or critter
|
||||
// - difference from the item_c_curr_size_ function: includes the size of equipped items for the critter
|
||||
// - does not return the size of nested items
|
||||
DWORD __stdcall Inventory_item_total_size(TGameObj* critter);
|
||||
DWORD __stdcall sfgame_item_total_size(TGameObj* critter);
|
||||
|
||||
// Reimplementation of adjust_fid engine function
|
||||
// Differences from vanilla:
|
||||
// - doesn't use art_vault_guy_num as default art, uses current critter FID instead
|
||||
// - calls AdjustFidHook that allows to hook into FID calculation
|
||||
DWORD __stdcall Inventory_adjust_fid();
|
||||
DWORD __stdcall sfgame_adjust_fid();
|
||||
|
||||
@@ -761,7 +761,7 @@ static void mf_unwield_slot() {
|
||||
itemRef = (long*)FO_VAR_i_rhand;
|
||||
}
|
||||
if (item) {
|
||||
if (!CorrectFidForRemovedItem_wHook(critter, item, (slot == INVEN_TYPE_LEFT_HAND) ? ObjectFlag::Left_Hand : ObjectFlag::Right_Hand)) {
|
||||
if (!sfgame_correctFidForRemovedItem(critter, item, (slot == INVEN_TYPE_LEFT_HAND) ? ObjectFlag::Left_Hand : ObjectFlag::Right_Hand)) {
|
||||
return;
|
||||
}
|
||||
*itemRef = 0;
|
||||
@@ -777,7 +777,7 @@ static void mf_unwield_slot() {
|
||||
forceAdd = true;
|
||||
}
|
||||
if (item) {
|
||||
if (!CorrectFidForRemovedItem_wHook(critter, item, ObjectFlag::Worn)) {
|
||||
if (!sfgame_correctFidForRemovedItem(critter, item, ObjectFlag::Worn)) {
|
||||
if (forceAdd) *ptr_i_worn = item;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -524,7 +524,7 @@ static void mf_set_unjam_locks_time() {
|
||||
static void mf_get_current_inven_size() {
|
||||
TGameObj* obj = opHandler.arg(0).asObject();
|
||||
if (obj) {
|
||||
opHandler.setReturn(Inventory_item_total_size(obj));
|
||||
opHandler.setReturn(sfgame_item_total_size(obj));
|
||||
} else {
|
||||
OpcodeInvalidArgs("get_current_inven_size");
|
||||
opHandler.setReturn(0);
|
||||
|
||||
Reference in New Issue
Block a user