Fixed the screen not returning to the player when moving a controlled critter to another elevation of the map.

Added DrugSaveFix option to fix saving the active effects of drugs.
Refactored some code in BugFixes.cpp.
This commit is contained in:
NovaRain
2019-03-04 15:27:00 +08:00
parent 15d762deb0
commit ab03186a1d
10 changed files with 150 additions and 109 deletions
+8 -4
View File
@@ -166,7 +166,6 @@ DebugEditorKey=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Misc]
;Time limit in years. Must be between -3 and 13
;Set to 0 if you want to die the instant you leave arroyo
;Set to -1 to remove the time limit, and automatically reset the date back to 2241 each time you would have reached it
@@ -484,13 +483,13 @@ NPCStage6Fix=0
;2 - Restoring the -1 AP bonus for HtH attacks (i.e. Fallout 1 behaviour)
FastShotFix=1
;Set to 1 to boost the maximum number of script names from 1450 to 10000
BoostScriptDialogLimit=0
;Allows you to edit the skill tables
;Point the next line at an ini file containing the replacement skill data
;SkillsFile=Skills.ini
;Set to 1 to boost the maximum number of script names from 1450 to 10000
BoostScriptDialogLimit=0
;To change the relationship between SPECIAL stats and derived stats, uncomment the next line
;See the Stats.ini in the modders pack for an example file
;DerivedStats=Stats.ini
@@ -661,6 +660,11 @@ PartyMemberExtraInfo=0
;that overrides First Aid/Doctor functions has very limited usefulness
PartyMemberSkillFix=0
;Set to 1 to fix the active effects of drugs not being saved properly
;If you have problems loading old save games saved while the player is under drug effects, disable this option
;Set to 0 to disable
DrugsSaveFix=1
;Set to 1 to skip loading game settings from a saved game, except for the game/combat difficulty settings
;Set to 2 to also skip loading the game/combat difficulty settings
SkipLoadingGameSettings=0
+5
View File
@@ -231,6 +231,7 @@ enum ProtoId : long
PID_STIMPAK = 40,
PID_BOTTLE_CAPS = 41,
PID_FIRST_AID_KIT = 47,
PID_RADAWAY = 48,
PID_ANTIDOTE = 49,
PID_DYNAMITE = 51,
PID_GEIGER_COUNTER = 52,
@@ -253,6 +254,8 @@ enum ProtoId : long
PID_NUKA_COLA = 106,
PID_RAD_X = 109,
PID_PSYCHO = 110,
PID_BEER = 124,
PID_BOOZE = 125,
PID_SUPER_STIMPAK = 144,
PID_ACTIVE_FLARE = 205,
PID_ACTIVE_DYNAMITE = 206,
@@ -264,9 +267,11 @@ enum ProtoId : long
PID_CHEMISTRY_MANUAL = 237,
PID_JET = 259,
PID_JET_ANTIDOTE = 260,
PID_DECK_OF_TRAGIC_CARDS = 306,
PID_GECK = 366,
PID_CAR_TRUNK = 455,
PID_JESSE_CONTAINER = 467,
PID_Player = 16777216,
PID_DRIVABLE_CAR = 33555441
};
+4 -1
View File
@@ -48,6 +48,7 @@ WRAP_WATCOM_FUNC2(long, combat_turn, GameObject*, critter, long, isDudeTurn)
WRAP_WATCOM_FUNC1(long, critter_is_dead, GameObject*, critter)
WRAP_WATCOM_FUNC1(void, EndLoad, DbFile*, file)
WRAP_WATCOM_FUNC1(long, folder_print_line, const char*, text)
WRAP_WATCOM_FUNC1(long, folder_print_seperator, const char*, text)
WRAP_WATCOM_FUNC1(long, game_get_global_var, long, globalVar)
WRAP_WATCOM_FUNC1(void, gdialogDisplayMsg, const char*, message)
WRAP_WATCOM_FUNC1(long, gmouse_3d_set_mode, long, mode)
@@ -86,9 +87,11 @@ WRAP_WATCOM_FUNC2(long, obj_pid_new, fo::GameObject*, object, long, pid)
// checks/unjams jammed locks
WRAP_WATCOM_FUNC1(long, obj_lock_is_jammed, GameObject*, object)
WRAP_WATCOM_FUNC1(void, obj_unjam_lock, GameObject*, object)
WRAP_WATCOM_FUNC1(void, pc_flag_on, long, flag)
WRAP_WATCOM_FUNC6(long, pick_death, GameObject*, attacker, GameObject*, target, GameObject*, weapon, long, amount, long, anim, long, hitFromBack)
WRAP_WATCOM_FUNC0(void, proto_dude_update_gender)
WRAP_WATCOM_FUNC2(long, queue_find_first, GameObject*, object, long, qType)
WRAP_WATCOM_FUNC2(long*, queue_find_first, GameObject*, object, long, qType)
WRAP_WATCOM_FUNC2(long*, queue_find_next, GameObject*, object, long, qType)
WRAP_WATCOM_FUNC3(long, register_object_animate, GameObject*, object, long, anim, long, delay)
WRAP_WATCOM_FUNC3(long, register_object_animate_and_hide, GameObject*, object, long, anim, long, delay)
// WRAP_WATCOM_FUNC3(long, register_object_animate_and_move_straight_, GameObject*, object;
+16
View File
@@ -709,6 +709,22 @@ struct Queue {
Queue* next;
};
struct QueueDrug {
DWORD pid;
fo::Stat stat0;
fo::Stat stat1;
fo::Stat stat2;
long amount0;
long amount1;
long amount2;
};
struct QueueAddict {
long init; // 1 = perk is not active yet
DWORD drugPid;
fo::Perk perkId; // effect of addiction
};
#pragma pack(1)
struct DrugInfoList {
DWORD itemPid;
+1
View File
@@ -48,6 +48,7 @@
#define FO_VAR_dialog_target_is_party 0x51884C
#define FO_VAR_dropped_explosive 0x5190E0
#define FO_VAR_drugInfoList 0x5191CC
#define FO_VAR_editor_message_file 0x56FCA8
#define FO_VAR_edit_win 0x57060C
#define FO_VAR_Educated 0x57082C
#define FO_VAR_elevation 0x631D2C
+1
View File
@@ -41,6 +41,7 @@ VAR_(dialog_target_is_party, DWORD)
VAR_(dropped_explosive, DWORD)
VARA(drugInfoList, DrugInfoList, 9)
VAR_(edit_win, DWORD)
VAR_(editor_message_file, MessageList)
VAR_(Educated, DWORD)
VAR_(elevation, DWORD)
VAR_(Experience_, DWORD)
+2 -2
View File
@@ -92,11 +92,11 @@ void Books::init() {
bool includeVanilla = (GetPrivateProfileIntA("main", "overrideVanilla", 0, iniBooks) == 0);
if (includeVanilla) BooksCount = 5;
int count = max(0, GetPrivateProfileIntA("main", "count", 0, iniBooks));
if (count > BooksMax) count = BooksMax;
int count = GetPrivateProfileIntA("main", "count", 0, iniBooks);
int n = 0;
if (count > 0) {
if (count > BooksMax) count = BooksMax;
books = new sBook[BooksCount + count];
if (includeVanilla) LoadVanillaBooks();
+84 -72
View File
@@ -192,97 +192,95 @@ skip:
}
}
static void __declspec(naked) item_d_check_addict_hack() {
static void __declspec(naked) item_d_check_addict_hack() { // replace engine function
__asm {
mov edx, 2 // type = addiction
cmp eax, -1 // Has drug_pid?
je skip // No
mov ebx, eax // ebx = drug_pid
mov eax, esi // eax = who
call fo::funcoffs::queue_find_first_
loopQueue:
test eax, eax // Has something in the list?
jz end // No
cmp ebx, dword ptr [eax+0x4] // drug_pid == queue_addict.drug_pid?
je end // Has specific addiction
mov eax, esi // eax = who
mov edx, 2 // type = addiction
call fo::funcoffs::queue_find_next_
jmp loopQueue
push 0x47A6A1; // return addr
mov edx, 2; // type = addiction
cmp eax, -1; // Has drug_pid?
jne skip; // No
mov eax, dword ptr ds:[FO_VAR_obj_dude];
jmp fo::funcoffs::queue_find_first_; // return player addiction
skip:
mov eax, dword ptr ds:[FO_VAR_obj_dude]
call fo::funcoffs::queue_find_first_
mov ebx, eax; // ebx = drug_pid
mov eax, esi; // eax = who
call fo::funcoffs::queue_find_first_;
loopQueue:
test eax, eax; // Has something in the list?
jz end; // No
cmp ebx, dword ptr [eax + 0x4]; // drug_pid == queue_addict.drug_pid?
je end; // Has specific addiction
mov eax, esi; // eax = who
mov edx, 2; // type = addiction
call fo::funcoffs::queue_find_next_;
jmp loopQueue;
end:
push 0x47A6A1
retn
retn;
}
}
static void __declspec(naked) remove_jet_addict() {
static void __declspec(naked) RemoveJetAddictFunc() {
__asm {
cmp eax, dword ptr ds:[FO_VAR_wd_obj]
jne end
cmp dword ptr [edx+0x4], PID_JET // queue_addict.drug_pid == PID_JET?
jne end
xor eax, eax
inc eax // Delete from queue
retn
cmp eax, dword ptr ds:[FO_VAR_wd_obj];
jne end;
cmp dword ptr [edx + 0x4], PID_JET; // queue_addict.drug_pid == PID_JET?
end:
xor eax, eax // Don't touch
retn
sete al; // 1 = Delete from queue, 0 = Don't touch
and eax, 0xFF;
retn;
}
}
static void __declspec(naked) item_d_take_drug_hack() {
__asm {
cmp dword ptr [eax], 0 // queue_addict.init
jne skip // Addiction is not active yet
mov edx, PERK_add_jet
mov eax, esi
call fo::funcoffs::perform_withdrawal_end_
cmp dword ptr [eax], 0; // queue_addict.init
jne skip; // Addiction is not active yet
mov edx, PERK_add_jet;
mov eax, esi;
call fo::funcoffs::perform_withdrawal_end_;
skip:
mov dword ptr ds:[FO_VAR_wd_obj], esi
mov eax, 2 // type = addiction
mov edx, offset remove_jet_addict
call fo::funcoffs::queue_clear_type_
push 0x479FD1
retn
mov dword ptr ds:[FO_VAR_wd_obj], esi;
mov eax, 2; // type = addiction
mov edx, offset RemoveJetAddictFunc;
call fo::funcoffs::queue_clear_type_;
push 0x479FD1;
retn;
}
}
static void __declspec(naked) item_d_load_hack() {
__asm {
sub esp, 4
mov [ebp], edi // edi->queue_drug
mov ecx, 7
mov esi, FO_VAR_drugInfoList + 12
sub esp, 4; // proto buf
mov [ebp], edi; // edi->queue_drug
mov ecx, 7;
mov esi, FO_VAR_drugInfoList + 12;
loopDrug:
cmp dword ptr [esi+8], 0 // drugInfoList.numeffects
je nextDrug
mov edx, esp
mov eax, [esi] // drugInfoList.pid
call fo::funcoffs::proto_ptr_
mov edx, [esp]
mov eax, [edx+0x24] // drug.stat0
cmp eax, [edi+0x4] // drug.stat0 == queue_drug.stat0?
jne nextDrug // No
mov eax, [edx+0x28] // drug.stat1
cmp eax, [edi+0x8] // drug.stat1 == queue_drug.stat1?
jne nextDrug // No
mov eax, [edx+0x2C] // drug.stat2
cmp eax, [edi+0xC] // drug.stat2 == queue_drug.stat2?
je foundPid // Yes
cmp dword ptr [esi + 8], 0; // drugInfoList.numeffects
je nextDrug;
mov edx, esp;
mov eax, [esi]; // drugInfoList.pid
call fo::funcoffs::proto_ptr_;
mov edx, [esp];
mov eax, [edx + 0x24]; // drug.stat0
cmp eax, [edi + 0x4]; // drug.stat0 == queue_drug.stat0?
jne nextDrug; // No
mov eax, [edx + 0x28]; // drug.stat1
cmp eax, [edi + 0x8]; // drug.stat1 == queue_drug.stat1?
jne nextDrug; // No
mov eax, [edx + 0x2C]; // drug.stat2
cmp eax, [edi + 0xC]; // drug.stat2 == queue_drug.stat2?
je foundPid; // Yes
nextDrug:
add esi, 12
loop loopDrug
add esi, 12;
dec ecx;
jnz loopDrug;
jz end;
foundPid:
jecxz end
mov eax, [esi] // drugInfoList.pid
mov [edi], eax // queue_drug.drug_pid
mov eax, [esi]; // drugInfoList.pid
mov [edi], eax; // queue_drug.drug_pid
end:
xor eax, eax
add esp, 4
retn
xor eax, eax;
add esp, 4;
retn;
}
}
@@ -652,7 +650,8 @@ found:
add edx, [esp+0x40] // inventory_offset
mov eax, ds:[FO_VAR_pud]
mov ecx, [eax] // itemsCount
jecxz skip
test ecx, ecx
jz skip
dec ecx
cmp edx, ecx
ja skip
@@ -676,13 +675,15 @@ static void __declspec(naked) drop_ammo_into_weapon_hook() {
jge skip // Yes
lea edx, [eax + inventory] // Inventory
mov ecx, [edx] // itemsCount
jcxz skip // inventory is empty (another excess check, but leave it)
test ecx, ecx
jz skip // inventory is empty (another excess check, but leave it)
mov edx, [edx+8] // FirstItem
nextItem:
cmp ebp, [edx] // Our weapon?
je foundItem // Yes
add edx, 8 // Go to the next
loop nextItem
dec ecx
jnz nextItem
jmp skip // Our weapon is not in inventory
foundItem:
cmp dword ptr [edx+4], 1 // Only one weapon?
@@ -1886,7 +1887,18 @@ void BugFixes::init()
// Fix for gaining stats from more than two doses of a specific chem after save-load
dlog("Applying fix for save-load unlimited drug use exploit.", DL_INIT);
MakeCall(0x47A243, item_d_load_hack);
if (GetConfigInt("Misc", "DrugsSaveFix", 0)) {
// games saved while the player is under drug effects will be incompatible
// item_d_save_
SafeWrite8(0x47A25C, 4);
SafeWrite8(0x47A262, 0);
// item_d_load_
SafeWrite8(0x47A1F6, 4);
SafeWrite8(0x47A1FB, 0xCA); // mov edx, esp > mov edx, ecx
SafeWrite8(0x47A21B, 0x27); // jnz 0x47A243
} else {
MakeCall(0x47A243, item_d_load_hack); // partial fix without breaking save game compatibility
}
dlogr(" Done", DL_INIT);
// Fix crash when leaving the map while waiting for someone to die of a super stimpak overdose
+3 -6
View File
@@ -16,8 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include <vector>
//#include <algorithm>
#include "..\main.h"
#include "..\FalloutEngine\Fallout2.h"
@@ -36,8 +35,6 @@ bool npcEngineLevelUp = true;
bool isControllingNPC = false;
bool skipCounterAnim = false;
static DWORD controlMode;
static std::vector<WORD> allowedCritterPids;
static int delayedExperience;
static bool switchHandHookInjected = false;
@@ -76,7 +73,6 @@ static void SaveRealDudeState() {
realDude.Experience = fo::var::Experience_;
realDude.free_perk = fo::var::free_perk;
realDude.unspent_skill_points = fo::var::curr_pc_stat[0];
//real_map_elevation = fo::var::map_elevation;
realDude.sneak_working = fo::var::sneak_working;
fo::SkillGetTags(realDude.tag_skill, 4);
@@ -154,6 +150,8 @@ static void SetCurrentDude(fo::GameObject* npc) {
static void RestoreRealDudeState() {
assert(realDude.obj_dude != nullptr);
fo::var::map_elevation = realDude.obj_dude->elevation;
fo::var::obj_dude = realDude.obj_dude;
fo::var::inven_dude = realDude.obj_dude;
fo::var::inven_pid = realDude.obj_dude->protoId;
@@ -169,7 +167,6 @@ static void RestoreRealDudeState() {
fo::var::Experience_ = realDude.Experience;
fo::var::free_perk = realDude.free_perk;
fo::var::curr_pc_stat[0] = realDude.unspent_skill_points;
//realDude.map_elevation = fo::var::map_elevation; -- why save elevation?
fo::var::sneak_working = realDude.sneak_working;
fo::SkillSetTags(realDude.tag_skill, 4);
@@ -402,7 +402,8 @@ argloopstart:
mov eax, ebp;
call fo::funcoffs::interpretPopLong_;
mov [esp + ecx * 4 - 0x4], eax;
loop argloopstart;
dec ecx;
jnz argloopstart;
//Error check
mov ecx, 4;
checkloopstart:
@@ -413,7 +414,8 @@ checkloopstart:
fild [esp + ecx * 4 + 0x4];
fstp [esp + ecx * 4 + 0x4];
paramWasFloat:
loop checkloopstart;
dec ecx;
jnz checkloopstart;
cmp word ptr [esp + 0x1a], VAR_TYPE_STR2;
jz next;
cmp word ptr [esp + 0x1a], VAR_TYPE_STR;