Changed the implementation of AutoQuickSave

* now it sets the number of pages used for quick saving.

Added related macros for controlling the save slot with scripts.
This commit is contained in:
NovaRain
2021-08-12 15:24:13 +08:00
parent 25b8933d7b
commit cc29d548fe
7 changed files with 179 additions and 101 deletions
+5 -5
View File
@@ -494,12 +494,12 @@ UseScrollingQuestsList=1
ExtraSaveSlots=0
;To use more than one save slot for quick saving (F6 key) without picking a slot beforehand, set the next two lines
;AutoQuickSave sets how many save slots on a page you want to use for quick saving (valid range: 1..10)
;AutoQuickSavePage is the page number to use (valid range: 1..1000) if ExtraSaveSlots is enabled
;The quick saves will be rotated from the first slot on the page to the n-th slot
;AutoQuickSave sets how many pages you want to use for quick saving (valid range: 1..10)
;AutoQuickSavePage is the page number to start at (valid range: 1..1000, if ExtraSaveSlots is enabled)
;The quick saves will be rotated from the first slot on the page to the last slot on the n-th page
;Set to 0 to disable. AutoQuickSave will use the current selected page if AutoQuickSavePage is disabled
AutoQuickSave=0
AutoQuickSavePage=0
AutoQuickSavePage=1
;Set to 1 to speed up the HP/AC counter animations
;Set to 2 to update the HP/AC counters instantly
@@ -649,7 +649,7 @@ ExplosionsEmitLight=0
;Set to 1 to enable the new arrays behavior (default behavior)
;Set to 0 for backward compatibility with pre-3.4 scripts
arraysBehavior=1
ArraysBehavior=1
;Set to 1 to add proper checks to see if there is enough ammo to attack with weapons that use multiple ammo per shot
CheckWeaponAmmoCost=0
+16 -7
View File
@@ -257,16 +257,10 @@
if (get_flags(obj1) bwand FLAG_MULTIHEX) then distance--; \
if (get_flags(obj2) bwand FLAG_MULTIHEX) then distance--
/* sfall metarule3 function macros */
// sets the number of days (range 1...127) for the Frank Horrigan encounter, or disable the encounter if days is set to 0
#define set_horrigan_days(day) metarule3(200, day, 0, 0)
// clears the keyboard input buffer, use it in the HOOK_KEYPRESS hook to clear keyboard events before calling functions that are waiting for keyboard input
#define clear_keyboard_buffer metarule3(201, 0, 0, 0)
// checks if the specified PID number exists in the list of registered protos
#define check_pid(pid) (get_proto_data(pid, 0) != -1)
/* sfall_funcX macros */
#define add_extra_msg_file(name) sfall_func1("add_extra_msg_file", name)
#define add_global_timer_event(time, fixedParam) sfall_func2("add_g_timer_event", time, fixedParam)
@@ -365,4 +359,19 @@
#define unwield_slot(critter, slot) sfall_func2("unwield_slot", critter, slot)
#define win_fill_color(x, y, width, height, color) sfall_func5("win_fill_color", x, y, width, height, color)
/* sfall metarule3 function macros */
// sets the number of days (range 1...127) for the Frank Horrigan encounter, or disable the encounter if days is set to 0
#define set_horrigan_days(day) metarule3(200, day, 0, 0)
// clears the keyboard input buffer, use it in the HOOK_KEYPRESS hook to clear keyboard events before calling functions that are waiting for keyboard input
#define clear_keyboard_buffer metarule3(201, 0, 0, 0)
// functions to control the save slot
// Note: page and slot here are 0-indexed instead of 1-indexed displayed in game
#define get_current_save_slot metarule3(1000, 0, 0, 0) // returns the amount: page + slot
#define set_current_save_slot(page, slot) metarule3(1001, page, slot, 0)
#define get_current_quick_save_page metarule3(1002, 0, 0, 0)
#define get_current_quick_save_slot metarule3(1003, 0, 0, 0)
#define set_current_quick_save_slot(page, slot, check) metarule3(1004, page, slot, check) // check: 1 - don't check slot when saving
#endif
+109 -68
View File
@@ -23,14 +23,23 @@
#include "ExtraSaveSlots.h"
DWORD LSPageOffset = 0;
static long LSPageOffset = 0;
static long LSButtDN = 0;
static BYTE* SaveLoadSurface = nullptr;
static const char* filename = "%s\\savegame\\slotdat.ini";
static void SavePageOffsets() {
long ExtraSaveSlots_GetSaveSlot() {
return LSPageOffset + *ptr_slot_cursor;
}
void ExtraSaveSlots_SetSaveSlot(long page, long slot) {
if (ExtraSaveSlots_GetQuickSavePage() >= 0 && page >= 0 && page <= 9990) LSPageOffset = page - (page % 10);;
if (slot >= 0 && slot < 10) *ptr_slot_cursor = slot;
}
// save last slot position values to file
static long save_page_offsets() {
char SavePath[MAX_PATH], buffer[6];
sprintf_s(SavePath, MAX_PATH, filename, *ptr_patches);
@@ -40,16 +49,8 @@ static void SavePageOffsets() {
_itoa_s(LSPageOffset, buffer, 10);
WritePrivateProfileStringA("POSITION", "PageOffset", buffer, SavePath);
}
static void __declspec(naked) save_page_offsets(void) {
__asm {
// save last slot position values to file
call SavePageOffsets;
// restore original code
mov eax, dword ptr ds:[FO_VAR_lsgwin];
retn;
}
return *ptr_lsgwin; // restore original code
}
static void LoadPageOffsets() {
@@ -71,13 +72,12 @@ static void __declspec(naked) load_page_offsets(void) {
__asm {
// load last slot position values from file
call LoadPageOffsets;
// restore original code
mov edx, 0x50A480; // ASCII "SAV"
mov edx, 0x50A480; // ASCII "SAV" (restore original code)
retn;
}
}
static void CreateButtons() {
static long create_page_buttons() {
DWORD winRef = *ptr_lsgwin;
// left button -10 | X | Y | W | H |HOn |HOff |BDown |BUp |PicUp |PicDown |? |ButType
@@ -90,14 +90,8 @@ static void CreateButtons() {
fo_win_register_button(winRef, 248, 60, 24, 20, -1, 0x500, 0x551, 0x151, 0, 0, 0, 32);
// Set Number button
fo_win_register_button(winRef, 140, 60, 60, 20, -1, -1, 'p', -1, 0, 0, 0, 32);
}
static void __declspec(naked) create_page_buttons(void) {
__asm {
call CreateButtons;
mov eax, 0x65; // restore original code
retn;
}
return 101; // restore original value
}
static void SetPageNum() {
@@ -212,12 +206,12 @@ static long __fastcall CheckPage(long button) {
break;
case 0x14D: // right button
LSPageOffset += 10;
if (LSPageOffset > 9990) LSPageOffset -= 10000; // to the first page
if (LSPageOffset >= 10000) LSPageOffset -= 10000; // to the first page
__asm call gsound_red_butt_press_;
break;
case 0x151: // fast right PGDN button
LSPageOffset += 100;
if (LSPageOffset > 9990) LSPageOffset -= 10000;
if (LSPageOffset >= 10000) LSPageOffset -= 10000;
__asm call gsound_red_butt_press_;
break;
case 'p': // p/P button pressed - start SetPageNum func
@@ -234,15 +228,17 @@ static long __fastcall CheckPage(long button) {
static void __declspec(naked) check_page_buttons(void) {
__asm {
pushad;
push eax;
push ecx;
mov ecx, eax;
call CheckPage;
test eax, eax;
popad;
jnz CheckUp;
pop ecx;
pop eax;
jnz checkUp;
add dword ptr ds:[esp], 26; // set return to button pressed code
jmp GetSlotList_; // reset page save list func
CheckUp:
checkUp:
// restore original code
cmp eax, 0x148; // up button
retn;
@@ -323,16 +319,16 @@ static void DrawPageText() {
static void __declspec(naked) draw_page_text(void) {
__asm {
pushad;
push eax;
call DrawPageText;
popad;
mov ebp, 0x57; // restore original code
pop eax;
mov ebp, 87; // restore original code
retn;
}
}
// add page num offset when reading and writing various save data files
static void __declspec(naked) AddPageOffset01(void) {
static void __declspec(naked) add_page_offset_hack1(void) {
__asm {
mov eax, dword ptr ds:[FO_VAR_slot_cursor]; // list position 0-9
add eax, LSPageOffset; // add page num offset
@@ -341,7 +337,7 @@ static void __declspec(naked) AddPageOffset01(void) {
}
// getting info for the 10 currently displayed save slots from save.dats
static void __declspec(naked) AddPageOffset02(void) {
static void __declspec(naked) add_page_offset_hack2(void) {
__asm {
push 0x50A514; // ASCII "SAVE.DAT"
lea eax, [ebx + 1];
@@ -352,7 +348,7 @@ static void __declspec(naked) AddPageOffset02(void) {
}
// printing current 10 slot numbers
static void __declspec(naked) AddPageOffset03(void) {
static void __declspec(naked) add_page_offset_hack3(void) {
__asm {
inc eax;
add eax, LSPageOffset; // add page num offset
@@ -363,34 +359,38 @@ static void __declspec(naked) AddPageOffset03(void) {
static void EnableSuperSaving() {
// save/load button setup func
MakeCall(0x47D80D, create_page_buttons);
MakeCall(0x47D80D, create_page_buttons); // LSGameStart_
// Draw button text
MakeCall(0x47E6E8, draw_page_text);
MakeCall(0x47E6E8, draw_page_text); // ShowSlotList_
// check save/load buttons
const DWORD checkPageBtnsAddr[] = {0x47BD49, 0x47CB1C};
const DWORD checkPageBtnsAddr[] = {0x47BD49, 0x47CB1C}; // SaveGame_, LoadGame_
MakeCalls(check_page_buttons, checkPageBtnsAddr);
// save current page and list positions to file on load/save scrn exit
MakeCall(0x47D828, save_page_offsets);
MakeCall(0x47D828, save_page_offsets); // LSGameEnd_
// load saved page and list positions from file
MakeCall(0x47B82B, load_page_offsets);
MakeCall(0x47B82B, load_page_offsets); // InitLoadSave_
// Add Load/Save page offset to Load/Save folder number
const DWORD AddPageOffset01Addr[] = {
0x47B929, 0x47D8DB, 0x47D9B0, 0x47DA34, 0x47DABF, 0x47DB58, 0x47DBE9,
0x47DC9C, 0x47EC77, 0x47F5AB, 0x47F694, 0x47F6EB, 0x47F7FB, 0x47F892,
0x47FB86, 0x47FC3A, 0x47FCF2, 0x480117, 0x4801CF, 0x480234, 0x480310,
0x4803F3, 0x48049F, 0x480512, 0x4805F2, 0x480767, 0x4807E6, 0x480839,
0x4808D3
const DWORD AddPageOffset1Addr[] = {
0x47B929, // SaveGame_
0x47D8DB, 0x47D9B0, 0x47DA34, 0x47DABF, 0x47DB58, 0x47DBE9, // SaveSlot_
0x47DC9C, // LoadSlot_
0x47EC77, // LoadTumbSlot_
0x47F5AB, 0x47F694, 0x47F6EB, 0x47F7FB, 0x47F892, // GameMap2Slot_
0x47FB86, 0x47FC3A, 0x47FCF2, // SlotMap2Game_
0x480117, 0x4801CF, 0x480234, 0x480310, // SaveBackup_
0x4803F3, 0x48049F, 0x480512, 0x4805F2, // RestoreSave_
0x480767, 0x4807E6, 0x480839, 0x4808D3 // EraseSave_
};
MakeCalls(AddPageOffset01, AddPageOffset01Addr);
MakeCalls(add_page_offset_hack1, AddPageOffset1Addr);
MakeJump(0x47E5E1, AddPageOffset02);
MakeJump(0x47E5E1, add_page_offset_hack2); // GetSlotList_
MakeCall(0x47E756, AddPageOffset03);
MakeCall(0x47E756, add_page_offset_hack3); // ShowSlotList_
}
static void GetSaveFileTime(char* filename, FILETIME* ftSlot) {
@@ -407,51 +407,77 @@ static void GetSaveFileTime(char* filename, FILETIME* ftSlot) {
};
}
static const char* commentFmt = "%02d/%02d/%d - %02d:%02d:%02d";
static const char* autoFmt = "AUTO: %02d/%02d/%d - %02d:%02d:%02d";
static const char* quickFmt = "QUICK: %02d/%02d/%d - %02d:%02d:%02d";
static void CreateSaveComment(char* bufstr) {
static void CreateSaveComment(char* bufstr, bool isAuto) {
SYSTEMTIME stUTC, stLocal;
GetSystemTime(&stUTC);
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
char buf[30];
sprintf_s(buf, commentFmt, stLocal.wDay, stLocal.wMonth, stLocal.wYear, stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
strcpy(bufstr, buf);
const char* fmt = (isAuto) ? autoFmt : quickFmt;
sprintf_s(bufstr, 30, fmt, stLocal.wDay, stLocal.wMonth, stLocal.wYear, stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
}
static long autoQuickSave = 0;
static long quickSavePage = 0;
static long quickSavePageInit = -1;
static long quickSavePageCount;
static long currentPageCount;
static long quickSavePage = -1;
static long quickSaveSlot = 0;
static long dontCheckSlot = 0;
static bool qFirst = true;
static FILETIME ftPrevSlot;
static DWORD __stdcall QuickSaveGame(DbFile* file, char* filename) {
long currSlot = *ptr_slot_cursor;
if (dontCheckSlot) {
if (file) fo_db_fclose(file);
} else {
// for quick feature
if (file) { // This slot is not empty
fo_db_fclose(file);
FILETIME ftCurrSlot;
GetSaveFileTime(filename, &ftCurrSlot);
if (currSlot == 0 || ftCurrSlot.dwHighDateTime > ftPrevSlot.dwHighDateTime ||
if (currSlot == 0 ||
ftCurrSlot.dwHighDateTime > ftPrevSlot.dwHighDateTime ||
(ftCurrSlot.dwHighDateTime == ftPrevSlot.dwHighDateTime && ftCurrSlot.dwLowDateTime > ftPrevSlot.dwLowDateTime))
{
ftPrevSlot.dwHighDateTime = ftCurrSlot.dwHighDateTime;
ftPrevSlot.dwLowDateTime = ftCurrSlot.dwLowDateTime;
if (++currSlot > autoQuickSave) {
currSlot = 0;
} else {
*ptr_slot_cursor = currSlot;
if (!qFirst && currSlot < 9) {
*ptr_slot_cursor = ++quickSaveSlot;
return 0x47B929; // check next slot
}
currSlot = 0; // set if currSlot >= 9
qFirst = false;
}
}
// next save slot
if (++quickSaveSlot >= 10) {
quickSaveSlot = 0;
// next page
if (quickSavePageCount > 1 && quickSavePageInit != -1) {
if (++currentPageCount >= quickSavePageCount) {
currentPageCount = 0;
quickSavePage = quickSavePageInit;
} else if (quickSavePage <= 9980) {
quickSavePage += 10;
}
}
}
}
// Save to slot
*ptr_slot_cursor = currSlot;
LSData* saveData = (LSData*)FO_VAR_LSData;
CreateSaveComment(saveData[currSlot].comment);
CreateSaveComment(saveData[currSlot].comment, dontCheckSlot != 0);
*ptr_quick_done = 1;
return 0x47B9A4; // normal return
@@ -471,13 +497,28 @@ static void __declspec(naked) SaveGame_hack0() {
static void __declspec(naked) SaveGame_hack1() {
__asm {
mov ds:[FO_VAR_slot_cursor], 0;
mov eax, quickSaveSlot;
mov ds:[FO_VAR_slot_cursor], eax;
mov eax, quickSavePage;
mov LSPageOffset, eax;
retn;
}
}
long ExtraSaveSlots_GetQuickSavePage() {
return quickSavePage;
}
long ExtraSaveSlots_GetQuickSaveSlot() {
return quickSaveSlot;
}
void ExtraSaveSlots_SetQuickSaveSlot(long page, long slot, long check) {
if (quickSavePage >= 0 && page >= 0 && page <= 9990) quickSavePage = page - (page % 10);
if (slot >= 0 && slot < 10) quickSaveSlot = slot;
dontCheckSlot = check;
}
void ExtraSaveSlots_Init() {
bool extraSaveSlots = (GetConfigInt("Misc", "ExtraSaveSlots", 0) != 0);
if (extraSaveSlots) {
@@ -486,19 +527,19 @@ void ExtraSaveSlots_Init() {
dlogr(" Done", DL_INIT);
}
autoQuickSave = GetConfigInt("Misc", "AutoQuickSave", 0);
if (autoQuickSave > 0) {
quickSavePageCount = GetConfigInt("Misc", "AutoQuickSave", 0);
if (quickSavePageCount > 0) {
dlog("Applying auto quick save patch.", DL_INIT);
if (autoQuickSave > 10) autoQuickSave = 10;
autoQuickSave--; // reserved slot count
if (quickSavePageCount > 10) quickSavePageCount = 10;
quickSavePage = GetConfigInt("Misc", "AutoQuickSavePage", 0);
quickSavePage = GetConfigInt("Misc", "AutoQuickSavePage", 1);
if (quickSavePage > 1000) quickSavePage = 1000;
if (extraSaveSlots && quickSavePage > 0) {
quickSavePage = (quickSavePage - 1) * 10;
quickSavePageInit = quickSavePage;
MakeCall(0x47B923, SaveGame_hack1, 1);
} else {
} else { // for quickSavePage == 0
SafeWrite8(0x47B923, 0x89);
SafeWrite32(0x47B924, 0x5193B83D); // mov [slot_cursor], edi = 0
}
+7 -2
View File
@@ -18,7 +18,12 @@
#pragma once
extern DWORD LSPageOffset;
void ExtraSaveSlots_Init();
void ExtraSaveSlots_Exit();
long ExtraSaveSlots_GetSaveSlot();
void ExtraSaveSlots_SetSaveSlot(long page, long slot);
long ExtraSaveSlots_GetQuickSavePage();
long ExtraSaveSlots_GetQuickSaveSlot();
void ExtraSaveSlots_SetQuickSaveSlot(long page, long slot, long check);
+2 -2
View File
@@ -1942,8 +1942,8 @@ void HookScripts_Init() {
HookCalls(SwitchHandHook, switchHandHkAddr);
MakeJump(0x4713A9, UseArmorHack); // old 0x4713A3
MakeJump(0x476491, DropIntoContainerHack);
MakeJump(0x471338, DropIntoContainerHandSlotHack);
MakeJump(0x4712AB, DropIntoContainerHandSlotHack);
const DWORD dropIntoContHandHkAddr[] = {0x471338, 0x4712AB};
MakeJumps(DropIntoContainerHandSlotHack, dropIntoContHandHkAddr);
HookCall(0x471200, MoveInventoryHook);
HookCall(0x476549, DropAmmoIntoWeaponHook); // old 0x476588
const DWORD actionCurObjDropHkAddr[] = {
+1 -1
View File
@@ -139,7 +139,7 @@ static void __stdcall RunOnAfterGameStarted() {
}
void GetSavePath(char* buf, char* ftype) {
sprintf(buf, "%s\\savegame\\slot%.2d\\sfall%s.sav", *ptr_patches, *ptr_slot_cursor + 1 + LSPageOffset, ftype); //add SuperSave Page offset
sprintf(buf, "%s\\savegame\\slot%.2d\\sfall%s.sav", *ptr_patches, ExtraSaveSlots_GetSaveSlot() + 1, ftype); //add SuperSave Page offset
}
static void __stdcall SaveGame2() {
+23
View File
@@ -18,6 +18,7 @@
#include "main.h"
#include "FalloutEngine.h"
#include "ExtraSaveSlots.h"
#define HorriganEncounterDays (0x4C06EA)
#define HorriganEncounterCheck (0x4C06D8)
@@ -29,6 +30,13 @@ static bool HorriganEncounterDisabled = false;
enum MetaruleFunction : long {
SET_HORRIGAN_ENCOUNTER = 200, // sets the number of days for the Frank Horrigan encounter or disable encounter
CLEAR_KEYBOARD_BUFFER = 201, // clears the keyboard input buffer, should be used in the HOOK_KEYPRESS hook to clear keyboard events in some cases
// for save slots
GET_CURRENT_SAVE_SLOT = 1000,
SET_CURRENT_SAVE_SLOT = 1001,
GET_CURRENT_QSAVE_PAGE = 1002,
GET_CURRENT_QSAVE_SLOT = 1003,
SET_CURRENT_QSAVE_SLOT = 1004,
};
/*
@@ -55,6 +63,21 @@ static long __fastcall op_metarule3_ext(long metafunc, long* args) {
case CLEAR_KEYBOARD_BUFFER:
__asm call kb_clear_;
break;
case GET_CURRENT_SAVE_SLOT:
result = ExtraSaveSlots_GetSaveSlot();
break;
case SET_CURRENT_SAVE_SLOT:
ExtraSaveSlots_SetSaveSlot(args[0], args[1]);
break;
case GET_CURRENT_QSAVE_PAGE:
result = ExtraSaveSlots_GetQuickSavePage();
break;
case GET_CURRENT_QSAVE_SLOT:
result = ExtraSaveSlots_GetQuickSaveSlot();
break;
case SET_CURRENT_QSAVE_SLOT:
ExtraSaveSlots_SetQuickSaveSlot(args[0], args[1], args[2]);
break;
default:
fo_debug_printf("\nOPCODE ERROR: metarule3(%d, ...) - metarule function number does not exist.\n > Script: %s, procedure %s.",
metafunc, (*ptr_currentProgram)->fileName, fo_findCurrentProc(*ptr_currentProgram));