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:
NovaRain
2021-02-07 20:04:00 +08:00
parent 83392f739b
commit 60a187de30
9 changed files with 184 additions and 58 deletions
+73
View File
@@ -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
+37
View File
@@ -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;
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();
+2 -2
View File
@@ -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;
}
+1 -1
View File
@@ -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);