diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index a84b9dea..8d7992b9 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -10,6 +10,7 @@ namespace sfall { using namespace fo; using namespace Fields; +using namespace ObjectFlag; static DWORD critterBody = 0; static DWORD sizeOnBody = 0; @@ -388,30 +389,66 @@ static void __declspec(naked) queue_clear_type_mem_free_hook() { static void __declspec(naked) partyMemberCopyLevelInfo_hook_stat_level() { __asm { nextArmor: - mov eax, esi - call fo::funcoffs::inven_worn_ - test eax, eax - jz noArmor - and byte ptr [eax+0x27], 0xFB // Unset the flag of equipped armor - jmp nextArmor + mov eax, esi; + call fo::funcoffs::inven_worn_; + test eax, eax; + jz noArmor; + and byte ptr [eax + flags+3], ~Worn >> 24; // Unset the flag of equipped armor + jmp nextArmor; noArmor: - mov eax, esi - jmp fo::funcoffs::stat_level_ + mov eax, esi; + jmp fo::funcoffs::stat_level_; } } static void __declspec(naked) correctFidForRemovedItem_hook_adjust_ac() { __asm { - call fo::funcoffs::adjust_ac_ + call fo::funcoffs::adjust_ac_; nextArmor: - mov eax, esi - call fo::funcoffs::inven_worn_ - test eax, eax - jz end - and byte ptr [eax+0x27], 0xFB // Unset flag of equipped armor - jmp nextArmor + mov eax, esi; + call fo::funcoffs::inven_worn_; + test eax, eax; + jz end; + and byte ptr [eax + flags+3], ~Worn >> 24; // Unset flag of equipped armor + jmp nextArmor; end: - retn + retn; + } +} + +static void __declspec(naked) op_move_obj_inven_to_obj_hook() { + __asm { + jz skip; // source == dude + mov eax, edx; + call fo::funcoffs::isPartyMember_; + test eax, eax; // is source a party member? + jnz skip; + retn; // must be eax = 0 +skip: + mov eax, edx; + call fo::funcoffs::inven_worn_; + cmp edx, ecx; // source(edx) == dude(ecx) + jz dudeFix; + test eax, eax; + jz end; + mov ecx, edx; + xor ebx, ebx; // new armor + xchg eax, edx; // set: eax - source, edx - removed armor + call fo::funcoffs::adjust_ac_; // fix for party member + mov edx, ecx; + xor eax, eax; +end: + retn; // must be eax = 0 +dudeFix: + test eax, eax; + jz equipped; // no armor + // additionally check flag of equipped armor for dude + test byte ptr [eax + flags+3], Worn >> 24; + jnz equipped; + xor eax, eax; +equipped: + or cl, 1; // reset ZF + retn; } } @@ -825,7 +862,7 @@ static void __declspec(naked) op_wield_obj_critter_adjust_ac_hook() { 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 + imul eax, edx, 204; // multiply record size 204 bytes by number of NPC records in party.txt mov ebx, eax; // copy total record size for later memset call fo::funcoffs::mem_malloc_; // malloc the necessary memory jmp partyMember_init_End; // call memset to set all malloc'ed memory to 0 @@ -1646,16 +1683,16 @@ end: static void __declspec(naked) op_obj_can_hear_obj_hack() { __asm { - mov eax, [esp + 0x28 - 0x28 + 4]; // target - mov edx, [esp + 0x28 - 0x24 + 4]; // source + mov eax, [esp + 0x28 - 0x28 + 4]; // target + mov edx, [esp + 0x28 - 0x24 + 4]; // source retn; } } static void __declspec(naked) ai_best_weapon_hook() { __asm { - mov eax, [esp + 0xF4 - 0x10 + 4]; // prev.item - jmp fo::funcoffs::item_w_perk_; + mov eax, [esp + 0xF4 - 0x10 + 4]; // prev.item + jmp fo::funcoffs::item_w_perk_; } } @@ -1676,11 +1713,11 @@ static void __declspec(naked) wmSetupRandomEncounter_hook() { static void __declspec(naked) inven_obj_examine_func_hack() { __asm { mov edx, dword ptr ds:[0x519064]; // inven_display_msg_line - cmp edx, 2; // 2 or more lines + cmp edx, 2; // >2 ja fix; retn; fix: - cmp edx, 9; // 8 lines (half of the display window) + cmp edx, 5; // 4 lines ja limit; dec edx; sub eax, 3; @@ -1688,7 +1725,7 @@ fix: add eax, 3; retn; limit: - mov eax, 57; + mov eax, 30; retn; } } @@ -1894,9 +1931,9 @@ skip: static void __declspec(naked) op_attack_hook() { __asm { - mov esi, dword ptr [esp + 0x3C + 4]; // free_move - mov ebx, dword ptr [esp + 0x40 + 4]; // add amount damage to target - jmp fo::funcoffs::gdialogActive_; + mov esi, dword ptr [esp + 0x3C + 4]; // free_move + mov ebx, dword ptr [esp + 0x40 + 4]; // add amount damage to target + jmp fo::funcoffs::gdialogActive_; } } @@ -1964,8 +2001,8 @@ isLoad: static void __declspec(naked) JesseContainerFid() { __asm { - dec edx; // set fid to -1 - jmp fo::funcoffs::obj_new_; + dec edx; // set fid to -1 + jmp fo::funcoffs::obj_new_; } } @@ -2053,11 +2090,11 @@ static void __declspec(naked) obj_load_dude_hook1() { static void __declspec(naked) PrintAMList_hook() { __asm { - cmp ebp, 20; // max line count - jle skip; - mov ebp, 20; + cmp ebp, 20; // max line count + jle skip; + mov ebp, 20; skip: - jmp fo::funcoffs::qsort_; + jmp fo::funcoffs::qsort_; } } @@ -2323,9 +2360,9 @@ void BugFixes::init() // Missing game initialization LoadGameHook::OnGameInit() += MusicVolInitialization; - // fix vanilla negate operator on float values + // Fix vanilla negate operator on float values MakeCall(0x46AB68, NegateFixHack); - // fix incorrect int-to-float conversion + // Fix incorrect int-to-float conversion // op_mult: SafeWrite16(0x46A3F4, 0x04DB); // replace operator to "fild 32bit" SafeWrite16(0x46A3A8, 0x04DB); @@ -2397,6 +2434,10 @@ void BugFixes::init() dlog("Applying fix for armor reducing NPC original stats when removed.", DL_INIT); HookCall(0x495F3B, partyMemberCopyLevelInfo_hook_stat_level); HookCall(0x45419B, correctFidForRemovedItem_hook_adjust_ac); + // Fix for move_obj_inven_to_obj function + HookCall(0x45C49A, op_move_obj_inven_to_obj_hook); + SafeWrite16(0x45C496, 0x9090); + SafeWrite8(0x45C4A3, 0x75); // jmp > jnz dlogr(" Done", DL_INIT); //} @@ -2512,19 +2553,21 @@ void BugFixes::init() // Fix for op_lookup_string_proc_ engine function not searching the last procedure in a script SafeWrite8(0x46C7AC, 0x76); // jb > jbe + // Update the AC counter //if (GetConfigInt("Misc", "WieldObjCritterFix", 1)) { dlog("Applying wield_obj_critter fix.", DL_INIT); - SafeWrite8(0x456912, 0x1E); + SafeWrite8(0x456912, 0x1E); // jnz 0x456931 HookCall(0x45697F, op_wield_obj_critter_adjust_ac_hook); 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); - SafeWrite8(0x494063, 6); // loop should look for a potential 6th stage + 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 - MakeJump(0x494224, NPCStage6Fix2); dlogr(" Done", DL_INIT); //} diff --git a/sfall/Modules/HeroAppearance.cpp b/sfall/Modules/HeroAppearance.cpp index 5e3f52a1..0321573e 100644 --- a/sfall/Modules/HeroAppearance.cpp +++ b/sfall/Modules/HeroAppearance.cpp @@ -45,7 +45,7 @@ BYTE *charScrnBackSurface = nullptr; DWORD charRotTick = 0; DWORD charRotOri = 0; -bool raceButtions = false, styleButtions = false; +bool raceButtons = false, styleButtons = 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 @@ -198,7 +198,7 @@ static __declspec(noinline) int _stdcall LoadHeroDat(unsigned int race, unsigned } const char sex = GetSex(); - bool folderIsExist = false, datIsExist = false; + bool folderIsExist = false, heroDatIsExist = 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) { @@ -213,17 +213,17 @@ static __declspec(noinline) int _stdcall LoadHeroDat(unsigned int race, unsigned heroPathPtr[1]->isDat = 1; } if (folderIsExist) heroPathPtr[0]->next = heroPathPtr[1]; - datIsExist = true; + heroDatIsExist = true; } else if (!folderIsExist) { return -1; // no .dat files and folder } - heroPathPtr[1]->next = nullptr; + //heroPathPtr[1]->next = nullptr; tempPathPtr = &heroPathPtr[1 - folderIsExist]; // set path for selected appearance - heroPathPtr[0 + datIsExist]->next = &fo::var::paths[0]; // heroPathPtr[] >> foPaths + heroPathPtr[0 + heroDatIsExist]->next = &fo::var::paths[0]; // heroPathPtr[] >> foPaths if (style != 0) { - datIsExist = false, folderIsExist = false; + bool raceDatIsExist = 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) { @@ -238,14 +238,13 @@ static __declspec(noinline) int _stdcall LoadHeroDat(unsigned int race, unsigned racePathPtr[1]->isDat = 1; } if (folderIsExist) racePathPtr[0]->next = racePathPtr[1]; - datIsExist = true; + raceDatIsExist = 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 = &fo::var::paths[0]; // insert racePathPtr in chain path: heroPathPtr[] >> racePathPtr[] >> foPaths + heroPathPtr[0 + heroDatIsExist]->next = racePathPtr[1 - folderIsExist]; // set path for selected race base appearance + racePathPtr[0 + raceDatIsExist]->next = &fo::var::paths[0]; // insert racePathPtr in chain path: heroPathPtr[] >> racePathPtr[] >> foPaths } return 0; } @@ -356,13 +355,13 @@ static long _stdcall AddHeroCritNames() { // art_init_ critterListSize = critterArt.total / 2; critterArraySize = critterListSize * 13; - char *CritList = critterArt.names; // critter list offset - char *HeroList = CritList + critterArraySize; // set start of hero critter list after regular critter list + char *CritList = critterArt.names; // critter list offset + char *HeroList = CritList + critterArraySize; // set start of hero critter list after regular critter list memset(HeroList, 0, critterArraySize); - for (DWORD i = 0; i < critterListSize; i++) { // copy critter name list to hero name list - *HeroList = '_'; // insert a '_' char at the front of new hero critt names. fallout wont load the same name twice + for (DWORD i = 0; i < critterListSize; i++) { // copy critter name list to hero name list + *HeroList = '_'; // insert a '_' char at the front of new hero critt names. fallout wont load the same name twice memcpy(HeroList + 1, CritList, 11); HeroList += 13; CritList += 13; @@ -442,11 +441,11 @@ void _stdcall SetNewCharAppearanceGlobals() { void _stdcall SetHeroStyle(int newStyleVal) { if (!HeroAppearance::appModEnabled || newStyleVal == currentStyleVal) return; - if (LoadHeroDat(currentRaceVal, newStyleVal, true) != 0) { // if new style cannot be set + if (LoadHeroDat(currentRaceVal, newStyleVal, true) != 0) { // if new style cannot be set if (currentRaceVal == 0 && newStyleVal == 0) { - currentStyleVal = 0; // ignore error if appearance = default + currentStyleVal = 0; // ignore error if appearance = default } else { - LoadHeroDat(currentRaceVal, currentStyleVal); // reload original style + LoadHeroDat(currentRaceVal, currentStyleVal); // reload original style } } else { currentStyleVal = newStyleVal; @@ -459,10 +458,10 @@ void _stdcall SetHeroStyle(int newStyleVal) { void _stdcall SetHeroRace(int newRaceVal) { if (!HeroAppearance::appModEnabled || newRaceVal == currentRaceVal) return; - if (LoadHeroDat(newRaceVal, 0, true) != 0) { // if new race fails with style at 0 + if (LoadHeroDat(newRaceVal, 0, true) != 0) { // if new race fails with style at 0 if (newRaceVal == 0) { currentRaceVal = 0; - currentStyleVal = 0; // ignore if appearance = default + currentStyleVal = 0; // ignore if appearance = default } else { LoadHeroDat(currentRaceVal, currentStyleVal); // reload original race & style } @@ -1104,7 +1103,7 @@ static void __declspec(naked) AddCharScrnButtons() { fo::func::win_register_button(WinRef, 332, 0, 82, 32, -1, -1, 0x501, -1, 0, 0, 0, 0); fo::func::win_register_button(WinRef, 332, 226, 82, 32, -1, -1, 0x502, -1, 0, 0, 0, 0); - if (fo::var::glblmode == 1 && (styleButtions || raceButtions)) { // equals 1 if new char screen - equals 0 if ingame char screen + if (fo::var::glblmode == 1 && (styleButtons || raceButtons)) { // equals 1 if new char screen - equals 0 if ingame char screen if (newButtonSurface == nullptr) { newButtonSurface = new BYTE [20 * 18 * 4]; @@ -1129,11 +1128,11 @@ static void __declspec(naked) AddCharScrnButtons() { frmSurface = nullptr; } - if (raceButtions) { // race selection buttons + if (raceButtons) { // race selection buttons fo::func::win_register_button(WinRef, 348, 37, 20, 18, -1, -1, -1, 0x511, newButtonSurface, newButtonSurface + (20 * 18), 0, 0x20); fo::func::win_register_button(WinRef, 374, 37, 20, 18, -1, -1, -1, 0x513, newButtonSurface + (20 * 18 * 2), newButtonSurface + (20 * 18 * 3), 0, 0x20); } - if (styleButtions) { // style selection buttons + if (styleButtons) { // style selection buttons fo::func::win_register_button(WinRef, 348, 199, 20, 18, -1, -1, -1, 0x512, newButtonSurface, newButtonSurface + (20 * 18), 0, 0x20); fo::func::win_register_button(WinRef, 374, 199, 20, 18, -1, -1, -1, 0x514, newButtonSurface + (20 * 18 * 2), newButtonSurface + (20 * 18 * 3), 0, 0x20); } @@ -1222,10 +1221,10 @@ static void __declspec(naked) FixCharScrnBack() { fo::func::art_ptr_unlock(FrmObj); // frm background for char screen Appearance button - if (fo::var::glblmode == 1 && (styleButtions || raceButtions)) { + if (fo::var::glblmode && (styleButtons || raceButtons)) { FrmSurface = fo::func::art_ptr_lock_data(BuildFrmId(fo::OBJ_TYPE_INTRFACE, 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 + if (raceButtons) sub_draw(69, 20, 640, 480, 281, 319, FrmSurface, 640, 480, 337, 36, charScrnBackSurface, 0); // button backround top + if (styleButtons) sub_draw(69, 20, 640, 480, 281, 319, FrmSurface, 640, 480, 337, 198, charScrnBackSurface, 0); // button backround bottom fo::func::art_ptr_unlock(FrmObj); } FrmSurface = nullptr; @@ -1388,12 +1387,12 @@ static void EnableHeroAppearanceMod() { // 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; + raceButtons = 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; + styleButtons = true; } // Check if new Appearance char scrn button pushed (editor_design_) diff --git a/sfall/Modules/Scripting/Arrays.cpp b/sfall/Modules/Scripting/Arrays.cpp index f7765a65..fd1adff2 100644 --- a/sfall/Modules/Scripting/Arrays.cpp +++ b/sfall/Modules/Scripting/Arrays.cpp @@ -156,7 +156,7 @@ void sArrayVar::clearRange( int from, int to /*= -1*/ ) void sArrayVar::clearAll() { - for (auto it = val.begin(); it != val.end(); ++it) { + for (std::vector::iterator it = val.begin(); it != val.end(); ++it) { it->clearData(); } } @@ -586,7 +586,7 @@ static void MapSort(sArrayVar& arr, int type) { arr.val.clear(); arr.keyHash.clear(); for (size_t i = 0; i < vmap.size(); ++i) { - auto el = arr.val.size(); + size_t el = arr.val.size(); if (sortByValue) { arr.val.emplace_back(vmap[i].second); // map value > key arr.val.emplace_back(vmap[i].first); // map key > value diff --git a/sfall/Modules/Scripting/Handlers/Objects.cpp b/sfall/Modules/Scripting/Handlers/Objects.cpp index 86a37ff2..7586e193 100644 --- a/sfall/Modules/Scripting/Handlers/Objects.cpp +++ b/sfall/Modules/Scripting/Handlers/Objects.cpp @@ -435,13 +435,23 @@ void sf_get_loot_object(OpcodeContext& ctx) { } void sf_get_object_data(OpcodeContext& ctx) { - BYTE* object_ptr = (BYTE*)ctx.arg(0).asObject(); - ctx.setReturn(*(long*)(object_ptr + ctx.arg(1).asInt()), DataType::INT); + DWORD result = 0; + DWORD* object_ptr = (DWORD*)ctx.arg(0).rawValue(); + if (*(object_ptr - 1) != 0xFEEDFACE) { + ctx.printOpcodeError("%s() - invalid object pointer.", ctx.getMetaruleName()); + } else { + result = *(long*)((BYTE*)object_ptr + ctx.arg(1).rawValue()); + } + ctx.setReturn(result, DataType::INT); } void sf_set_object_data(OpcodeContext& ctx) { - BYTE* object_ptr = (BYTE*)ctx.arg(0).asObject(); - *(long*)(object_ptr + ctx.arg(1).asInt()) = ctx.arg(2).asInt(); + DWORD* object_ptr = (DWORD*)ctx.arg(0).rawValue(); + if (*(object_ptr - 1) != 0xFEEDFACE) { + ctx.printOpcodeError("%s() - invalid object pointer.", ctx.getMetaruleName()); + } else { + *(long*)((BYTE*)object_ptr + ctx.arg(1).rawValue()) = ctx.arg(2).rawValue(); + } } void sf_get_object_ai_data(OpcodeContext& ctx) {