From e3a3ff25407c5b8a6b381d20ae0731cbbe425e83 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 28 Sep 2019 10:52:48 +0800 Subject: [PATCH] Improved file searching for hero appearance mod (#251) * now it will search files in .dat files and folders simultaneously. * files in folders have higher priority than .dat files. --- sfall/BugFixes.cpp | 25 +++--- sfall/HeroAppearance.cpp | 170 ++++++++++++++++++++++----------------- 2 files changed, 113 insertions(+), 82 deletions(-) diff --git a/sfall/BugFixes.cpp b/sfall/BugFixes.cpp index c6d624714..ce8db4968 100644 --- a/sfall/BugFixes.cpp +++ b/sfall/BugFixes.cpp @@ -19,6 +19,10 @@ static const DWORD ScriptTargetAddr[] = { 0x456AA4, // op_use_obj_ }; +/* + Saving a list of PIDs for saved drug effects + Note: the sequence of saving and loading the list is very important! +*/ std::list drugsPid; static void __fastcall DrugPidPush(int pid) { @@ -56,6 +60,7 @@ bool DrugsLoadFix(HANDLE file) { } return false; } +/////////////////////////////////////////////////////////////////////////////// void ResetBodyState() { __asm mov critterBody, 0; @@ -807,22 +812,22 @@ static void __declspec(naked) op_wield_obj_critter_adjust_ac_hook() { } } -static const DWORD NPCStage6Fix1End = 0x493D16; +static const DWORD partyMember_init_End = 0x493D16; static void __declspec(naked) NPCStage6Fix1() { __asm { - imul eax, edx, 204; // necessary memory = number of NPC records in party.txt * record size - mov ebx, eax; // copy total record size for later memset - call mem_malloc_; // malloc the necessary memory - jmp NPCStage6Fix1End; // call memset to set all malloc'ed memory to 0 + imul eax, edx, 204; // necessary memory = number of NPC records in party.txt * record size + mov ebx, eax; // copy total record size for later memset + call mem_malloc_; // malloc the necessary memory + jmp partyMember_init_End; // call memset to set all malloc'ed memory to 0 } } -static const DWORD NPCStage6Fix2End = 0x49423A; +static const DWORD partyMemberGetAIOptions_End = 0x49423A; static void __declspec(naked) NPCStage6Fix2() { __asm { - imul edx, edx, 204; // NPC number as listed in party.txt * record size - mov eax, ds:[_partyMemberAIOptions]; // get starting offset of internal NPC table - jmp NPCStage6Fix2End; // eax+edx = offset of specific NPC record + imul edx, 204; // multiply record size 204 bytes by NPC number as listed in party.txt + mov eax, dword ptr ds:[_partyMemberAIOptions]; // get starting offset of internal NPC table + jmp partyMemberGetAIOptions_End; // eax + edx = offset of specific NPC record } } @@ -2442,7 +2447,7 @@ void BugFixesInit() //if (GetPrivateProfileIntA("Misc", "NPCLevelFix", 1, ini)) { dlog("Applying NPC level fix.", DL_INIT); - HookCall(0x495BC9, (void*)0x495E51); + HookCall(0x495BC9, (void*)0x495E51); // jz 0x495E7F > jz 0x495E51 dlogr(" Done", DL_INIT); //} diff --git a/sfall/HeroAppearance.cpp b/sfall/HeroAppearance.cpp index 0bef696e2..1aaf1ba55 100644 --- a/sfall/HeroAppearance.cpp +++ b/sfall/HeroAppearance.cpp @@ -39,6 +39,7 @@ BYTE *charScrnBackSurface = nullptr; DWORD charRotTick = 0; DWORD charRotOri = 0; +bool raceButtions = false, styleButtions = false; int currentRaceVal = 0, currentStyleVal = 0; // holds Appearance values to restore after global reset in NewGame2 function in LoadGameHooks.cpp DWORD critterListSize = 0, critterArraySize = 0; // Critter art list size @@ -51,8 +52,9 @@ struct sPath { }; sPath **tempPathPtr = (sPath**)_paths; -sPath *heroPathPtr = nullptr; -sPath *racePathPtr = nullptr; +// index: 0 - only folder (w/o extension .dat), 1 - file or folder .dat +sPath *heroPathPtr[2] = {nullptr, nullptr}; +sPath *racePathPtr[2] = {nullptr, nullptr}; // for word wrapping typedef struct LineNode { @@ -801,47 +803,66 @@ static char _stdcall GetSex() { static __declspec(noinline) int _stdcall LoadHeroDat(unsigned int race, unsigned int style, bool flush = false) { if (flush) RefreshArtCache(); - if (heroPathPtr->pDat) { // unload previous Dats - UnloadDat(heroPathPtr->pDat); - heroPathPtr->pDat = nullptr; - heroPathPtr->isDat = 0; + if (heroPathPtr[1]->pDat) { // unload previous Dats + UnloadDat(heroPathPtr[1]->pDat); + heroPathPtr[1]->pDat = nullptr; + heroPathPtr[1]->isDat = 0; } - if (racePathPtr->pDat) { - UnloadDat(racePathPtr->pDat); - racePathPtr->pDat = nullptr; - racePathPtr->isDat = 0; + if (racePathPtr[1]->pDat) { + UnloadDat(racePathPtr[1]->pDat); + racePathPtr[1]->pDat = nullptr; + racePathPtr[1]->isDat = 0; } const char sex = GetSex(); - - sprintf_s(heroPathPtr->path, 64, appearancePathFmt, sex, race, style, ".dat"); - int result = GetFileAttributes(heroPathPtr->path); - if (result != INVALID_FILE_ATTRIBUTES && !(result & FILE_ATTRIBUTE_DIRECTORY)) { // check if Dat exists for selected appearance - heroPathPtr->pDat = LoadDat(heroPathPtr->path); - heroPathPtr->isDat = 1; - } else { - sprintf_s(heroPathPtr->path, 64, appearancePathFmt, sex, race, style, ""); - if (GetFileAttributes(heroPathPtr->path) == INVALID_FILE_ATTRIBUTES) // check if folder exists for selected appearance - return -1; + bool folderIsExist = false, datIsExist = false; + // check if folder exists for selected appearance + sprintf_s(heroPathPtr[0]->path, 64, appearancePathFmt, sex, race, style, ""); + if (GetFileAttributes(heroPathPtr[0]->path) != INVALID_FILE_ATTRIBUTES) { + folderIsExist = true; + } + // check if Dat exists for selected appearance + sprintf_s(heroPathPtr[1]->path, 64, appearancePathFmt, sex, race, style, ".dat"); + int result = GetFileAttributes(heroPathPtr[1]->path); + if (result != INVALID_FILE_ATTRIBUTES) { + if (!(result & FILE_ATTRIBUTE_DIRECTORY)) { + heroPathPtr[1]->pDat = LoadDat(heroPathPtr[1]->path); + heroPathPtr[1]->isDat = 1; + } + if (folderIsExist) heroPathPtr[0]->next = heroPathPtr[1]; + datIsExist = true; + } else if (!folderIsExist) { + return -1; // no .dat files and folder } - tempPathPtr = &heroPathPtr; // set path for selected appearance - heroPathPtr->next = *(sPath**)_paths; + heroPathPtr[1]->next = nullptr; + tempPathPtr = &heroPathPtr[1 - folderIsExist]; // set path for selected appearance + heroPathPtr[0 + datIsExist]->next = *(sPath**)_paths; // heroPathPtr[] >> foPaths if (style != 0) { - sprintf_s(racePathPtr->path, 64, appearancePathFmt, sex, race, 0, ".dat"); - int result = GetFileAttributes(racePathPtr->path); - if (result != INVALID_FILE_ATTRIBUTES && !(result & FILE_ATTRIBUTE_DIRECTORY)) { // check if Dat exists for selected race base appearance - racePathPtr->pDat = LoadDat(racePathPtr->path); - racePathPtr->isDat = 1; - } else { - sprintf_s(racePathPtr->path, 64, appearancePathFmt, sex, race, 0, ""); + datIsExist = false, folderIsExist = false; + // check if folder exists for selected race base appearance + sprintf_s(racePathPtr[0]->path, 64, appearancePathFmt, sex, race, 0, ""); + if (GetFileAttributes(racePathPtr[0]->path) != INVALID_FILE_ATTRIBUTES) { + folderIsExist = true; } - - if (GetFileAttributes(racePathPtr->path) != INVALID_FILE_ATTRIBUTES) { // check if folder/Dat exists for selected race base appearance - heroPathPtr->next = racePathPtr; // set path for selected race base appearance - racePathPtr->next = *(sPath**)_paths; + // check if Dat (or folder) exists for selected race base appearance + sprintf_s(racePathPtr[1]->path, 64, appearancePathFmt, sex, race, 0, ".dat"); + int result = GetFileAttributes(racePathPtr[1]->path); + if (result != INVALID_FILE_ATTRIBUTES) { + if (!(result & FILE_ATTRIBUTE_DIRECTORY)) { + racePathPtr[1]->pDat = LoadDat(racePathPtr[1]->path); + racePathPtr[1]->isDat = 1; + } + if (folderIsExist) racePathPtr[0]->next = racePathPtr[1]; + datIsExist = true; + } else if (!folderIsExist) { + return 0; } + + long i = 0 + (heroPathPtr[1]->next != nullptr); + heroPathPtr[i]->next = racePathPtr[1 - folderIsExist]; // set path for selected race base appearance + racePathPtr[0 + datIsExist]->next = *(sPath**)_paths; // insert racePathPtr in chain path: heroPathPtr[] >> racePathPtr[] >> foPaths } return 0; } @@ -1392,7 +1413,7 @@ void _stdcall HeroSelectWindow(int raceStyleFlag) { BYTE *ConDraw = new BYTE [70 * 102]; int button = 0; - bool drawFlag = true; // redraw flag for char note pad + bool drawFlag = true; // redraw flag for char note pad DWORD RotSpeed = *(DWORD*)0x47066B; // get rotation speed - inventory rotation speed DWORD RedrawTick = 0, NewTick = 0, OldTick = 0; @@ -1434,7 +1455,7 @@ void _stdcall HeroSelectWindow(int raceStyleFlag) { } button = check_buttons(); - if (button == 0x148) { // previous style/race -up arrow button pushed + if (button == 0x148) { // previous style/race - up arrow button pushed PlayAcm("ib1p1xx1"); if (isStyle) { @@ -1745,7 +1766,7 @@ static void __declspec(naked) SexScrnEnd() { } } -// Create race and style selection buttons when creating a character +// Create race and style selection buttons when creating a character (hero) static void __declspec(naked) AddCharScrnButtons() { __asm { pushad; // prolog @@ -1757,10 +1778,10 @@ static void __declspec(naked) AddCharScrnButtons() { WinRef = *(DWORD*)_edit_win; // char screen window ref // race and style title buttons - WinRegisterButton(WinRef, 332, 0, 82, 32, -1, -1, 0x501, -1, 0, 0, 0, 0); + WinRegisterButton(WinRef, 332, 0, 82, 32, -1, -1, 0x501, -1, 0, 0, 0, 0); WinRegisterButton(WinRef, 332, 226, 82, 32, -1, -1, 0x502, -1, 0, 0, 0, 0); - if (*(DWORD*)_glblmode == 1) { // equals 1 if new char screen - equals 0 if ingame char screen + if (*(DWORD*)_glblmode == 1 && (styleButtions || raceButtions)) { // equals 1 if new char screen - equals 0 if ingame char screen if (newButtonSurface == nullptr) { newButtonSurface = new BYTE [20 * 18 * 4]; @@ -1785,20 +1806,13 @@ static void __declspec(naked) AddCharScrnButtons() { frmSurface = nullptr; } - - // check if Data exists for other races male or female, and if so enable race selection buttons - if (GetFileAttributes("Appearance\\hmR01S00") != INVALID_FILE_ATTRIBUTES || GetFileAttributes("Appearance\\hfR01S00") != INVALID_FILE_ATTRIBUTES || - GetFileAttributes("Appearance\\hmR01S00.dat") != INVALID_FILE_ATTRIBUTES || GetFileAttributes("Appearance\\hfR01S00.dat") != INVALID_FILE_ATTRIBUTES) { - // race selection buttons + if (raceButtions) { // race selection buttons WinRegisterButton(WinRef, 348, 37, 20, 18, -1, -1, -1, 0x511, newButtonSurface, newButtonSurface + (20 * 18), 0, 0x20); - WinRegisterButton(WinRef, 373, 37, 20, 18, -1, -1, -1, 0x513, newButtonSurface + (20 * 18 * 2), newButtonSurface + (20 * 18 * 3), 0, 0x20); + WinRegisterButton(WinRef, 374, 37, 20, 18, -1, -1, -1, 0x513, newButtonSurface + (20 * 18 * 2), newButtonSurface + (20 * 18 * 3), 0, 0x20); } - // check if Data exists for other styles male or female, and if so enable style selection buttons - if (GetFileAttributes("Appearance\\hmR00S01") != INVALID_FILE_ATTRIBUTES || GetFileAttributes("Appearance\\hfR00S01") != INVALID_FILE_ATTRIBUTES || - GetFileAttributes("Appearance\\hmR00S01.dat") != INVALID_FILE_ATTRIBUTES || GetFileAttributes("Appearance\\hfR00S01.dat") != INVALID_FILE_ATTRIBUTES) { - // style selection buttons + if (styleButtions) { // style selection buttons WinRegisterButton(WinRef, 348, 199, 20, 18, -1, -1, -1, 0x512, newButtonSurface, newButtonSurface + (20 * 18), 0, 0x20); - WinRegisterButton(WinRef, 373, 199, 20, 18, -1, -1, -1, 0x514, newButtonSurface + (20 * 18 * 2), newButtonSurface + (20 * 18 * 3), 0, 0x20); + WinRegisterButton(WinRef, 374, 199, 20, 18, -1, -1, -1, 0x514, newButtonSurface + (20 * 18 * 2), newButtonSurface + (20 * 18 * 3), 0, 0x20); } } @@ -1849,7 +1863,7 @@ static void __declspec(naked) FixCharScrnBack() { DWORD FrmObj, FrmMaskObj; // frm objects for char screen Appearance button BYTE *FrmSurface, *FrmMaskSurface; - FrmSurface = GetFrmSurface(BuildFrmId(6, 113), 0, 0, &FrmObj); + FrmSurface = GetFrmSurface(BuildFrmId(6, 113), 0, 0, &FrmObj); // "Use Item On" window sub_draw(81, 132, 292, 376, 163, 20, FrmSurface, 640, 480, 331, 63, charScrnBackSurface, 0); // char view win sub_draw(79, 31, 292, 376, 154, 228, FrmSurface, 640, 480, 331, 32, charScrnBackSurface, 0); // upper char view win sub_draw(79, 30, 292, 376, 158, 236, FrmSurface, 640, 480, 331, 195, charScrnBackSurface, 0); // lower char view win @@ -1885,12 +1899,12 @@ static void __declspec(naked) FixCharScrnBack() { UnloadFrm(FrmObj); // frm background for char screen Appearance button - FrmSurface = GetFrmSurface(BuildFrmId(6, 174), 0, 0, &FrmObj); // Pickchar frm - sub_draw(69, 20, 640, 480, 282, 320, FrmSurface, 640, 480, 337, 37, charScrnBackSurface, 0); // button backround top - sub_draw(69, 20, 640, 480, 282, 320, FrmSurface, 640, 480, 337, 199, charScrnBackSurface, 0); // button backround bottom - sub_draw(47, 16, 640, 480, 94, 394, FrmSurface, 640, 480, 347, 39, charScrnBackSurface, 0); // cover buttons pics top - sub_draw(47, 16, 640, 480, 94, 394, FrmSurface, 640, 480, 347, 201, charScrnBackSurface, 0); // cover buttons pics bottom - UnloadFrm(FrmObj); + if (*(DWORD*)_glblmode == 1 && (styleButtions || raceButtions)) { + FrmSurface = GetFrmSurface(BuildFrmId(6, 174), 0, 0, &FrmObj); // Pickchar frm + if (raceButtions) sub_draw(69, 20, 640, 480, 281, 319, FrmSurface, 640, 480, 337, 36, charScrnBackSurface, 0); // button backround top + if (styleButtions) sub_draw(69, 20, 640, 480, 281, 319, FrmSurface, 640, 480, 337, 198, charScrnBackSurface, 0); // button backround bottom + UnloadFrm(FrmObj); + } FrmSurface = nullptr; } @@ -2037,15 +2051,26 @@ static void EnableHeroAppearanceMod() { appModEnabled = true; // setup paths - heroPathPtr = new sPath; - racePathPtr = new sPath; - heroPathPtr->path = new char[64]; - racePathPtr->path = new char[64]; + heroPathPtr[0] = new sPath(); + racePathPtr[0] = new sPath(); + heroPathPtr[0]->path = new char[64]; + racePathPtr[0]->path = new char[64]; - heroPathPtr->isDat = 0; - racePathPtr->isDat = 0; - heroPathPtr->pDat = nullptr; - racePathPtr->pDat = nullptr; + heroPathPtr[1] = new sPath(); + racePathPtr[1] = new sPath(); + heroPathPtr[1]->path = new char[64]; + racePathPtr[1]->path = new char[64]; + + // check if Data exists for other races male or female, and if so enable race selection buttons + if (GetFileAttributes("Appearance\\hmR01S00") != INVALID_FILE_ATTRIBUTES || GetFileAttributes("Appearance\\hfR01S00") != INVALID_FILE_ATTRIBUTES || + GetFileAttributes("Appearance\\hmR01S00.dat") != INVALID_FILE_ATTRIBUTES || GetFileAttributes("Appearance\\hfR01S00.dat") != INVALID_FILE_ATTRIBUTES) { + raceButtions = true; + } + // check if Data exists for other styles male or female, and if so enable style selection buttons + if (GetFileAttributes("Appearance\\hmR00S01") != INVALID_FILE_ATTRIBUTES || GetFileAttributes("Appearance\\hfR00S01") != INVALID_FILE_ATTRIBUTES || + GetFileAttributes("Appearance\\hmR00S01.dat") != INVALID_FILE_ATTRIBUTES || GetFileAttributes("Appearance\\hfR00S01.dat") != INVALID_FILE_ATTRIBUTES) { + styleButtions = true; + } // Check if new Appearance char scrn button pushed (editor_design_) HookCall(0x431E9D, CheckCharScrnButtons); @@ -2150,14 +2175,15 @@ static void EnableHeroAppearanceMod() { void HeroAppearanceModExit() { if (!appModEnabled) return; - if (heroPathPtr) { - delete[] heroPathPtr->path; - delete heroPathPtr; - } - if (racePathPtr) { - delete[] racePathPtr->path; - delete racePathPtr; - } + delete[] heroPathPtr[0]->path; + delete[] heroPathPtr[1]->path; + delete heroPathPtr[0]; + delete heroPathPtr[1]; + + delete[] racePathPtr[0]->path; + delete[] racePathPtr[1]->path; + delete racePathPtr[0]; + delete racePathPtr[1]; } void HeroAppearanceModInit() {