Added ActiveGeigerMsgs option and radiation fixes

Changed "Radiated" to be highlighted in red color when the player is
under the influence of negative effects of radiation.
This commit is contained in:
NovaRain
2020-03-30 21:06:11 +08:00
parent ba911375a9
commit 29608bb51c
8 changed files with 119 additions and 42 deletions
+3
View File
@@ -662,6 +662,9 @@ DontTurnOffSneakIfYouRun=0
;Set to 0 to disable switching. (Default is 3)
UseWalkDistance=3
;Set to 1 to display messages about radiation for the active geiger counter
ActiveGeigerMsgs=1
;Set to 1 to fix the bug of being unable to sell used geiger counters or stealth boys
CanSellUsedGeiger=1
+10
View File
@@ -144,6 +144,16 @@ long CheckAddictByPid(fo::GameObject* critter, long pid) {
/* keyword 'return' is not needed, the compiler will do everything correctly */
}
// Checks whether the player is under the influence of negative effects of radiation
long __fastcall IsRadInfluence() {
fo::QueueRadiation* queue = (fo::QueueRadiation*)fo::func::queue_find_first(fo::var::obj_dude, fo::radiation_event);
while (queue) {
if (queue->init && queue->level >= 2) return 1;
queue = (fo::QueueRadiation*)fo::func::queue_find_next(fo::var::obj_dude, fo::radiation_event);
}
return 0;
}
void ToggleNpcFlag(fo::GameObject* npc, long flag, bool set) {
Proto* protoPtr;
if (fo::func::proto_ptr(npc->protoId, &protoPtr) != -1) {
+4
View File
@@ -18,6 +18,7 @@
#pragma once
#include <string>
#include <vector>
#include "Functions.h"
@@ -66,6 +67,9 @@ bool HeroIsFemale();
long CheckAddictByPid(fo::GameObject* critter, long pid);
// Checks whether the player is under the influence of negative effects of radiation
long __fastcall IsRadInfluence();
void ToggleNpcFlag(fo::GameObject* npc, long flag, bool set);
// Returns the number of party members in the existing table (begins from 1)
+8 -3
View File
@@ -117,7 +117,7 @@ struct GameObject {
long damageLastTurn;
long aiPacket;
long teamNum;
long whoHitMe;
GameObject* whoHitMe;
long health;
long rads;
long poison;
@@ -791,10 +791,15 @@ struct Queue {
DWORD time;
long type;
GameObject* object;
long data;
DWORD* data;
Queue* next;
};
struct QueueRadiation {
long level;
long init; // 1 - for removing effect
};
struct QueueDrug {
DWORD pid;
fo::Stat stat0;
@@ -806,7 +811,7 @@ struct QueueDrug {
};
struct QueueAddict {
long init; // 1 = perk is not active yet
long init; // 1 - perk is not active yet
DWORD drugPid;
fo::Perk perkId; // effect of addiction
};
+1
View File
@@ -281,6 +281,7 @@
#define FO_VAR_GoodColor 0x6AB4EF
#define FO_VAR_GreenColor 0x6A3CB0
#define FO_VAR_LIGHT_GREY_Color 0x6A76BF
#define FO_VAR_LIGHT_RED_Color 0x6AB61A
#define FO_VAR_PeanutButter 0x6A82F3
#define FO_VAR_RedColor 0x6AB4D0
#define FO_VAR_WhiteColor 0x6AB8CF
+69 -38
View File
@@ -1098,37 +1098,31 @@ skip:
}
static void __declspec(naked) combat_ctd_init_hack() {
static const DWORD combat_ctd_init_Ret = 0x422F11;
__asm {
mov [esi+0x24], eax // ctd.targetTile
mov eax, [ebx + whoHitMe] // pobj.who_hit_me
inc eax
jnz end
mov [ebx + whoHitMe], eax // pobj.who_hit_me
mov [esi + 0x24], eax; // ctd.targetTile
mov eax, [ebx + whoHitMe]; // pobj.who_hit_me
inc eax;
jnz end; // jump if whoHitMe != -1
mov [ebx + whoHitMe], eax; // pobj.who_hit_me = 0
end:
push 0x422F11
retn
jmp combat_ctd_init_Ret;
}
}
static void __declspec(naked) obj_save_hack() {
__asm {
inc eax
jz end
dec eax
mov edx, [esp+0x1C] // combat_data
mov eax, [eax + cid] // pobj.who_hit_me.cid
test byte ptr ds:[FO_VAR_combat_state], 1 // in combat?
jz clear // No
cmp dword ptr [edx], 0 // in combat?
jne skip // Yes
__asm { // edx - combat_data
mov eax, [eax + cid]; // pobj.who_hit_me.cid
test byte ptr ds:[FO_VAR_combat_state], 1; // in combat?
jz clear; // No
cmp dword ptr [edx], 0; // in combat?
jne skip; // Yes
clear:
xor eax, eax
dec eax
xor eax, eax;
dec eax; // -1
skip:
mov [edx+0x18], eax // combat_data.who_hit_me
end:
push 0x489422
retn
mov [edx + 0x18], eax; // combat_data.who_hit_me
retn;
}
}
@@ -1511,11 +1505,14 @@ static void __declspec(naked) ResetPlayer_hook() {
}
}
static const DWORD obj_move_to_tile_Ret = 0x48A74E;
static void __declspec(naked) obj_move_to_tile_hack() {
static const DWORD obj_move_to_tile_Ret = 0x48A74E;
__asm {
cmp dword ptr ds:[FO_VAR_map_state], 0; // map number, -1 exit to worldmap
cmp ds:[FO_VAR_loadingGame], 0;
jnz skip;
cmp dword ptr ds:[FO_VAR_map_state], 0; // map number, -1 exit to worldmap (probably redundant)
jz mapLeave;
skip:
add esp, 4;
jmp obj_move_to_tile_Ret;
mapLeave:
@@ -1868,7 +1865,32 @@ noRange:
}
}
static void __declspec(naked) process_rads_hack() {
static const DWORD process_rads_Ret = 0x42D708;
__asm {
test ebp, ebp;
jl fix;
test byte ptr [ecx + damageFlags], DAM_DEAD;
jnz fix;
retn;
fix:
add esp, 4;
jmp process_rads_Ret;
}
}
static void __declspec(naked) process_rads_hook() {
__asm {
test ebp, ebp;
jg skip;
mov esi, 999; // msg number
mov [esp + 0x20 - 0x20 + 4], esi;
skip:
jmp fo::funcoffs::message_search_;
}
}
static void __declspec(naked) process_rads_hook_msg() {
__asm {
push eax; // death message for DialogOut
call fo::funcoffs::display_print_;
@@ -2789,6 +2811,16 @@ void BugFixes::init()
dlogr(" Done", DL_INIT);
//}
// Enable party members with level 6 protos to reach level 6
//if (GetConfigInt("Misc", "NPCStage6Fix", 1)) {
dlog("Applying NPC Stage 6 Fix.", DL_INIT);
MakeJump(0x493CE9, NPCStage6Fix1); // partyMember_init_
MakeJump(0x494224, NPCStage6Fix2); // partyMemberGetAIOptions_
SafeWrite8(0x494063, 6); // loop should look for a potential 6th stage (partyMember_init_)
SafeWrite8(0x4940BB, 204); // move pointer by 204 bytes instead of 200
dlogr(" Done", DL_INIT);
//}
//if (GetConfigInt("Misc", "NPCLevelFix", 1)) {
dlog("Applying NPC level fix.", DL_INIT);
HookCall(0x495BC9, (void*)0x495E51); // jz 0x495E7F > jz 0x495E51
@@ -2849,16 +2881,6 @@ void BugFixes::init()
dlogr(" Done", DL_INIT);
//}
// Enable party members with level 6 protos to reach level 6
//if (GetConfigInt("Misc", "NPCStage6Fix", 1)) {
dlog("Applying NPC Stage 6 Fix.", DL_INIT);
MakeJump(0x493CE9, NPCStage6Fix1); // partyMember_init_
MakeJump(0x494224, NPCStage6Fix2); // partyMemberGetAIOptions_
SafeWrite8(0x494063, 6); // loop should look for a potential 6th stage (partyMember_init_)
SafeWrite8(0x4940BB, 204); // move pointer by 204 bytes instead of 200
dlogr(" Done", DL_INIT);
//}
//if (GetConfigInt("Misc", "MultiHexPathingFix", 1)) {
dlog("Applying MultiHex Pathing Fix.", DL_INIT);
MakeCalls(MultiHexFix, {0x42901F, 0x429170});
@@ -2893,7 +2915,7 @@ void BugFixes::init()
dlog("Applying fix for explosives bugs.", DL_INIT);
// Fix crashes when killing critters with explosives
MakeJump(0x422F05, combat_ctd_init_hack);
MakeJump(0x489413, obj_save_hack);
MakeCall(0x48941C, obj_save_hack, 1);
// Fix for destroy_p_proc not being called if the critter is killed by explosives when you leave the map
MakeCall(0x4130C3, action_explode_hack);
MakeCall(0x4130E5, action_explode_hack1);
@@ -3105,8 +3127,17 @@ void BugFixes::init()
// Fix for determine_to_hit_func_ engine function taking distance into account when called from determine_to_hit_no_range_
HookCall(0x4244C3, determine_to_hit_func_hook);
// Display a pop-up messages box about death from radiation
HookCall(0x42D733, process_rads_hook);
// Radiation fixes
MakeCall(0x42D6C3, process_rads_hack, 1); // prevents player's death if a stat is less than 1 when removing radiation effects
HookCall(0x42D67A, process_rads_hook); // fix for the same message being displayed when removing radiation effects
// Display messages about radiation for the active geiger counter
if (GetConfigInt("Misc", "ActiveGeigerMsgs", 1)) {
dlog("Applying active geiger counter messages patch.", DL_INIT);
SafeWriteBatch<BYTE>(0x74, {0x42D424, 0x42D444}); // jnz > jz
dlogr(" Done", DL_INIT);
}
// Display a pop-up message box about death from radiation
HookCall(0x42D733, process_rads_hook_msg);
// Fix for AI not taking chem_primary_desire in AI.txt as drug use preference when using drugs in their inventory
if (GetConfigInt("Misc", "AIDrugUsePerfFix", 0)) {
+1 -1
View File
@@ -45,7 +45,7 @@ static void __declspec(naked) CombatLoopHook() {
//pop eax;
pop edx;
call fo::funcoffs::get_input_;
pop ecx; // prevent the combat turn from being skipped after pressing Alt-Tab
pop ecx; // fix to prevent the combat turn from being skipped after using Alt+Tab
retn;
}
}
+23
View File
@@ -264,6 +264,26 @@ playWalkMovie:
}
}
static void __declspec(naked) ListDrvdStats_hook() {
static const DWORD ListDrvdStats_Ret = 0x4354D9;
__asm {
call fo::IsRadInfluence;
test eax, eax;
jnz influence;
mov eax, ds:[FO_VAR_obj_dude];
jmp fo::funcoffs::critter_get_rads_;
influence:
xor ecx, ecx;
mov cl, ds:[FO_VAR_RedColor];
cmp dword ptr [esp], 0x4354BE + 5;
jne skip;
mov cl, 131; // color index for selected
skip:
add esp, 4;
jmp ListDrvdStats_Ret;
}
}
void AdditionalWeaponAnimsPatch() {
if (GetConfigInt("Misc", "AdditionalWeaponAnims", 0)) {
dlog("Applying additional weapon animations patch.", DL_INIT);
@@ -689,6 +709,9 @@ void MiscPatches::init() {
dlogr(" Done", DL_INIT);
}
// Highlight "Radiated" in red color when the player is under the influence of negative effects of radiation
HookCalls(ListDrvdStats_hook, { 0x43549C, 0x4354BE });
// Increase the max text width of the information card in the character screen
SafeWriteBatch<BYTE>(145, {0x43ACD5, 0x43DD37}); // 136, 133