Compare commits

...
9 Commits
Author SHA1 Message Date
NovaRain fe5f4bb2aa Changed the fix for multihex critter moving in combat to a more proper one (from Mr.Stalin)
Added AIBestWeaponFix option to ddraw.ini.
2018-09-02 18:08:37 +08:00
NovaRain 715b55dda8 Fixed multihex critters moving too close and overlapping their targets in combat (from Crafty)
Fixed critters not checking weapon perks properly when searching for the best weapon (from Mr.Stalin)
Changed BugFixes module to be initialized at the beginning.
2018-08-21 07:19:51 +08:00
NovaRain 1d7fd442b0 Minor edits to sfall-mods.ini. 2018-08-19 00:41:50 +08:00
NovaRain 9f0797f8ad Added extra comment for CarChargingFix to ddraw.ini. 2018-08-14 23:58:09 +08:00
NovaRain ccd897281f Fixed obj_can_see_obj not checking if source and target objects are on the same elevation before calling is_within_perception_ (from Mr.Stalin) 2018-08-10 22:54:07 +08:00
NovaRain d200262a2b Added a fix for the display issue in the pipboy when a quest list is too long with UseScrollingQuestsList diabled (from Mr.Stalin)
Added a fix for the clickability issue of holodisk list in the pipboy (from Mr.Stalin)
2018-08-06 22:04:21 +08:00
NovaRain d0c97f7118 Fixed an issue with file IDs of additional game msg files being shifted when a file in ExtraGameMsgFileList is missing.
Minor edit to the description of CityRepsList in ddraw.ini, to avoid misunderstanding.
Updated version number.
2018-07-28 22:46:59 +08:00
NovaRain 41c8722179 Merged a couple of fixes and minor improvements for 4.0.x from the develop branch:
* Fixed the game thinking you dropped an active explosive when the dropping is prevented with hs_inventorymove.
* Added "inventory_redraw" script function (from Mr.Stalin)
* NPC combat control mod now centers the screen on the controlled critter and has new options to display critter's name.
* Removed obsoleted WIN2K preprocessor defines.
Updated version number.
2018-07-16 09:14:01 +08:00
NovaRain 1b3b5dc523 Fixed premature assignment of arguments before the beginning of the hooks in InventoryHs.cpp. (#173)
(cherry picked from commit fff48407c3)
Updated version number.
2018-06-24 12:36:01 +08:00
21 changed files with 259 additions and 33 deletions
+14
View File
@@ -38,3 +38,17 @@ MotionScanner=0
;If you want to control only specific critters, uncomment the PIDList line and set a comma delimited list of PIDs
Mode=0
;PIDList=62,89,97,107,160,161
;Choose a notification box to display the name of the controlled critter above the interface bar. Must be between 5 and 9
;Set to 0 to disable
DisplayName=0
;Set the color of display name, available colors:
;0 - green
;1 - red
;2 - white
;3 - yellow
;4 - dark yellow
;5 - blue
;6 - purple
DisplayNameColor=0
+8 -3
View File
@@ -1,5 +1,5 @@
;sfall configuration settings
;v4.0.5
;v4.0.8
[Main]
;Change to 1 if you want to use command line args to tell sfall to use another ini file.
@@ -345,6 +345,10 @@ SkipOpeningMovies=0
;Set to 0 to disable
NPCsTryToSpendExtraAP=0
;Set to 1 to fix NPCs not checking weapon perks properly when searching for the best weapon
;Note that enabling this option can significantly affect the weapon choice of some NPCs in combat
AIBestWeaponFix=0
;Allows the use of tiles over 80*36 in size. sfall will just split and resave them at startup
;Set to 1 to check all tiles on started (slow)
;Set to 2 if you provide a XLtiles.lst file in art/tiles/ containing a list of the tile ids that need checking
@@ -366,7 +370,7 @@ Repair=293
;Remove window position rounding
RemoveWindowRounding=0
;Set to 1 to add scroll buttons to the pip boy quest list, and remove the quests per area limit
;Set to 1 to add scroll buttons to the pipboy quest list, and remove the quests per area limit
UseScrollingQuestsList=1
;Uncomment these lines to control the premade characters offered when starting a new game
@@ -375,7 +379,7 @@ UseScrollingQuestsList=1
;PremadeFIDs=201,203,202
;Use this line to modify the list of cities and their associated global variables used for city reputations
;Syntax is 'city id : global id', with each city/global pair separated by a comma.
;Syntax is 'city id:global id', with each city/global pair separated by a comma.
;CityRepsList=0:47,2:48,1:49,4:50,5:51,3:52,8:53,6:54,7:55,13:56,10:57,11:59,14:61,17:63,19:64,18:65,25:66,9:294,20:308
;Set this to a valid path to save a copy of the console contents
@@ -551,6 +555,7 @@ DontTurnOffSneakIfYouRun=0
CanSellUsedGeiger=1
;Set to 1 to fix the issue with being able to charge the car by using cells on other scenary/critters
;Set to 0 if another mod you're using has custom vehicles
CarChargingFix=1
;Set to 1 to skip weapon equip/unequip animations when performing various actions
Binary file not shown.
+27 -3
View File
@@ -12,12 +12,16 @@
*/
#include "..\headers\define.h"
#include "..\headers\command.h"
#include "main.h"
variable
configSection := "CombatControl",
controlMode,
pidList,
displayName,
displayNameColor,
inControl := false,
hasGeckoSkinning := false;
@@ -33,25 +37,45 @@ procedure combatturn_handler begin
if (status == 1
and (len_array(pidList) == 0 or scan_array(pidList, pid bwand 0xFFFFFF) != -1)
and (controlMode == 1 or party_member_obj(pid))) then begin
set_dude_obj(critter);
if hasGeckoSkinning then critter_add_trait(critter, TRAIT_PERK, PERK_gecko_skinning_perk, 1);
end else begin
if not(critter == real_dude_obj) then begin
set_dude_obj(critter);
if hasGeckoSkinning then critter_add_trait(critter, TRAIT_PERK, PERK_gecko_skinning_perk, 1);
inControl := true;
end
if inControl then begin
// center the screen on the controlled critter and remove roof tiles
move_to(dude_obj, dude_tile, dude_elevation);
if displayName then begin
set_iface_tag_text(displayName, obj_name(critter), displayNameColor);
show_iface_tag(displayName);
end
end
end else if inControl then begin
set_dude_obj(real_dude_obj);
if displayName then hide_iface_tag(displayName);
end
end
procedure gamemodechange_handler begin
if not(get_game_mode BWAND COMBAT) then inControl := false;
end
procedure start begin
if game_loaded and (sfall_ver_major >= 4) then begin
set_perk_ranks(PERK_gecko_skinning_perk, 1);
set_perk_level(PERK_gecko_skinning_perk, 999); // prevent it from appearing in the perk selection window
controlMode := GetConfig("CombatControl", "Mode", 0);
displayName := GetConfig("CombatControl", "DisplayName", 0);
displayNameColor := GetConfig("CombatControl", "DisplayNameColor", 0);
if (controlMode > 2) then controlMode := 0;
if (displayName < 5 or displayName > 9) then displayName := 0;
if (controlMode > 0) then begin
pidList := GetConfigListInt("CombatControl", "PIDList");
fix_array(pidList);
if has_trait(TRAIT_PERK, dude_obj, PERK_gecko_skinning_perk) then hasGeckoSkinning := true;
register_hook_proc(HOOK_COMBATTURN, combatturn_handler);
register_hook_proc(HOOK_GAMEMODECHANGE, gamemodechange_handler);
end
end
end
+1
View File
@@ -234,6 +234,7 @@
#define intface_is_hidden sfall_func0("intface_is_hidden")
#define intface_redraw sfall_func0("intface_redraw")
#define intface_show sfall_func0("intface_show")
#define inventory_redraw(invSide) sfall_func1("inventory_redraw", invSide)
#define item_weight(obj) sfall_func1("item_weight", obj)
#define lock_is_jammed(obj) sfall_func1("lock_is_jammed", obj)
#define outlined_object sfall_func0("outlined_object")
+1 -1
View File
@@ -497,7 +497,7 @@ int arg2 - event type: 1 - when the resting ends normally, -1 - when pressin
int arg3 - the hour part of the length of resting time
int arg4 - the minute part of the length of resting time
int ret1 - pass 1 to interrupt the resting
int ret1 - pass 1 to interrupt the resting, pass 0 to continue the rest if it was interrupted by pressing ESC key
-------------------------------------------
@@ -486,6 +486,10 @@ Some utility/math functions are available:
- The text is limited to 19 characters
- available colors: 0 - green, 1 - red, 2 - white, 3 - yellow, 4 - dark yellow, 5 - blue, 6 - purple
> void sfall_func1("inventory_redraw", int invSide)
- redraws inventory list in the inventory/use inventory item on/loot/barter screens
- invSide specifies which side needs to be redrawn: 0 - the player, 1 - target (container/NPC in loot/barter screens)
------------------------
------ MORE INFO -------
------------------------
+2
View File
@@ -31,6 +31,8 @@ WRAP_WATCOM_FUNC3(long, db_freadIntCount, DbFile*, file, DWORD*, dest, long, cou
WRAP_WATCOM_FUNC2(long, db_fwriteByte, DbFile*, file, long, value)
WRAP_WATCOM_FUNC2(long, db_fwriteInt, DbFile*, file, long, value)
WRAP_WATCOM_FUNC0(void, display_stats)
WRAP_WATCOM_FUNC3(void, display_inventory, long, inventoryOffset, long, visibleOffset, long, mode)
WRAP_WATCOM_FUNC4(void, display_target_inventory, long, inventoryOffset, long, visibleOffset, DWORD*, targetInventory, long, mode)
// perform combat turn for a given critter
WRAP_WATCOM_FUNC2(long, combat_turn, GameObject*, critter, long, isDudeTurn)
WRAP_WATCOM_FUNC1(long, critter_is_dead, GameObject*, critter)
+3
View File
@@ -40,6 +40,7 @@
#define FO_VAR_dialogue_switch_mode 0x518718
#define FO_VAR_dialog_target 0x518848
#define FO_VAR_dialog_target_is_party 0x51884C
#define FO_VAR_dropped_explosive 0x5190E0
#define FO_VAR_drugInfoList 0x5191CC
#define FO_VAR_edit_win 0x57060C
#define FO_VAR_Educated 0x57082C
@@ -67,6 +68,7 @@
#define FO_VAR_gsound_initialized 0x518E30
#define FO_VAR_hit_location_penalty 0x510954
#define FO_VAR_holo_flag 0x664529
#define FO_VAR_holodisk 0x6644F4
#define FO_VAR_holopages 0x66445C
#define FO_VAR_hot_line_count 0x6644F8
#define FO_VAR_i_fid 0x59E95C
@@ -150,6 +152,7 @@
#define FO_VAR_proto_main_msg_file 0x6647FC
#define FO_VAR_ptable 0x59E934
#define FO_VAR_pud 0x59E960
#define FO_VAR_quest_count 0x51C12C
#define FO_VAR_queue 0x6648C0
#define FO_VAR_quick_done 0x5193BC
#define FO_VAR_read_callback 0x51DEEC
+1
View File
@@ -37,6 +37,7 @@ VAR_(dialogue_state, DWORD)
VAR_(dialogue_switch_mode, DWORD)
VAR_(dialog_target, DWORD)
VAR_(dialog_target_is_party, DWORD)
VAR_(dropped_explosive, DWORD)
VAR_(drugInfoList, DWORD)
VAR_(edit_win, DWORD)
VAR_(Educated, DWORD)
+90 -2
View File
@@ -49,6 +49,14 @@ static void __declspec(naked) PipAlarm_hack() {
}
}
static void __declspec(naked) PipStatus_hook() {
__asm {
call fo::funcoffs::ListHoloDiskTitles_;
mov dword ptr ds:[FO_VAR_holodisk], ebx;
retn;
}
}
// corrects saving script blocks (to *.sav file) by properly accounting for actual number of scripts to be saved
static void __declspec(naked) scr_write_ScriptNode_hook() {
__asm {
@@ -603,7 +611,7 @@ static void __declspec(naked) op_wield_obj_critter_adjust_ac_hook() {
// Haenlomal
static void __declspec(naked) MultiHexFix() {
__asm {
xor ecx, ecx; // argument value for make_path_func: ecx=0 (unknown arg)
xor ecx, ecx; // argument value for make_path_func: ecx=0 (rotation data arg)
test byte ptr ds:[ebx+0x25], 0x08; // is target multihex?
mov ebx, dword ptr ds:[ebx+0x4]; // argument value for make_path_func: target's tilenum (end_tile)
je end; // skip if not multihex
@@ -613,6 +621,42 @@ end:
}
}
static const DWORD ai_move_steps_closer_run_object_ret = 0x42A169;
static void __declspec(naked) MultiHexCombatRunFix() {
__asm {
test byte ptr ds:[edi + 0x25], 0x08; // is target multihex?
jnz multiHex;
test byte ptr ds:[esi + 0x25], 0x08; // is source multihex?
jz runTile;
multiHex:
mov edx, dword ptr ds:[esp + 0x4]; // source's destination tilenum
cmp dword ptr ds:[edi + 0x4], edx; // target's tilenum
jnz runTile;
add esp, 4;
jmp ai_move_steps_closer_run_object_ret;
runTile:
retn;
}
}
static const DWORD ai_move_steps_closer_move_object_ret = 0x42A192;
static void __declspec(naked) MultiHexCombatMoveFix() {
__asm {
test byte ptr ds:[edi + 0x25], 0x08; // is target multihex?
jnz multiHex;
test byte ptr ds:[esi + 0x25], 0x08; // is source multihex?
jz moveTile;
multiHex:
mov edx, dword ptr ds:[esp + 0x4]; // source's destination tilenum
cmp dword ptr ds:[edi + 0x4], edx; // target's tilenum
jnz moveTile;
add esp, 4;
jmp ai_move_steps_closer_move_object_ret;
moveTile:
retn;
}
}
//checks if an attacked object is a critter before attempting dodge animation
static void __declspec(naked) action_melee_hack() {
__asm {
@@ -1121,6 +1165,29 @@ end:
}
}
static void __declspec(naked) op_obj_can_see_obj_hack() {
__asm {
mov eax, [esp + 0x2C - 0x28 + 4]; // source
mov ecx, [eax + 4]; // source.tile
cmp ecx, -1;
jz end;
mov eax, [eax + 0x28]; // source.elev
mov edi, [edx + 0x28]; // target.elev
cmp eax, edi; // check source.elev == target.elev
retn;
end:
dec ecx; // reset ZF
retn;
}
}
static void __declspec(naked) ai_best_weapon_hook() {
__asm {
mov eax, [esp + 0xF4 - 0x10 + 4]; // prev.item
jmp fo::funcoffs::item_w_perk_;
}
}
void BugFixes::init()
{
@@ -1137,9 +1204,13 @@ void BugFixes::init()
//}
// Fixes for clickability issue in Pip-Boy and exploit that allows to rest in places where you shouldn't be able to rest
dlog("Applying fix for Pip-Boy rest exploit.", DL_INIT);
dlog("Applying fix for Pip-Boy clickability issues and rest exploit.", DL_INIT);
MakeCall(0x4971C7, pipboy_hack);
MakeCall(0x499530, PipAlarm_hack);
// Fix for clickability issue of holodisk list
HookCall(0x497E9F, PipStatus_hook);
SafeWrite16(0x497E8C, 0xD389); // mov ebx, edx
SafeWrite32(0x497E8E, 0x90909090);
dlogr(" Done", DL_INIT);
// Fix for "Too Many Items" bug
@@ -1299,6 +1370,11 @@ void BugFixes::init()
dlog("Applying MultiHex Pathing Fix.", DL_INIT);
MakeCall(0x42901F, MultiHexFix);
MakeCall(0x429170, MultiHexFix);
// Fix for multihex critters moving too close and overlapping their targets in combat
MakeCall(0x42A14F, MultiHexCombatRunFix);
SafeWrite8(0x42A154, 0x90);
MakeCall(0x42A178, MultiHexCombatMoveFix);
SafeWrite8(0x42A17D, 0x90);
dlogr(" Done", DL_INIT);
//}
@@ -1436,6 +1512,18 @@ void BugFixes::init()
// Fix for critters killed in combat by scripting still being able to move in their combat turn if the distance parameter
// in their AI packages is set to stay_close/charge, or NPCsTryToSpendExtraAP is enabled
HookCall(0x42A1A8, ai_move_steps_closer_hook); // 0x42B24D
// 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);
SafeWrite16(0x456B76, 0x23EB); // jmp loc_456B9B (skip unused engine code)
// Fix for critters not checking weapon perks properly when searching for the best weapon
if (GetConfigInt("Misc", "AIBestWeaponFix", 0)) {
dlog("Applying AI best weapon choice fix.", DL_INIT);
HookCall(0x42954B, ai_best_weapon_hook);
dlogr(" Done", DL_INIT);
}
}
}
-4
View File
@@ -983,11 +983,7 @@ void Graphics::init() {
}
if (Graphics::mode == 4 || Graphics::mode == 5) {
dlog("Applying dx9 graphics patch.", DL_INIT);
#ifdef WIN2K
#define _DLL_NAME "d3dx9_42.dll"
#else
#define _DLL_NAME "d3dx9_43.dll"
#endif
HMODULE h = LoadLibraryEx(_DLL_NAME, 0, LOAD_LIBRARY_AS_DATAFILE);
if (!h) {
MessageBoxA(0, "You have selected graphics mode 4 or 5, but " _DLL_NAME " is missing\nSwitch back to mode 0, or install an up to date version of DirectX", "Error", 0);
+2
View File
@@ -42,6 +42,8 @@ void _stdcall BeginHook();
void _stdcall RunHookScript(DWORD hook);
void _stdcall EndHook();
#define HookBegin __asm pushad __asm call BeginHook __asm popad
#define hookbegin(a) __asm pushad __asm call BeginHook __asm popad __asm mov argCount, a
#define hookend __asm pushad __asm call EndHook __asm popad
+39 -11
View File
@@ -15,6 +15,7 @@ static const DWORD RemoveObjHookRet = 0x477497;
static void __declspec(naked) RemoveObjHook() {
__asm {
mov ecx, [esp + 8]; // call addr
HookBegin;
mov args[0], eax;
mov args[4], edx;
mov args[8], ebx;
@@ -22,7 +23,6 @@ static void __declspec(naked) RemoveObjHook() {
pushad;
}
BeginHook();
argCount = 4;
RunHookScript(HOOK_REMOVEINVENOBJ);
EndHook();
@@ -38,6 +38,7 @@ static void __declspec(naked) RemoveObjHook() {
static void __declspec(naked) MoveCostHook() {
__asm {
HookBegin;
mov args[0], eax;
mov args[4], edx;
call fo::funcoffs::critter_compute_ap_from_distance_
@@ -45,7 +46,6 @@ static void __declspec(naked) MoveCostHook() {
pushad;
}
BeginHook();
argCount = 3;
RunHookScript(HOOK_MOVECOST);
EndHook();
@@ -53,7 +53,7 @@ static void __declspec(naked) MoveCostHook() {
__asm {
popad;
cmp cRet, 1;
cmovge eax, rets[0];
cmovge eax, dword ptr rets[0];
retn;
}
}
@@ -78,16 +78,19 @@ static int __fastcall SwitchHandHook_Script(fo::GameObject* item, fo::GameObject
if (itemReplaced && fo::GetItemType(itemReplaced) == fo::item_type_weapon && fo::GetItemType(item) == fo::item_type_ammo) {
return -1; // to prevent inappropriate hook call after dropping ammo on weapon
}
BeginHook();
argCount = 3;
args[0] = (addr < 0x47136D) ? 1 : 2; // slot: 1 - left, 2 - right
args[1] = (DWORD)item;
args[2] = (DWORD)itemReplaced;
RunHookScript(HOOK_INVENTORYMOVE);
int tmp = PartyControl::SwitchHandHook(item);
if (tmp != -1) {
int result = PartyControl::SwitchHandHook(item);
if (result != -1) {
cRetTmp = 0;
SetHSReturn(tmp);
SetHSReturn(result);
}
EndHook();
@@ -162,10 +165,11 @@ skip:
// - if 0 is returned while dropping caps, selected amount - 1 will still disappear from inventory (fixed)
static DWORD nextHookDropSkip = 0;
static int dropResult = -1;
static const DWORD InvenActionObjDropRet = 0x473874;
static void __declspec(naked) InvenActionCursorObjDropHook() {
if (nextHookDropSkip) {
nextHookDropSkip = 0;
dropResult = -1;
goto skipHook;
} else {
__asm {
pushad;
@@ -180,6 +184,7 @@ static void __declspec(naked) InvenActionCursorObjDropHook() {
}
if (dropResult == -1) {
skipHook:
_asm call fo::funcoffs::obj_drop_;
}
_asm retn;
@@ -189,10 +194,28 @@ capsMultiDrop:
if (dropResult == -1) {
nextHookDropSkip = 1;
_asm call fo::funcoffs::item_remove_mult_;
} else {
_asm mov dword ptr [esp], 0x473874; // no caps drop
_asm retn;
}
_asm add esp, 4;
_asm jmp InvenActionObjDropRet; // no caps drop
}
static void __declspec(naked) InvenActionExplosiveDropHack() {
__asm {
pushad;
xor ecx, ecx; // no itemReplace
push 6; // event: item drop ground
call InventoryMoveHook_Script; // edx - item
cmp eax, -1; // ret value
popad;
jnz noDrop;
mov dword ptr ds:[FO_VAR_dropped_explosive], ebp; // overwritten engine code (ebp = 1)
mov nextHookDropSkip, ebp;
retn;
noDrop:
add esp, 4;
jmp InvenActionObjDropRet; // no drop
}
_asm retn;
}
static int __fastcall DropIntoContainer(DWORD ptrCont, DWORD item, DWORD addrCall) {
@@ -255,7 +278,7 @@ donothing:
/* Common InvenWield hook */
static void InvenWieldHook_Script(int flag) {
BeginHook();
argCount = 4;
args[3] = flag; // invenwield flag
RunHookScript(HOOK_INVENWIELD);
@@ -265,6 +288,7 @@ static void InvenWieldHook_Script(int flag) {
static void _declspec(naked) InvenWieldFuncHook() {
using namespace fo;
__asm {
HookBegin;
mov args[0], eax; // critter
mov args[4], edx; // item
mov args[8], ebx; // slot
@@ -288,6 +312,7 @@ static void _declspec(naked) InvenWieldFuncHook() {
// called when unwielding weapons
static void _declspec(naked) InvenUnwieldFuncHook() {
__asm {
HookBegin;
mov args[0], eax; // critter
mov args[8], edx; // slot
pushad;
@@ -310,6 +335,7 @@ static void _declspec(naked) InvenUnwieldFuncHook() {
static void _declspec(naked) CorrectFidForRemovedItemHook() {
__asm {
HookBegin;
mov args[0], eax; // critter
mov args[4], edx; // item
mov args[8], ebx; // item flag
@@ -367,6 +393,8 @@ void InitInventoryHookScripts() {
0x473851, 0x47386F,
0x47379A // caps multi drop
});
MakeCall(0x473807, InvenActionExplosiveDropHack); // drop active explosives
SafeWrite8(0x47380C, 0x90);
LoadHookScript("hs_invenwield", HOOK_INVENWIELD);
HookCalls(InvenWieldFuncHook, { 0x47275E, 0x495FDF });
+3 -1
View File
@@ -66,14 +66,16 @@ char* GetMsg(fo::MessageList *msgList, int msgRef, int msgNum) {
void ReadExtraGameMsgFiles() {
auto msgFileList = GetConfigList("Misc", "ExtraGameMsgFileList", "", 512);
if (msgFileList.size() > 0) {
int number = 0;
for (auto& msgName : msgFileList) {
std::string path = "game\\" + msgName + ".msg";
fo::MessageList* list = new fo::MessageList();
if (fo::func::message_load(list, (char*)path.data()) == 1) {
gExtraGameMsgLists.insert(std::make_pair(0x2000 + gExtraGameMsgLists.size(), list));
gExtraGameMsgLists.insert(std::make_pair(0x2000 + number, list));
} else {
delete list;
}
number++;
}
}
}
+31 -1
View File
@@ -24,12 +24,40 @@
namespace sfall
{
static bool outRangeFlag = false;
static DWORD calledflag = 0x0;
static DWORD called_quest_number = 0x0;
static DWORD total_quests = 0x0;
static DWORD curent_quest_page = 0x0;
static DWORD wait_flag = 0x0;
// Fix crash when the quest list is too long
static void __declspec(naked) PipStatus_hook_printfix() {
__asm {
test outRangeFlag, 0xFF;
jnz force;
call fo::funcoffs::_word_wrap_;
push eax;
movzx eax, word ptr [esp + 0x49C + 8];
dec eax;
shl eax, 1;
add eax, dword ptr ds:[FO_VAR_cursor_line];
cmp eax, dword ptr ds:[FO_VAR_bottom_line]; // check max
jb skip;
mov eax, dword ptr ds:[FO_VAR_quest_count];
sub eax, 2;
mov dword ptr [esp + 0x4BC - 0x24 + 8], eax; // set last counter
mov outRangeFlag, 1;
skip:
pop eax;
retn;
force:
or eax, -1; // force log error "out of range"
mov outRangeFlag, 0;
retn;
}
}
static void __declspec(naked) newhookpress() {
__asm {
push eax;
@@ -357,10 +385,12 @@ void QuestListPatch() {
}
void QuestList::init() {
if(GetConfigInt("Misc", "UseScrollingQuestsList", 0)) {
if (GetConfigInt("Misc", "UseScrollingQuestsList", 0)) {
dlog("Applying quests list patch ", DL_INIT);
QuestListPatch();
dlogr(" Done", DL_INIT);
} else {
HookCall(0x498186, PipStatus_hook_printfix); // fix "out of range" bug when printing a list of quests
}
}
@@ -460,5 +460,32 @@ void sf_set_iface_tag_text(OpcodeContext& ctx) {
}
}
void sf_inventory_redraw(OpcodeContext& ctx) {
int mode = -1;
DWORD loopFlag = GetLoopFlags();
if (loopFlag & INVENTORY) {
mode = 0;
} else if (loopFlag & INTFACEUSE) {
mode = 1;
} else if (loopFlag & INTFACELOOT) {
mode = 2;
} else if (loopFlag & BARTER) {
mode = 3;
} else {
return;
}
if (!ctx.arg(0).asBool()) {
int* stack_offset = (int*)FO_VAR_stack_offset;
stack_offset[fo::var::curr_stack * 4] = 0;
fo::func::display_inventory(0, -1, mode);
} else if (mode >= 2) {
int* target_stack_offset = (int*)FO_VAR_target_stack_offset;
target_stack_offset[fo::var::target_curr_stack * 4] = 0;
fo::func::display_target_inventory(0, -1, (DWORD*)fo::var::target_pud, mode);
fo::func::win_draw(fo::var::i_wid);
}
}
}
}
@@ -91,5 +91,7 @@ void sf_display_stats(OpcodeContext&);
void sf_set_iface_tag_text(OpcodeContext&);
void sf_inventory_redraw(OpcodeContext&);
}
}
@@ -94,6 +94,7 @@ static const SfallMetarule metarules[] = {
{"intface_is_hidden", sf_intface_is_hidden, 0, 0},
{"intface_redraw", sf_intface_redraw, 0, 0},
{"intface_show", sf_intface_show, 0, 0},
{"inventory_redraw", sf_inventory_redraw, 1, 1, {ARG_INT}},
{"item_weight", sf_item_weight, 1, 1, {ARG_OBJECT}},
{"lock_is_jammed", sf_lock_is_jammed, 1, 1, {ARG_OBJECT}},
{"outlined_object", sf_outlined_object, 0, 0},
+1 -1
View File
@@ -128,8 +128,8 @@ static void InitModules() {
auto& manager = ModuleManager::getInstance();
// initialize all modules
manager.add<SpeedPatch>();
manager.add<BugFixes>();
manager.add<SpeedPatch>();
manager.add<Graphics>();
manager.add<Input>();
manager.add<Movies>();

Some files were not shown because too many files have changed in this diff Show More