Added a fix to the poison handling in the engine when an NPC is under

the player's control.

Minor code edits.
This commit is contained in:
NovaRain
2020-12-30 22:34:32 +08:00
parent 28bba7cfef
commit cdc06b4e6a
9 changed files with 73 additions and 24 deletions
+1 -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)
+1
View File
@@ -176,6 +176,7 @@ WRAP_WATCOM_FUNC2(long, PerkLevel, perk_level_, TGameObj*, critter, long, perkId
WRAP_WATCOM_FUNC6(long, PickDeath, pick_death_, TGameObj*, attacker, TGameObj*, target, TGameObj*, weapon, long, amount, long, anim, long, hitFromBack)
WRAP_WATCOM_FUNC0(void, ProcessBk, process_bk_)
WRAP_WATCOM_FUNC0(void, ProtoDudeUpdateGender, proto_dude_update_gender_)
WRAP_WATCOM_FUNC2(void, QueueClearType, queue_clear_type_, long, qType, void*, func)
WRAP_WATCOM_FUNC2(void*, QueueFindFirst, queue_find_first_, TGameObj*, object, long, qType)
WRAP_WATCOM_FUNC2(void*, QueueFindNext, queue_find_next_, TGameObj*, object, long, qType)
WRAP_WATCOM_FUNC2(void, QueueRemoveThis, queue_remove_this_, TGameObj*, object, long, qType)
+2 -2
View File
@@ -164,9 +164,9 @@ errorSave:
static char saveFailMsg[128];
static DWORD __stdcall CombatSaveTest() {
if (!saveInCombatFix && !IsNpcControlled()) return 1;
if (!saveInCombatFix && !PartyControl_IsNpcControlled()) return 1;
if (inLoop & COMBAT) {
if (saveInCombatFix == 2 || IsNpcControlled() || !(inLoop & PCOMBAT)) {
if (saveInCombatFix == 2 || PartyControl_IsNpcControlled() || !(inLoop & PCOMBAT)) {
DisplayPrint(saveFailMsg);
return 0;
}
+2 -2
View File
@@ -393,11 +393,11 @@ static void PartyControlReset() {
realDude.obj_dude = nullptr;
}
bool IsNpcControlled() {
bool PartyControl_IsNpcControlled() {
return isControllingNPC;
}
TGameObj* RealDudeObject() {
TGameObj* PartyControl_RealDudeObject() {
return realDude.obj_dude != nullptr
? realDude.obj_dude
: *ptr_obj_dude;
+2 -2
View File
@@ -26,7 +26,7 @@ void PartyControl_OnGameLoad();
int __fastcall PartyControl_SwitchHandHook(TGameObj* item);
bool IsNpcControlled();
bool PartyControl_IsNpcControlled();
// Returns pointer to "real" dude, which is different from "dude_obj" when controlling another critter
TGameObj* RealDudeObject();
TGameObj* PartyControl_RealDudeObject();
+1 -1
View File
@@ -491,7 +491,7 @@ static void mf_item_weight() {
}
static void mf_real_dude_obj() {
opHandler.setReturn(RealDudeObject());
opHandler.setReturn(PartyControl_RealDudeObject());
}
static void mf_car_gas_amount() {
+1 -4
View File
@@ -928,10 +928,7 @@ static void __fastcall SetPanPosition(ACMSoundData* sound) {
if (distance > 5) {
long direction = TileDir((*ptr_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
+62 -11
View File
@@ -18,20 +18,10 @@
#include "main.h"
#include "FalloutEngine.h"
#include "PartyControl.h"
#include "Stats.h"
void __fastcall sf_critter_adjust_poison(TGameObj* critter, long amount) {
if (amount == 0) return;
if (amount > 0) {
amount -= StatLevel(critter, 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[STAT_max_stat];
static DWORD statMinimumsPC[STAT_max_stat];
static DWORD statMaximumsNPC[STAT_max_stat];
@@ -221,6 +211,25 @@ allow:
}
}
//////////////////////////////// CRITTER POISON ////////////////////////////////
void __fastcall sf_critter_adjust_poison(TGameObj* critter, long amount) {
if (amount == 0) return;
if (amount > 0) {
amount -= StatLevel(critter, 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);
//QueueAdd(10 * (505 - 5 * critter->critter.poison), critter, nullptr, poison_event);
}
}
static void __declspec(naked) critter_adjust_poison_hack() {
__asm {
mov edx, esi;
@@ -229,6 +238,42 @@ static void __declspec(naked) critter_adjust_poison_hack() {
}
}
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
QueueClearType(poison_event, nullptr);
TGameObj* dude = PartyControl_RealDudeObject();
QueueAdd(10, dude, nullptr, poison_event);
}
}
static void __declspec(naked) critter_check_poison_hack_fix() {
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() {
using namespace Fields;
__asm {
mov edx, ds:[_obj_dude];
mov ebx, [eax + protoId]; // critter.pid
mov ecx, PID_Player;
retn;
}
}
////////////////////////////////////////////////////////////////////////////////
static void StatsReset() {
for (size_t i = 0; i < STAT_max_stat; i++) {
statMaximumsPC[i] = statMaximumsNPC[i] = *(DWORD*)(_stat_data + 16 + i * 24);
@@ -261,10 +306,16 @@ 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
// 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
std::vector<std::string> xpTableList = GetConfigList("Misc", "XPTable", "", 2048);
size_t numLevels = xpTableList.size();
if (numLevels > 0) {
+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 3
#define VERSION_MINOR 8