From e2ad5326071f77722c4f02c7ecf365af3ca6752d Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sun, 2 Jun 2024 09:12:56 +0800 Subject: [PATCH] Added a new attrType value to get_window_attribute Added PAUSEWIN (Ctrl+P) to LoadGameHook game modes. Fixed crash in interface_art_draw (when drawing beyond window bounds). Fixed assert fail when calling sfall_func7+ Edits to documents. --- artifacts/scripting/headers/sfall.h | 2 ++ artifacts/scripting/sfall function notes.md | 7 ++++--- sfall/Modules/LoadGameHook.cpp | 11 +++++++++++ sfall/Modules/LoadGameHook.h | 1 + sfall/Modules/Scripting/Handlers/Interface.cpp | 8 ++++++++ sfall/Modules/Scripting/OpcodeContext.h | 2 +- 6 files changed, 27 insertions(+), 4 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 309ad227..ed3ec52f 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -23,6 +23,7 @@ #define HEROWIN (0x40000) #define DIALOGVIEW (0x80000) #define COUNTERWIN (0x100000) // counter window for moving multiple items or setting a timer +#define PAUSEWIN (0x200000) // Ctrl+P pause window #define SPECIAL (0x80000000) // Valid arguments to register_hook_proc @@ -320,6 +321,7 @@ #define get_interface_y(winType) sfall_func2("get_window_attribute", winType, 2) #define get_interface_width(winType) sfall_func2("get_window_attribute", winType, 3) #define get_interface_height(winType) sfall_func2("get_window_attribute", winType, 4) +#define get_interface_id(winType) sfall_func2("get_window_attribute", winType, 5) #define get_inven_ap_cost sfall_func0("get_inven_ap_cost") #define get_map_enter_position sfall_func0("get_map_enter_position") #define get_metarule_table sfall_func0("get_metarule_table") diff --git a/artifacts/scripting/sfall function notes.md b/artifacts/scripting/sfall function notes.md index 7bb53d48..9b9442aa 100644 --- a/artifacts/scripting/sfall function notes.md +++ b/artifacts/scripting/sfall function notes.md @@ -48,7 +48,7 @@ The `set_pickpocket_max` and `set_hit_chance_max` affect all critters rather tha The `set_skill_max` can't be used to increase the skill cap above 300. The `set_perk_level_mod` sets a modifier between +25 and -25 that is added/subtracted from the player's level for the purposes of deciding which perks can be chosen. -The `set_fake_trait` and `set_fake_perk` can be used to add additional traits and perks to the character screen. They will be saved correctly when the player saves and reloads games, but by themselves they will have no further effect on the character. For perks, the allowed range for levels is between 0 and 100; setting the level to 0 removes that perk. For traits, the level must be 0 or 1. The image is a numeric id that corresponds to an entry in **skilldex.lst**. The name is limited to 63 characters and the description to 255 characters by sfall, but internal Fallout limits may be lower. +The `set_fake_trait` and `set_fake_perk` can be used to add additional traits and perks to the character screen. They will be saved correctly when the player saves and reloads games, but by themselves they will have no further effect on the character. For perks, the allowed range for levels is between 0 and 100; setting the level to 0 removes that perk. For traits, the level must be 0 or 1. The image is a numeric ID that corresponds to an entry in **skilldex.lst**. The name is limited to 63 characters and the description to 255 characters by sfall, but internal Fallout limits may be lower. The `has_fake_trait` and `has_fake_perk` return the number of levels the player has of the perks/traits with the given name. @@ -70,10 +70,10 @@ The `get_proto_data` and `set_proto_data` are used to manipulate the in memory c The `list_xxx` functions can be used to loop over all items on a map. `list_begin` takes an argument telling sfall what you want to list (defined in **sfall.h**). It returns a list pointer, which you iterate through with `list_next`. Finally, when you've finished with the list use `list_end` on it. Not calling `list_end` will result in a memory leak. Alternatively, use `list_as_array` to get the whole list at once as a temp array variable, which can be looped over using `len_array` and which you don't need to remember to free afterwards. -The `play_sfall_sound` and `stop_sfall_sound` are used to play **mp3/wav/wma** files. The path given is relative to the Fallout folder. Specify mode as 1 to loop the file continuously, 2 to replace the current background game music with playing the specified file in loop mode, or 0 to play the file once. If you don't wish to loop, `play_sfall_sound` returns 0. If you do loop, it returns an id which can be passed back to `stop_sfall_sound` when you want to stop the effect. All sounds effects will be stopped on game reload, looping or not. These functions do not require **AllowDShowSound** to be set to 1 in **ddraw.ini**. +The `play_sfall_sound` and `stop_sfall_sound` are used to play **mp3/wav/wma** files. The path given is relative to the Fallout folder. Specify mode as 1 to loop the file continuously, 2 to replace the current background game music with playing the specified file in loop mode, or 0 to play the file once. If you don't wish to loop, `play_sfall_sound` returns 0. If you do loop, it returns an ID which can be passed back to `stop_sfall_sound` when you want to stop the effect. All sounds effects will be stopped on game reload, looping or not. These functions do not require **AllowDShowSound** to be set to 1 in **ddraw.ini**. Starting from sfall 4.2.8/3.8.28, you can pass a value in the **mode** argument for a reduced sound volume. To set the volume, You need to convert the number to hexadecimal and use the argument format `0xZZZZ000Y`, where `ZZZZ` is the volume reduction value in range from 0 to 32767 (the value 32767 is muted), and `Y` is the playback mode. -Arrays are created and manipulated with the `xxx_array` functions. An array must first be created with `create_array` or `temp_array`, specifying how many data elements the array can hold. You can store any of ints, floats and strings in an array, and can mix all 3 in a single array. The ID returned by `create_array` or `temp_array` can then be used with the other array functions. Arrays are shared between all scripts. (i.e. you can call `create_array` from one script, and then use the returned ID from another script.) They are also saved across savegames. Arrays created with `temp_array` will be automatically freed at the end of the frame. These functions are safe, in that supplying a bad id or trying to access out of range elements will not crash the script. `create_array` is the only function that returns a permanent array, all other functions which return arrays (`string_split`, `list_as_array`, etc,) all return temp arrays. You can use `fix_array` to make a temp array permanent.\ +Arrays are created and manipulated with the `xxx_array` functions. An array must first be created with `create_array` or `temp_array`, specifying how many data elements the array can hold. You can store any of ints, floats and strings in an array, and can mix all 3 in a single array. The ID returned by `create_array` or `temp_array` can then be used with the other array functions. Arrays are shared between all scripts. (i.e. you can call `create_array` from one script, and then use the returned ID from another script.) They are also saved across savegames. Arrays created with `temp_array` will be automatically freed at the end of the frame. These functions are safe, in that supplying a bad ID or trying to access out of range elements will not crash the script. `create_array` is the only function that returns a permanent array, all other functions which return arrays (`string_split`, `list_as_array`, etc,) all return temp arrays. You can use `fix_array` to make a temp array permanent.\ __NOTE:__ refer to **arrays.md** for detailed description of the array behavior and function usage. The `force_aimed_shots` and `disable_aimed_shots` allow overriding the normal rules regarding which weapons are allowed to make aimed attacks. (e.g. weapons that cause explosive damage normally cannot normally make aimed shots.) `force_aimed_shots` will allow a weapon to make aimed shots even if it normally couldn't, and `disable_aimed_shots` stops a weapon from making aimed shots even if it normally could. Both of these functions affect player and NPCs alike. `force_aimed_shots` does not override the effects of the fast shot trait. The list of edited weapons is not saved over game loads, so you need to call the functions once at each reload. Use a pid of 0 to represent unarmed. @@ -961,6 +961,7 @@ sfall_funcX metarule functions 0 - checks and returns a value of 1 if the specified interface window is created by the game (same as without the argument)\ 1 - X position, 2 - Y position (relative to the top-left corner of the game screen)\ 3 - interface width size, 4 - interface height size\ + 5 - window ID (to compare with the `get_window_under_mouse` function)\ -1 - returns an associative array of keys (left, top, right, bottom) and values that define the position of the window rectangle (use standard syntax to access array values, e.g. `win.top`, `win.bottom`) - Returns -1 if the specified attribute cannot be obtained diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index 0cb2fb3f..9ac98b18 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -624,6 +624,15 @@ static void __declspec(naked) HelpMenuHook() { } } +static void __declspec(naked) PauseWindowHook() { + __asm { + _InLoop(1, PAUSEWIN); + call fo::funcoffs::PauseWindow_; + _InLoop(0, PAUSEWIN); + retn; + } +} + static void __declspec(naked) CharacterHook() { __asm { push edx; @@ -938,6 +947,8 @@ void LoadGameHook::init() { HookCall(0x447A7E, gdialog_bk_hook); // set when switching from dialog mode to barter mode (unset when entering barter) HookCall(0x4457B1, gdialogUpdatePartyStatus_hook1); // set when a party member joins/leaves HookCall(0x4457BC, gdialogUpdatePartyStatus_hook0); // unset + + HookCall(0x443482, PauseWindowHook); } } diff --git a/sfall/Modules/LoadGameHook.h b/sfall/Modules/LoadGameHook.h index d7de935d..11173950 100644 --- a/sfall/Modules/LoadGameHook.h +++ b/sfall/Modules/LoadGameHook.h @@ -65,6 +65,7 @@ enum LoopFlag : unsigned long { HEROWIN = 1 << 18, // 0x40000 Hero Appearance mod DIALOGVIEW = 1 << 19, // 0x80000 COUNTERWIN = 1 << 20, // 0x100000 Counter window for moving multiple items or setting a timer + PAUSEWIN = 1 << 21, // 0x200000 Ctrl+P pause window SPECIAL = 1UL << 31 // 0x80000000 Additional special flag for all modes }; diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index ce938bc1..a6df4e53 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -722,6 +722,11 @@ static long InterfaceDrawImage(OpcodeContext& ctx, fo::Window* ifaceWin) { int width = (w >= 0) ? w : frm.width; int height = (h >= 0) ? h : frm.height; + if (x + width > ifaceWin->width || y + height > ifaceWin->height) { + ctx.printOpcodeError("%s() - attempt to draw beyond window bounds (%d, %d)", ctx.getMetaruleName(), ifaceWin->width, ifaceWin->height); + return -1; + } + BYTE* surface = (ifaceWin->randY) ? WindowRender::GetOverlaySurface(ifaceWin) : ifaceWin->surface; fo::func::trans_cscale(frm.pixelData, frm.width, frm.height, frm.width, @@ -783,6 +788,9 @@ void mf_get_window_attribute(OpcodeContext& ctx) { case 4: result = win->height; break; + case 5: + result = win->wID; + break; } ctx.setReturn(result); } diff --git a/sfall/Modules/Scripting/OpcodeContext.h b/sfall/Modules/Scripting/OpcodeContext.h index 4886d4d0..209a2e9a 100644 --- a/sfall/Modules/Scripting/OpcodeContext.h +++ b/sfall/Modules/Scripting/OpcodeContext.h @@ -29,7 +29,7 @@ namespace sfall namespace script { -#define OP_MAX_ARGUMENTS (8) +#define OP_MAX_ARGUMENTS (10) class OpcodeContext;