Rewrote the fix to allow fleeing NPC to use drugs.

Code edits to Perks.cpp/PerksOp.hpp.
This commit is contained in:
NovaRain
2019-05-24 10:43:46 +08:00
parent af6038ee0c
commit 1f6dac09b8
6 changed files with 72 additions and 56 deletions
+30 -15
View File
@@ -40,22 +40,9 @@ static void __declspec(naked) ai_try_attack_hook_FleeFix() {
static const DWORD combat_ai_hook_flee_Ret = 0x42B22F;
static void __declspec(naked) combat_ai_hook_FleeFix() {
__asm {
test byte ptr [ebp], 8; // 'ReTarget' flag
test byte ptr [ebp], 8; // 'ReTarget' flag (critter.combat_state)
jnz reTarget;
test byte ptr [ebp], 4; // flee flag? (critter.combat_state)
jz tryHeal;
flee:
jmp critter_name_;
tryHeal:
call ai_check_drugs_; // try to heal
mov eax, esi;
mov edx, STAT_current_hp;
call stat_level_;
cmp eax, [ebx + 0x10]; // minimum hp, below which NPC will run away
mov eax, esi;
jl flee;
add esp, 4;
jmp combat_ai_hook_flee_Ret;
reTarget:
and byte ptr [ebp], ~(4 | 8); // unset Flee/ReTarget flags
xor edi, edi;
@@ -65,6 +52,31 @@ reTarget:
}
}
static const DWORD combat_ai_hack_Ret = 0x42B204;
static void __declspec(naked) combat_ai_hack() {
__asm {
mov edx, [ebx + 0x10]; // cap.min_hp
cmp eax, edx;
jl tryHeal; // curr_hp < min_hp
end:
add esp, 4;
jmp combat_ai_hack_Ret;
tryHeal:
mov eax, esi;
call ai_check_drugs_;
push edx;
mov eax, esi;
mov edx, STAT_current_hp;
call stat_level_;
pop edx;
cmp eax, edx; // edx - minimum hp, below which NPC will run away
jge end;
retn; // flee
}
}
////////////////////////////////////////////////////////////////////////////////
static DWORD RetryCombatLastAP;
static DWORD RetryCombatMinAP;
static void __declspec(naked) RetryCombatHook() {
@@ -92,6 +104,8 @@ end:
}
}
////////////////////////////////////////////////////////////////////////////////
static void __fastcall CombatAttackHook(DWORD source, DWORD target) {
sources[target] = source;
targets[source] = target;
@@ -178,8 +192,9 @@ void AIInit() {
/////////////////////// Combat AI behavior fixes ///////////////////////
// Fix to allow fleeing NPC to use drugs
HookCall(0x42B1E3, combat_ai_hook_FleeFix);
MakeCall(0x42B1DC, combat_ai_hack);
// Fix for NPC stuck in fleeing mode when the hit chance of a target was too low
HookCall(0x42B1E3, combat_ai_hook_FleeFix);
HookCall(0x42ABA8, ai_try_attack_hook_FleeFix);
HookCall(0x42ACE5, ai_try_attack_hook_FleeFix);
// Disable fleeing when NPC cannot move closer to target
+5 -5
View File
@@ -125,9 +125,6 @@ static void TakeControlOfNPC(TGameObj* npc) {
(*ptr_perkLevelDataList)[i] = 0;
}
// change character name
CritterPcSetName(CritterName(npc));
// change level
int level = IsPartyMember(npc)
? PartyMemberGetCurrentLevel(npc)
@@ -136,6 +133,9 @@ static void TakeControlOfNPC(TGameObj* npc) {
*ptr_Level_ = level;
*ptr_last_level = level;
// change character name
CritterPcSetName(CritterName(npc));
// reset other stats
*ptr_Experience_ = 0;
*ptr_free_perk = 0;
@@ -472,8 +472,8 @@ void PartyControlInit() {
// Gets dude perks and traits from script while controlling another NPC
// WARNING: Handling dude perks/traits in the engine code while controlling another NPC remains impossible, this requires serious hacking of the engine code
HookCall(0x458242, GetRealDudePerk); //op_has_trait_hook_
HookCall(0x458326, GetRealDudeTrait); //op_has_trait_hook_
HookCall(0x458242, GetRealDudePerk); // op_has_trait_
HookCall(0x458326, GetRealDudeTrait); // op_has_trait_
} else
dlogr(" Disabled.", DL_INIT);
+14 -9
View File
@@ -205,7 +205,11 @@ void _stdcall SetSelectablePerk(char* name, int active, int image, char* desc) {
}
void _stdcall SetFakePerk(char* name, int level, int image, char* desc) {
if (level < 0 || level > 100) return;
if (level > 100) {
level = 100;
} else if (level < 0 ) {
return;
}
size_t size = fakePerks.size();
if (level == 0) { // remove perk from fakePerks
for (size_t i = 0; i < size; i++) {
@@ -235,7 +239,11 @@ void _stdcall SetFakePerk(char* name, int level, int image, char* desc) {
}
void _stdcall SetFakeTrait(char* name, int active, int image, char* desc) {
if (active < 0 || active > 1) return;
if (active > 1) {
active = 1;
} else if (active < 0) {
return;
}
size_t size = fakeTraits.size();
if (active == 0) {
for (size_t i = 0; i < size; i++) {
@@ -474,12 +482,11 @@ cLoop:
}
}
// Build a table of perks ID numbers available for selection
// data buffer has limited size for 119 perks
// Build a table of perks ID numbers available for selection, data buffer has limited size for 119 perks
static DWORD _stdcall HandleExtraSelectablePerks(DWORD available, DWORD* data) {
for (DWORD i = 0; i < fakeSelectablePerks.size(); i++) {
if (available >= 119) break; // exit if the buffer is overfull
data[available++] = PERK_count + i; //*(WORD*)(_name_sort_list + (offset+i)*8)=(WORD)(PERK_count+i);
data[available++] = PERK_count + i;
}
return available; // total number of perks available for selection
}
@@ -488,8 +495,7 @@ static void __declspec(naked) GetAvailablePerksHook() {
__asm {
push ecx;
push edx; // arg data
mov ecx, IgnoringDefaultPerks;
test ecx, ecx;
cmp IgnoringDefaultPerks, 0;
jnz skipDefaults;
call perk_make_list_; // return available count
jmp next;
@@ -590,8 +596,7 @@ static void _stdcall AddFakePerk(DWORD perkID) {
}
}
if (addPerkMode & 4) { // delete from selectable perks
RemoveSelectableID.push_back(perkID);
//fakeSelectablePerks.remove_at(perkID);
RemoveSelectableID.push_back(perkID); //fakeSelectablePerks.remove_at(perkID);
}
}
+3 -3
View File
@@ -1196,16 +1196,16 @@ static void __declspec(naked) CombatOverHook() {
}
}
static int maxCountProto = 512;
static int maxCountLoadProto = 512;
static void __declspec(naked) proto_ptr_hack() {
__asm {
mov ecx, maxCountProto;
mov ecx, maxCountLoadProto;
cmp ecx, 4096;
jae skip;
cmp eax, ecx;
jb end;
add ecx, 256;
mov maxCountProto, ecx;
mov maxCountLoadProto, ecx;
skip:
cmp eax, ecx;
end:
+3 -3
View File
@@ -49,7 +49,6 @@ typedef struct {
} sScriptProgram;
void ScriptExtenderSetup();
void LoadProtoAutoMaxLimit();
bool _stdcall isGameScript(const char* filename);
void LoadGlobalScripts();
void ClearGlobalScripts();
@@ -96,6 +95,8 @@ static char reg_anim_combat_check = 1;
extern DWORD isGlobalScriptLoading;
extern DWORD AvailableGlobalScriptTypes;
void LoadProtoAutoMaxLimit();
// object's unique id
extern long objUniqueID;
long SetObjectUniqueID(TGameObj* obj);
@@ -138,6 +139,5 @@ enum ScriptProc : long
push_p_proc = 24,
is_dropping_p_proc = 25,
combat_is_starting_p_proc = 26,
combat_is_over_p_proc = 27,
count = 28
combat_is_over_p_proc = 27
};
+17 -21
View File
@@ -547,28 +547,24 @@ end:
static void __declspec(naked) remove_trait() {
__asm {
pushad;
mov ebp, eax;
call interpretPopShort_;
mov edi, eax;
mov eax, ebp;
call interpretPopLong_;
cmp di, VAR_TYPE_INT;
jnz end;
xor ebx, ebx;
dec ebx;
mov ecx, ds:[_pc_trait2];
cmp eax, ds:[_pc_trait];
jne next;
mov ds:[_pc_trait], ecx;
mov ds:[_pc_trait2], ebx;
jmp end;
next:
cmp eax, ds:[_pc_trait2];
jne end;
mov ds:[_pc_trait2], ebx;
push ecx;
_GET_ARG_INT(end);
test eax, eax;
jl end;
mov edx, -1;
cmp eax, ds:[_pc_trait];
jne next;
mov ecx, ds:[_pc_trait2];
mov ds:[_pc_trait], ecx;
mov ds:[_pc_trait2], edx;
end:
popad;
pop ecx;
retn;
next:
cmp eax, ds:[_pc_trait2];
jne end;
mov ds:[_pc_trait2], edx;
pop ecx;
retn;
}
}