diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 474f39ec..3d4f6728 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -629,6 +629,9 @@ NumbersInDialogue=0 ;Set to 1 to use Fallout's normal text font instead of DOS-like font on the world map WorldMapFontPatch=0 +;Set to 1 to display experience points with the bonus from Swift Learner perk when gained from non-scripted situations +DisplaySwiftLearnerExp=1 + ;Set to 1 to display party member's current level/AC/addict flag on the combat control panel PartyMemberExtraInfo=0 diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index 23f990b2..eae50533 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -189,7 +189,7 @@ Critter arg1 - The critter that just died HOOK_FINDTARGET (hs_findtarget.int) -Runs when the ai is trying to pick a target in combat. Fallout first chooses a list of 4 likely suspects, then normally sorts them in order of weakness/distance/etc depending on the ai caps of the attacker. This hook replaces that sorting function, allowing you to sort the targets in some arbitrary way. Use sfall_return to give the 4 targets, in order of preference. All 4 must be given if you want to override normal sorting; if you want to specify less than 4 targets fill in the extra spaces with 0's. If you do not give 4 targets, the NPCs normal sorting mechanism will be used. +Runs when the ai is trying to pick a target in combat. Fallout first chooses a list of 4 likely suspects, then normally sorts them in order of weakness/distance/etc depending on the ai caps of the attacker. This hook replaces that sorting function, allowing you to sort the targets in some arbitrary way. Use sfall_return to give the 4 targets, in order of preference. All 4 must be given if you want to override normal sorting; if you want to specify less than 4 targets, fill in the extra spaces with 0's. If you do not give 4 targets, the NPCs normal sorting mechanism will be used. The return values can include critters that weren't in the list of possible targets, but the additional targets may still be discarded later on in the combat turn if they are out of the attackers perception or the chance of a successful hit is too low. The list of possible targets often includes duplicated entries. diff --git a/sfall/Bugs.cpp b/sfall/Bugs.cpp index 735e2e30..4c869dd6 100644 --- a/sfall/Bugs.cpp +++ b/sfall/Bugs.cpp @@ -1305,6 +1305,67 @@ end: } } +static DWORD expSwiftLearner; // experience points for print +static void __declspec(naked) statPCAddExperienceCheckPMs_hack() { + __asm { + mov expSwiftLearner, edi; + mov eax, dword ptr ds:[_Experience_]; + retn; + } +} + +static void __declspec(naked) combat_give_exps_hook() { + __asm { + call stat_pc_add_experience_; + mov ebx, expSwiftLearner; + retn; + } +} + +static const DWORD LootContainerExp_Ret = 0x4745E3; +static void __declspec(naked) loot_container_exp_hack() { + __asm { + mov edx, [esp + 0x150 - 0x18]; // experience + xchg edx, eax; + call stat_pc_add_experience_; + // engine code + cmp edx, 1; // from eax + jnz skip; + push expSwiftLearner; + mov ebx, [esp + 0x154 - 0x78 + 0x0C]; // msgfile.message + push ebx; + lea eax, [esp + 0x158 - 0x150]; // buf + push eax; + call sprintf_; + add esp, 0x0C; + mov eax, esp; + call display_print_; + // end code +skip: + jmp LootContainerExp_Ret; + } +} + +static void __declspec(naked) wmRndEncounterOccurred_hook() { + __asm { + call stat_pc_add_experience_; + cmp ecx, 110; + jnb skip; + push expSwiftLearner; + // engine code + push edx; + lea eax, [esp + 0x08 + 4]; + push eax; + call sprintf_; + add esp, 0x0C; + lea eax, [esp + 4]; + call display_print_; + // end code +skip: + retn; + } +} + static void __declspec(naked) op_obj_can_see_obj_hack() { __asm { mov eax, [esp + 0x2C - 0x28 + 4]; // source @@ -1804,6 +1865,17 @@ void BugsInit() // in their AI packages is set to stay_close/charge, or NPCsTryToSpendExtraAP is enabled HookCall(0x42A1A8, ai_move_steps_closer_hook); // 0x42B24D + // Display experience points with the bonus from Swift Learner perk when gained from non-scripted situations + if (GetPrivateProfileIntA("Misc", "DisplaySwiftLearnerExp", 1, ini)) { + dlog("Applying Swift Learner exp display patch.", DL_INIT); + MakeCall(0x4AFAEF, statPCAddExperienceCheckPMs_hack); + HookCall(0x4221E2, combat_give_exps_hook); + MakeJump(0x4745AE, loot_container_exp_hack); + SafeWrite16(0x4C0AB1, 0x23EB); // jmps 0x4C0AD6 + HookCall(0x4C0AEB, wmRndEncounterOccurred_hook); + dlogr(" Done", DL_INIT); + } + // Fix for obj_can_see_obj not checking if source and target objects are on the same elevation before calling // is_within_perception_ MakeCall(0x456B63, op_obj_can_see_obj_hack); diff --git a/sfall/SafeWrite.cpp b/sfall/SafeWrite.cpp index 608874b9..694651c1 100644 --- a/sfall/SafeWrite.cpp +++ b/sfall/SafeWrite.cpp @@ -37,13 +37,13 @@ void _stdcall SafeWrite32(DWORD addr, DWORD data) { void _stdcall SafeWriteStr(DWORD addr, const char* data) { DWORD oldProtect; - VirtualProtect((void *)addr, strlen(data)+1, PAGE_EXECUTE_READWRITE, &oldProtect); + VirtualProtect((void *)addr, strlen(data) + 1, PAGE_EXECUTE_READWRITE, &oldProtect); strcpy((char *)addr, data); - VirtualProtect((void *)addr, strlen(data)+1, oldProtect, &oldProtect); + VirtualProtect((void *)addr, strlen(data) + 1, oldProtect, &oldProtect); } void HookCall(DWORD addr, void* func) { - SafeWrite32(addr+1, (DWORD)func - (addr+5)); + SafeWrite32(addr + 1, (DWORD)func - (addr + 5)); } void MakeCall(DWORD addr, void* func) { diff --git a/sfall/SuperSave.cpp b/sfall/SuperSave.cpp index d86e7000..56f5c9ee 100644 --- a/sfall/SuperSave.cpp +++ b/sfall/SuperSave.cpp @@ -143,11 +143,7 @@ void SetPageNum() { if (NewTick - OldTick > 166) { // time to draw OldTick = NewTick; - if (blip == '_') { - blip = ' '; - } else { - blip = '_'; - } + blip = (blip == '_') ? ' ' : '_'; sprintf_s(TempText, 32, "#%d%c", tempPageOffset / 10 + 1, '_'); if (tempPageOffset == -1) {