Added a new hook: HOOK_ADJUSTPOISON

Added a fix to the poison handling in the engine when an NPC is under
the player's control.
This commit is contained in:
NovaRain
2020-12-30 22:11:02 +08:00
parent 45a523f6ca
commit 19f6d64e5b
16 changed files with 231 additions and 30 deletions
+1
View File
@@ -69,6 +69,7 @@
#define HOOK_STDPROCEDURE_END (41)
#define HOOK_TARGETOBJECT (42)
#define HOOK_ENCOUNTER (43)
#define HOOK_ADJUSTPOISON (44)
//Valid arguments to list_begin
#define LIST_CRITTERS (0)
+15 -1
View File
@@ -368,7 +368,7 @@ int ret0 - overrides the pressed key (a new key DX scancode or 0 for no over
HOOK_MOUSECLICK (hs_mouseclick.int)
Runs once every time when a mouse button was pressed or release.
Runs once every time when a mouse button was pressed or released.
int arg0 - event type: 1 - pressed, 0 - released
int arg1 - button number (0 - left, 1 - right, up to 7)
@@ -693,3 +693,17 @@ int arg2 - 1 when the encounter occurs is a special encounter, 0 otherwise
int ret0 - overrides the map ID, or pass -1 for event type 0 to cancel the encounter and continue traveling
int ret1 - pass 1 to cancel the encounter and load the specified map from the ret1 (only for event type 0)
-------------------------------------------
HOOK_ADJUSTPOISON (hs_adjustpoison.int)
Runs when a critter's poison level is changed, or when the player takes damage from the poison.
Critter arg0 - the critter
int arg1 - the amount of poison being added/removed
int arg2 - the damage value at the time of applying the poison effect
(damage from the poison effect is implemented only for the player character; for other critters, this value will always be 0)
int ret0 - the new amount of poison being added/removed
int ret1 - the new damage value, only negative values are allowed (will only be valid at the time of taking damage from the poison)
+1
View File
@@ -205,6 +205,7 @@ WRAP_WATCOM_FUNC0(void, process_bk)
WRAP_WATCOM_FUNC0(void, proto_dude_update_gender)
// Places pointer to a prototype structure into ptrPtr and returns 0 on success or -1 on failure
WRAP_WATCOM_FUNC2(long, proto_ptr, long, pid, Proto**, ptrPtr)
WRAP_WATCOM_FUNC2(void, queue_clear_type, long, qType, void*, func)
WRAP_WATCOM_FUNC2(void*, queue_find_first, GameObject*, object, long, qType)
WRAP_WATCOM_FUNC2(void*, queue_find_next, GameObject*, object, long, qType)
WRAP_WATCOM_FUNC2(void, queue_remove_this, GameObject*, object, long, qType)
+1 -1
View File
@@ -16,6 +16,6 @@ public:
extern int tagSkill4LevelBase;
extern void ResetBodyState();
void ResetBodyState();
}
+122
View File
@@ -0,0 +1,122 @@
/*
* sfall
* Copyright (C) 2008-2021 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
#include "PartyControl.h"
#include "CritterPoison.h"
namespace sfall
{
//static long adjustPoison = -2;
long CritterPoison::adjustPoisonHP_Default = -1;
long CritterPoison::adjustPoisonHP; // default or returned value from HOOK_ADJUSTPOISON
void CritterPoison::SetDefaultAdjustPoisonHP(long value) {
adjustPoisonHP_Default = adjustPoisonHP = value;
}
void __fastcall sf_critter_adjust_poison(fo::GameObject* critter, long amount) {
if (amount == 0) return;
if (amount > 0) {
amount -= fo::func::stat_level(critter, fo::STAT_poison_resist) * amount / 100;
} else if (critter->critter.poison == 0) {
return;
}
critter->critter.poison += amount;
if (critter->critter.poison < 0) {
critter->critter.poison = 0; // level can't be negative
} else {
// set uID for saving queue
//Objects::SetObjectUniqueID(critter);
//fo::func::queue_add(10 * (505 - 5 * critter->critter.poison), critter, nullptr, fo::QueueType::poison_event);
}
}
static void __declspec(naked) critter_adjust_poison_hack() {
__asm {
mov edx, esi;
mov ecx, edi;
jmp sf_critter_adjust_poison;
}
}
void __declspec(naked) critter_check_poison_hack() {
__asm {
mov eax, CritterPoison::adjustPoisonHP_Default;
mov edx, CritterPoison::adjustPoisonHP;
mov CritterPoison::adjustPoisonHP, eax;
retn;
}
}
void __fastcall critter_check_poison_fix() {
if (PartyControl::IsNpcControlled()) {
// since another critter is being controlled, we can't apply the poison effect to it
// instead, we add the "poison" event to dude again, which will be triggered when dude returns to the player's control
fo::func::queue_clear_type(fo::QueueType::poison_event, nullptr);
fo::GameObject* dude = PartyControl::RealDudeObject();
fo::func::queue_add(10, dude, nullptr, fo::QueueType::poison_event);
}
}
static void __declspec(naked) critter_check_poison_hack_fix() {
using namespace fo;
using namespace Fields;
__asm {
mov ecx, [eax + protoId]; // critter.pid
cmp ecx, PID_Player;
jnz notDude;
retn;
notDude:
call critter_check_poison_fix;
or al, 1; // unset ZF (exit from func)
retn;
}
}
void __declspec(naked) critter_adjust_poison_hack_fix() { // can also be called from HOOK_ADJUSTPOISON
using namespace fo;
using namespace Fields;
__asm {
mov edx, ds:[FO_VAR_obj_dude];
mov ebx, [eax + protoId]; // critter.pid
mov ecx, PID_Player;
retn;
}
}
void CritterPoison::init() {
// Allow changing the poison level for critters
MakeCall(0x42D226, critter_adjust_poison_hack);
SafeWrite8(0x42D22C, 0xDA); // jmp 0x42D30A
// Adjust poison damage
SetDefaultAdjustPoisonHP(*(DWORD*)0x42D332);
MakeCall(0x42D331, critter_check_poison_hack);
// Fix/tweak for party control
MakeCall(0x42D31F, critter_check_poison_hack_fix, 1);
MakeCall(0x42D21C, critter_adjust_poison_hack_fix, 1);
SafeWrite8(0x42D223, 0xCB); // cmp eax, edx > cmp ebx, ecx
}
}
+39
View File
@@ -0,0 +1,39 @@
/*
* sfall
* Copyright (C) 2008-2021 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "Module.h"
namespace sfall
{
class CritterPoison : public Module {
public:
const char* name() { return "CritterPoison"; }
void init();
static long adjustPoisonHP_Default;
static long adjustPoisonHP; // temp value from HOOK_ADJUSTPOISON
static void SetDefaultAdjustPoisonHP(long value);
};
void critter_adjust_poison_hack_fix();
}
+1
View File
@@ -103,6 +103,7 @@ static HooksInjectInfo injectHooks[] = {
{HOOK_STDPROCEDURE_END, Inject_ScriptProcedureHook2, false},
{HOOK_TARGETOBJECT, Inject_TargetObjectHook, false},
{HOOK_ENCOUNTER, Inject_EncounterHook, false},
{HOOK_ADJUSTPOISON, Inject_AdjustPoisonHook, false},
};
void HookScripts::InjectingHook(int hookId) {
+1
View File
@@ -70,6 +70,7 @@ enum HookType
HOOK_STDPROCEDURE_END = 41,
HOOK_TARGETOBJECT = 42,
HOOK_ENCOUNTER = 43,
HOOK_ADJUSTPOISON = 44,
HOOK_COUNT
};
+37 -1
View File
@@ -1,6 +1,7 @@
#include "..\..\FalloutEngine\Fallout2.h"
#include "..\..\SafeWrite.h"
#include "..\HookScripts.h"
#include "..\CritterPoison.h"
#include "Common.h"
#include "ObjectHs.h"
@@ -302,6 +303,36 @@ skip:
}
}
static DWORD __fastcall AdjustPoison_Script(DWORD critter, long amount, DWORD addr) {
BeginHook();
argCount = 3;
bool checkPoison = (addr == (0x42D32C + 5)); // from critter_check_poison_
args[0] = critter;
args[1] = amount;
args[2] = (checkPoison) ? CritterPoison::adjustPoisonHP_Default : 0;
RunHookScript(HOOK_ADJUSTPOISON);
if (cRet > 0) amount = rets[0];
if (cRet > 1 && checkPoison && (long)rets[1] < 0) CritterPoison::adjustPoisonHP = rets[1];
EndHook();
return amount;
}
static void __declspec(naked) critter_adjust_poison_hack() {
__asm {
push [esp + 0x24 + 4]; // called from
mov ecx, eax; // critter
call AdjustPoison_Script; // edx - amount
mov esi, eax; // old/new amount
mov eax, edi; // restore eax value
jmp critter_adjust_poison_hack_fix; // in CritterPoison
}
}
void Inject_UseObjOnHook() {
HookCalls(UseObjOnHook, { 0x49C606, 0x473619 });
@@ -310,7 +341,7 @@ void Inject_UseObjOnHook() {
0x4285DF, // ai_check_drugs
0x4286F8, // ai_check_drugs
0x4287F8, // ai_check_drugs
0x473573 // inven_action_cursor
0x473573 // inven_action_cursor
});
}
@@ -339,6 +370,10 @@ void Inject_ScriptProcedureHook2() {
HookCall(0x4A49A7, After_ScriptStdProcedureHook);
}
void Inject_AdjustPoisonHook() {
MakeCall(0x42D21C, critter_adjust_poison_hack, 1);
}
void InitObjectHookScripts() {
HookScripts::LoadHookScript("hs_useobjon", HOOK_USEOBJON);
HookScripts::LoadHookScript("hs_useobj", HOOK_USEOBJ);
@@ -347,6 +382,7 @@ void InitObjectHookScripts() {
HookScripts::LoadHookScript("hs_setlighting", HOOK_SETLIGHTING);
HookScripts::LoadHookScript("hs_stdprocedure", HOOK_STDPROCEDURE); // combo hook
HookScripts::LoadHookScript("hs_stdprocedure", HOOK_STDPROCEDURE_END);
HookScripts::LoadHookScript("hs_adjustpoison", HOOK_ADJUSTPOISON);
}
}
+1
View File
@@ -11,4 +11,5 @@ namespace sfall
void Inject_SetLightingHook();
void Inject_ScriptProcedureHook();
void Inject_ScriptProcedureHook2();
void Inject_AdjustPoisonHook();
}
+1 -4
View File
@@ -916,10 +916,7 @@ static void __fastcall SetPanPosition(fo::ACMSoundData* sound) {
if (distance > 5) {
long direction = fo::func::tile_dir(fo::var::obj_dude->tile, relativeObject->tile);
bool isRightSide = (direction <= 2);
long panValue = (distance - 5) * 100;
if (panValue > 10000) panValue = 10000;
long panValue = (distance < 55) ? (distance - 5) * 200 : 10000;
sound->soundBuffer->SetPan((isRightSide) ? panValue : -panValue); // left mute 10000 ... -10000 right mute
}
relativeObject = nullptr; // just in case
-22
View File
@@ -26,17 +26,6 @@
namespace sfall
{
void __fastcall sf_critter_adjust_poison(fo::GameObject* critter, long amount) {
if (amount == 0) return;
if (amount > 0) {
amount -= fo::func::stat_level(critter, fo::STAT_poison_resist) * amount / 100;
} else if (critter->critter.poison == 0) {
return;
}
critter->critter.poison += amount;
if (critter->critter.poison < 0) critter->critter.poison = 0; // level can't be negative
}
static DWORD statMaximumsPC[fo::STAT_max_stat];
static DWORD statMinimumsPC[fo::STAT_max_stat];
static DWORD statMaximumsNPC[fo::STAT_max_stat];
@@ -220,14 +209,6 @@ allow:
}
}
static void __declspec(naked) critter_adjust_poison_hack() {
__asm {
mov edx, esi;
mov ecx, edi;
jmp sf_critter_adjust_poison;
}
}
static void StatsReset() {
for (size_t i = 0; i < fo::STAT_max_stat; i++) {
statMaximumsPC[i] = statMaximumsNPC[i] = fo::var::stat_data[i].maxValue;
@@ -262,9 +243,6 @@ void Stats::init() {
// Allow set_critter_stat function to change STAT_unused and STAT_dmg_* stats for the player
MakeCall(0x4AF54E, stat_set_base_hack_allow);
MakeCall(0x455D65, op_set_critter_stat_hack); // STAT_unused for other critters
// Allow changing the poison level for critters
MakeCall(0x42D226, critter_adjust_poison_hack);
SafeWrite8(0x42D22C, 0xDA); // jmp 0x42D30A
auto xpTableList = GetConfigList("Misc", "XPTable", "", 2048);
size_t numLevels = xpTableList.size();
+2
View File
@@ -291,6 +291,7 @@
<ClInclude Include="FalloutEngine\Variables.h" />
<ClInclude Include="FalloutEngine\Functions.h" />
<ClInclude Include="FalloutEngine\Functions_def.h" />
<ClInclude Include="Modules\CritterPoison.h" />
<ClInclude Include="Modules\CritterStats.h" />
<ClInclude Include="Modules\Interface.h" />
<ClInclude Include="Modules\Drugs.h" />
@@ -388,6 +389,7 @@
<ClCompile Include="FalloutEngine\FunctionOffsets.cpp" />
<ClCompile Include="FalloutEngine\Variables.cpp" />
<ClCompile Include="FalloutEngine\Functions.cpp" />
<ClCompile Include="Modules\CritterPoison.cpp" />
<ClCompile Include="Modules\CritterStats.cpp" />
<ClCompile Include="Modules\Interface.cpp" />
<ClCompile Include="Modules\Drugs.cpp" />
+6
View File
@@ -304,6 +304,9 @@
<ClInclude Include="Modules\SubModules\GameRender.h">
<Filter>Modules\SubModules</Filter>
</ClInclude>
<ClInclude Include="Modules\CritterPoison.h">
<Filter>Modules</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
@@ -562,6 +565,9 @@
<ClCompile Include="Modules\SubModules\GameRender.cpp">
<Filter>Modules\SubModules</Filter>
</ClCompile>
<ClCompile Include="Modules\CritterPoison.cpp">
<Filter>Modules</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="version.rc" />
+2
View File
@@ -38,6 +38,7 @@
#include "Modules\Credits.h"
#include "Modules\Criticals.h"
#include "Modules\CritterStats.h"
#include "Modules\CritterPoison.h"
#include "Modules\DamageMod.h"
#include "Modules\DebugEditor.h"
#include "Modules\Drugs.h"
@@ -185,6 +186,7 @@ static void InitModules() {
manager.add<Worldmap>();
manager.add<Stats>();
manager.add<CritterStats>();
manager.add<CritterPoison>();
manager.add<Perks>();
manager.add<Combat>();
manager.add<Skills>();
+1 -1
View File
@@ -20,7 +20,7 @@
#define TARGETVERSION "Fallout 2 v1.02 US"
#define LEGAL_COPYRIGHT "Copyright (C) 2006-2020, sfall team"
#define LEGAL_COPYRIGHT "Copyright (C) 2006-2021, sfall team"
#define VERSION_MAJOR 4
#define VERSION_MINOR 2