mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
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:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user