From ea2a4bfdfa0e02aec678b00a0d006b25c4307cda Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 22 Sep 2022 10:09:52 +0800 Subject: [PATCH 01/33] Edited [ExtraPatches] description in ddraw.ini --- artifacts/ddraw.ini | 19 +++++++++---------- docs/Gemfile.lock | 14 ++++---------- sfall/Modules/LoadOrder.cpp | 5 +++-- sfall/Modules/Worldmap.h | 4 ++-- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 15354e81a..69044f8b4 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -16,18 +16,17 @@ UseCommandLine=0 ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX [ExtraPatches] -;This section allows you to set multiple paths to folders containing mods or patches that will be loaded by the game -;If DataLoadOrderPatch is enabled, the data load order is: -;master_patches > critter_patches > [extra patches] > patchXXX.dat > sfall.dat > critter_dat > f2_res_patches > f2_res_dat > master_dat +;This section allows you to set multiple paths to folders containing mods or patches ;Paths to folders and Fallout .dat files are supported -;The PatchFile## options are available from 0 to 99. Larger numbers take precedence over smaller numbers (same as patchXXX.dat) +;The PatchFileXX options are available from 0 to 99. Larger numbers take precedence over smaller numbers (same as patchXXX.dat) ;PatchFile0=mods\RP_data +;PatchFile1= -;Path to the folder in which the game will automatically search and load custom files (by *.dat mask, including folders) -;The data load order of the files in the folder will be in reverse alphabetical order of the filenames -;The files placed in this folder will have higher priority than the PatchFile## options -;This option has no effect in 4.2.6 or later. The path is fixed to \mods\ -;AutoSearchPath=mods +;Starting from 4.2.6, the game will automatically search and load custom .dat files (or folders named as .dat files) from \mods\ +;The load order of files in the folder will be in reverse alphabetical order of the filenames +;Autoloaded files will have a higher priority than the files specified in the PatchFileXX options +;The complete data load order is: +;master_patches > critter_patches > mods > PatchFile99..PatchFile0 > patchXXX.dat > sfall.dat > critter_dat > f2_res_patches > f2_res_dat > master_dat ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX [Speed] @@ -281,7 +280,7 @@ UseFileSystemOverride=0 ;Set to 1 to use the modified data load order for the engine to find game data ;Original: patchXXX.dat > critter_patches > critter_dat > f2_res_patches > f2_res_dat > master_patches > master_dat -;Modified: master_patches > critter_patches > patchXXX.dat > critter_dat > f2_res_patches > f2_res_dat > master_dat +;Modified: master_patches > critter_patches > extra_patches > patchXXX.dat > sfall.dat > critter_dat > f2_res_patches > f2_res_dat > master_dat ;This option is always enabled in 4.3/3.8.30 or later. The information is left for reference only DataLoadOrderPatch=1 diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 04fec695a..7e7462098 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -14,7 +14,7 @@ GEM execjs coffee-script-source (1.11.1) colorator (1.1.0) - commonmarker (0.23.4) + commonmarker (0.23.6) concurrent-ruby (1.1.9) dnsruby (1.61.9) simpleidn (~> 0.1) @@ -121,6 +121,7 @@ GEM pathutil (~> 0.9) rouge (>= 1.7, < 4) safe_yaml (~> 1.0) + jekyll-analytics (0.1.14) jekyll-avatar (0.7.0) jekyll (>= 3.0, < 5.0) jekyll-coffeescript (1.1.1) @@ -232,7 +233,7 @@ GEM jekyll-seo-tag (~> 2.1) minitest (5.15.0) multipart-post (2.1.1) - nokogiri (1.13.3) + nokogiri (1.13.6) mini_portile2 (~> 2.8.0) racc (~> 1.4) octokit (4.22.0) @@ -267,14 +268,10 @@ GEM ethon (>= 0.9.0) tzinfo (1.2.10) thread_safe (~> 0.1) - tzinfo-data (1.2021.1) - tzinfo (>= 1.0.0) unf (0.1.4) unf_ext unf_ext (0.0.8) unicode-display_width (1.8.0) - wdm (0.1.1) - webrick (1.7.0) zeitwerk (2.5.4) PLATFORMS @@ -284,11 +281,8 @@ DEPENDENCIES github-pages (~> 225) jekyll-analytics jekyll-feed (~> 0.6) - kramdown-parser-gfm - tzinfo (~> 1.2) + jekyll-remote-theme tzinfo-data - wdm (~> 0.1.0) - webrick (~> 1.7) BUNDLED WITH 2.1.4 diff --git a/sfall/Modules/LoadOrder.cpp b/sfall/Modules/LoadOrder.cpp index aab24d757..60ff370e4 100644 --- a/sfall/Modules/LoadOrder.cpp +++ b/sfall/Modules/LoadOrder.cpp @@ -256,6 +256,7 @@ static void __fastcall game_init_databases_hook1() { } fo::var::master_db_handle = node; // set pointer to master_patches node + InitSystemPatches(); InitExtraPatches(); } */ @@ -263,7 +264,7 @@ static bool NormalizePath(std::string &path) { if (path.find(':') != std::string::npos) return false; int pos = 0; - do { // replace all '/' char to '\' + do { // replace all '/' char with '\' pos = path.find('/', pos); if (pos != std::string::npos) path[pos] = '\\'; } while (pos != std::string::npos); @@ -303,7 +304,7 @@ static void GetExtraPatches() { // Remove first duplicates size_t size = patchFiles.size(); for (size_t i = 1; i < size; ++i) { - for(size_t j = size - 1; j > i; --j) { + for (size_t j = size - 1; j > i; --j) { if (patchFiles[j] == patchFiles[i]) { patchFiles[i].clear(); } diff --git a/sfall/Modules/Worldmap.h b/sfall/Modules/Worldmap.h index cd6f4a162..23e9123f3 100644 --- a/sfall/Modules/Worldmap.h +++ b/sfall/Modules/Worldmap.h @@ -31,8 +31,8 @@ class Worldmap : public Module { static Delegate<>& OnWorldmapLoop(); - static void Worldmap::SaveData(HANDLE); - static bool Worldmap::LoadData(HANDLE); + static void SaveData(HANDLE); + static bool LoadData(HANDLE); static void SetCarInterfaceArt(DWORD artIndex); static void SetRestHealTime(DWORD minutes); From bd15cf2b9e4e20d3b32fe2f3af53d04a146a2cfe Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 27 Sep 2022 16:14:38 +0800 Subject: [PATCH 02/33] Fixed the order of autoloaded dat files on FAT file system --- artifacts/ddraw.ini | 5 ++--- sfall/Modules/LoadOrder.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 69044f8b4..0ab18f1cd 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -19,14 +19,13 @@ UseCommandLine=0 ;This section allows you to set multiple paths to folders containing mods or patches ;Paths to folders and Fallout .dat files are supported ;The PatchFileXX options are available from 0 to 99. Larger numbers take precedence over smaller numbers (same as patchXXX.dat) -;PatchFile0=mods\RP_data -;PatchFile1= - ;Starting from 4.2.6, the game will automatically search and load custom .dat files (or folders named as .dat files) from \mods\ ;The load order of files in the folder will be in reverse alphabetical order of the filenames ;Autoloaded files will have a higher priority than the files specified in the PatchFileXX options ;The complete data load order is: ;master_patches > critter_patches > mods > PatchFile99..PatchFile0 > patchXXX.dat > sfall.dat > critter_dat > f2_res_patches > f2_res_dat > master_dat +;PatchFile0=mods\RP_data +;PatchFile1= ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX [Speed] diff --git a/sfall/Modules/LoadOrder.cpp b/sfall/Modules/LoadOrder.cpp index 60ff370e4..b59ad2f73 100644 --- a/sfall/Modules/LoadOrder.cpp +++ b/sfall/Modules/LoadOrder.cpp @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +#include + #include "..\main.h" #include "..\FalloutEngine\Fallout2.h" #include "..\Utils.h" @@ -288,6 +290,7 @@ static void GetExtraPatches() { //if (searchPath.back() != '\\') searchPath += "\\"; std::string pathMask(".\\mods\\*.dat"); + size_t startPos = patchFiles.size(); dlogr("Loading custom patches:", DL_MAIN); WIN32_FIND_DATA findData; HANDLE hFind = FindFirstFile(pathMask.c_str(), &findData); @@ -300,6 +303,10 @@ static void GetExtraPatches() { } while (FindNextFile(hFind, &findData)); FindClose(hFind); } + // Sort the search result + if (!patchFiles.empty()) { + std::sort(patchFiles.begin() + startPos, patchFiles.end()); + } //} // Remove first duplicates size_t size = patchFiles.size(); From 5d5da0a471958361c5211875623bbde6f3d026a5 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 28 Sep 2022 10:17:11 +0800 Subject: [PATCH 03/33] Code correction to LoadOrder.cpp Updated version number. --- artifacts/ddraw.ini | 2 +- sfall/Modules/LoadOrder.cpp | 2 +- sfall/version.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 0ab18f1cd..551981f60 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -1,5 +1,5 @@ ;sfall configuration settings -;v4.3.7 +;v4.3.7.1 [Main] ;Set to 1 to enable the built-in High Resolution Patch mode that is similar to the hi-res patch by Mash diff --git a/sfall/Modules/LoadOrder.cpp b/sfall/Modules/LoadOrder.cpp index b59ad2f73..3730c89d9 100644 --- a/sfall/Modules/LoadOrder.cpp +++ b/sfall/Modules/LoadOrder.cpp @@ -310,7 +310,7 @@ static void GetExtraPatches() { //} // Remove first duplicates size_t size = patchFiles.size(); - for (size_t i = 1; i < size; ++i) { + for (size_t i = 0; i < size; ++i) { for (size_t j = size - 1; j > i; --j) { if (patchFiles[j] == patchFiles[i]) { patchFiles[i].clear(); diff --git a/sfall/version.h b/sfall/version.h index 83a05583b..8bee108e6 100644 --- a/sfall/version.h +++ b/sfall/version.h @@ -25,6 +25,6 @@ #define VERSION_MAJOR 4 #define VERSION_MINOR 3 #define VERSION_BUILD 7 -#define VERSION_REV 0 +#define VERSION_REV 1 -#define VERSION_STRING "4.3.7" +#define VERSION_STRING "4.3.7.1" From 87f5a5f08188d88e4014552dfc29f15802d11460 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sun, 9 Oct 2022 22:01:11 +0800 Subject: [PATCH 04/33] Fixed incorrect critter names for corpses * happens when multiple critters based on the same proto with different scripts attached are killed. Tweaked the fix for create_object_sid function. --- sfall/Modules/BugFixes.cpp | 8 +++++++- sfall/Modules/SubModules/ObjectName.cpp | 21 ++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index ac03fc55e..0e8bcd601 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -3146,10 +3146,16 @@ static void __declspec(naked) op_create_object_sid_hack() { jz noObject; mov ecx, [ebx + scriptId]; cmp ecx, -1; - jne init; + jne setScrIdx; mov edx, ebx; mov eax, esi; retn; +setScrIdx: + mov eax, [esp + 0x50 - 0x40 + 4]; // scriptIndex + cmp eax, -1; + je init; + dec eax; + mov [ebx + scriptIndex], eax; init: call LoadGameHook::IsMapLoading; test al, al; diff --git a/sfall/Modules/SubModules/ObjectName.cpp b/sfall/Modules/SubModules/ObjectName.cpp index e1c86c863..045aa6241 100644 --- a/sfall/Modules/SubModules/ObjectName.cpp +++ b/sfall/Modules/SubModules/ObjectName.cpp @@ -28,7 +28,7 @@ namespace sfall static std::unordered_map overrideScrName; -static long lastNamePid = -1; +static long lastNameScrIdx = -1; static long lastNameSid = -1; static long lastItemPid = -1; @@ -72,21 +72,24 @@ static void __declspec(naked) critter_name_hack_check() { __asm { mov ecx, [ebx + scriptId]; cmp ecx, -1; - je checkPid; // has no script, check only the PID + je checkScrIdx; // has no script, check the script index instead cmp ecx, lastNameSid; jne default; add esp, 4; mov eax, ds:[FO_VAR_name_critter]; jmp critter_name_hack_ret; -checkPid: - mov ecx, [ebx + protoId]; - cmp ecx, lastNamePid; - jne default; +checkScrIdx: + mov ecx, [ebx + scriptIndex]; + cmp ecx, -1; // no inherited script index + je end; + cmp ecx, lastNameScrIdx; + jne end; add esp, 4; mov eax, ds:[FO_VAR_name_critter]; jmp critter_name_hack_ret; default: mov ecx, [ebx + scriptIndex]; +end: retn; } } @@ -94,8 +97,8 @@ static void __declspec(naked) critter_name_hack_check() { static void __declspec(naked) critter_name_hack_end() { using namespace fo::Fields; __asm { - mov edx, [ebx + protoId]; - mov lastNamePid, edx; + mov edx, [ebx + scriptIndex]; + mov lastNameScrIdx, edx; mov ecx, [ebx + scriptId]; mov lastNameSid, ecx; retn; @@ -131,7 +134,7 @@ void ObjectName::init() { LoadGameHook::OnBeforeMapLoad() += Reset; LoadGameHook::OnGameReset() += []() { Reset(); - lastNamePid = -1; + lastNameScrIdx = -1; lastItemPid = -1; }; } From 007fa7314b040275ad68932a87437aeaac7c04c9 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 18 Oct 2022 08:58:09 +0800 Subject: [PATCH 05/33] Minor edit to hookscripts.md --- artifacts/scripting/hooks.yml | 2 +- artifacts/scripting/hookscripts.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artifacts/scripting/hooks.yml b/artifacts/scripting/hooks.yml index f0d702e53..fb9e4b218 100644 --- a/artifacts/scripting/hooks.yml +++ b/artifacts/scripting/hooks.yml @@ -112,7 +112,7 @@ int arg3 - The amount of damage to the attacker int arg4 - The special effect flags for the target (use bwand DAM_* to check specific flags) int arg5 - The special effect flags for the attacker (use bwand DAM_* to check specific flags) - int arg6 - The weapon used in the attack + Item arg6 - The weapon used in the attack int arg7 - The bodypart that was struck int arg8 - Damage Multiplier (this is divided by 2, so a value of 3 does 1.5x damage, and 8 does 4x damage. Usually it's 2; for critical hits, the value is taken from the critical table; with Silent Death perk and the corresponding attack conditions, the value will be doubled) int arg9 - Number of bullets actually hit the target (1 for melee attacks) diff --git a/artifacts/scripting/hookscripts.md b/artifacts/scripting/hookscripts.md index 2c9d81d47..037f1a01f 100644 --- a/artifacts/scripting/hookscripts.md +++ b/artifacts/scripting/hookscripts.md @@ -193,7 +193,7 @@ int arg2 - The amount of damage to the target int arg3 - The amount of damage to the attacker int arg4 - The special effect flags for the target (use bwand DAM_* to check specific flags) int arg5 - The special effect flags for the attacker (use bwand DAM_* to check specific flags) -int arg6 - The weapon used in the attack +Item arg6 - The weapon used in the attack int arg7 - The bodypart that was struck int arg8 - Damage Multiplier (this is divided by 2, so a value of 3 does 1.5x damage, and 8 does 4x damage. Usually it's 2; for critical hits, the value is taken from the critical table; with Silent Death perk and the corresponding attack conditions, the value will be doubled) int arg9 - Number of bullets actually hit the target (1 for melee attacks) From db7419a2f72a6aff79e15bba1bc6154de69b9804 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 25 Oct 2022 21:23:21 +0800 Subject: [PATCH 06/33] Some format edits to documents Updated version number. --- artifacts/ddraw.ini | 2 +- artifacts/scripting/compiler/sslc_readme.md | 1 + artifacts/scripting/functions.yml | 12 ++++---- artifacts/scripting/sfall function notes.md | 34 +++++++++++---------- docs/Gemfile.lock | 2 +- docs/global-scripts.md | 6 ++-- sfall/version.h | 6 ++-- 7 files changed, 34 insertions(+), 29 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 551981f60..36e51ff0e 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -1,5 +1,5 @@ ;sfall configuration settings -;v4.3.7.1 +;v4.3.8 [Main] ;Set to 1 to enable the built-in High Resolution Patch mode that is similar to the hi-res patch by Mash diff --git a/artifacts/scripting/compiler/sslc_readme.md b/artifacts/scripting/compiler/sslc_readme.md index d87c68f67..164fd3f69 100644 --- a/artifacts/scripting/compiler/sslc_readme.md +++ b/artifacts/scripting/compiler/sslc_readme.md @@ -246,6 +246,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by - you couldn't see all references of a procedure from a Script Editor - it was completely not obvious that you could do such a thing, it was a confusing syntax + - (*) **Arrays**: In vanilla Fallout, arrays had to be constructed by reserving a block of global/map variables. Since sfall 2.7, specific array targeted functions have been available, but they are fairly messy and long winded to use. The compiler provides additional syntactic shorthand for accessing and setting array variables, as well as for array creation. When declaring an array variable, put a constant integer in `[]`` to give the number of elements in the array. (before sfall 3.4 you had to specify size in bytes for array elements, now it's not required, see **arrays.md** for more information) - new: ``` diff --git a/artifacts/scripting/functions.yml b/artifacts/scripting/functions.yml index 1222d28ba..6a6fe04ff 100644 --- a/artifacts/scripting/functions.yml +++ b/artifacts/scripting/functions.yml @@ -1077,11 +1077,11 @@ parent: Variables items: - name: string_split - detail: array string_split(string, split) + detail: array string_split(string text, split) doc: "Takes a string and a seperator, searches the string for all instances of the seperator, and returns a temp array filled with the pieces of the string split at each instance. If you give an empty string as the seperator, the string is split into individual characters. You can use this to search for a substring in a string like this: `strlen(get_array(string_split(haystack, needle), 0))`" opcode: 0x8235 - name: substr - detail: string substr(string, start, length) + detail: string substr(string text, start, length) doc: | Cuts a substring from a string starting at "start" up to "length" characters. The first character position is 0 (zero). - If start is negative - it indicates starting position from the end of the string (for example `substr("test", -2, 2)` will return last 2 charactes: "st"). @@ -1822,7 +1822,7 @@ - name: Objects and scripts items: - name: set_self - detail: void set_self(ObjectPtr) + detail: void set_self(ObjectPtr setObj) doc: | Overrides the script's `self_obj` for the next function call. - It is primarily used to allow the calling of functions which take an implicit `self_obj` parameter (e.g. `drop_obj`) from global scripts, but it can also be used from normal scripts. @@ -1841,15 +1841,15 @@ macro: sfall.h - name: remove_script - detail: void remove_script(ObjectPtr) + detail: void remove_script(ObjectPtr obj) opcode: 0x81f3 doc: Accepts a pointer to an object and will remove the script from that object. - name: set_script - detail: void set_script(ObjectPtr, int scriptID) + detail: void set_script(ObjectPtr obj, int scriptID) opcode: 0x81f4 doc: Accepts a pointer to an object and scriptID, and applies the given script to an object (scriptID accept the same values as `create_object_sid `from sfall 3.6). If used on an object that is already scripted, it will remove the existing script first; you cannot have multiple scripts attached to a single object. Calling `set_script` on `self_obj` will have all sorts of wacky side effects, and should be avoided. If you add 0x80000000 to the sid when calling `set_script`, `map_enter_p_proc` will be SKIPPED. The `start` proc will always be run. - name: get_script - detail: int get_script(ObjectPtr) + detail: int get_script(ObjectPtr obj) opcode: 0x81f5 doc: | - accepts a pointer to an object and returns its scriptID (line number in `scripts.lst`), or 0 if the object is unscripted. diff --git a/artifacts/scripting/sfall function notes.md b/artifacts/scripting/sfall function notes.md index ee2678d25..cbb2ecec6 100644 --- a/artifacts/scripting/sfall function notes.md +++ b/artifacts/scripting/sfall function notes.md @@ -1,10 +1,12 @@ GLOBAL SCRIPTS -------------- -As well as the new functions, sfall also adds global scripts. These run independent of any loaded maps, but do not have an attached object. (i.e. using `self_obj` without using `set_self` first will crash the script.) To use a global script, the script must have a name which begins with `gl` and contains a procedure called `start`, `map_enter_p_proc`, `map_exit_p_proc`, or `map_update_p_proc`. The `start` procedure will be executed once when the player loads a saved game or starts a new game. The `map_*_p_proc` procedures will be executed once when a map is being entered/left/updated. If you wish the script to be executed repeatedly, call `set_global_script_repeat` on the first run of the `start` procedure using the number of frames between each run as the argument. (0 disables the script, 1 runs it every frame, 2 runs it every other frame, etc.) +As well as the new functions, sfall also adds global scripts. These run independent of any loaded maps, but do not have an attached object (i.e. using `self_obj` without using `set_self` first will crash the script). -Global scripts have multiple modes, which can be set using the `set_global_script_type` function. In the default mode (i.e. mode 0) their execution is linked to the local map game loop, so the script will not run in dialogs or on the world map. In mode 1 their execution is linked to the player input, and so they will run whenever the mouse cursor is visible on screen, including the world map, character dialogs, etc. In mode 2, execution is linked to the world map loop, so the script will only be executed on the world map and not on the local map or in any dialog windows. Mode 3 is a combination of modes 0 and 2, so scripts will be executed on both local maps and the world map, but not in dialog windows. -_Using mode 1 requires the input wrapper to be enabled. Use available_global_script_types to check what is available._ - Obsolete. +To use a global script, the script must have a name which begins with `gl` and contains a procedure called `start`, `map_enter_p_proc`, `map_exit_p_proc`, or `map_update_p_proc`. The `start` procedure will be executed once when the player loads a saved game or starts a new game. The `map_*_p_proc` procedures will be executed once when a map is being entered/left/updated. If you wish the script to be executed repeatedly, call `set_global_script_repeat` on the first run of the `start` procedure using the number of frames between each run as the argument (0 disables the script, 1 runs it every frame, 2 runs it every other frame, etc.). + +Global scripts have multiple modes, which can be set using the `set_global_script_type` function. In the default mode (i.e. mode 0) their execution is linked to the local map game loop, so the script will not run in dialogs or on the world map. In mode 1 their execution is linked to the player input, and so they will run whenever the mouse cursor is visible on screen, including the world map, character dialogs, etc. In mode 2, execution is linked to the world map loop, so the script will only be executed on the world map and not on the local map or in any dialog windows. Mode 3 is a combination of modes 0 and 2, so scripts will be executed on both local maps and the world map, but not in dialog windows.\ +_Using mode 1 requires the input wrapper to be enabled. Use available_global_script_types to check what is available._ - **Obsolete**. ---------------------- @@ -168,22 +170,22 @@ FUNCTION REFERENCE - This function works in addition to the **WorldMapTimeMod** setting in ddraw.ini and the Pathfinder perk, rather than overriding it, so calling `set_map_time_multi(0.5)` when the player has 2 levels of pathfinder would result in time passing at 25% the normal speed on the world map. ----- -##### `void remove_script(object)` +##### `void remove_script(object obj)` - Accepts a pointer to an object and will remove the script from that object. ----- -##### `void set_script(object, int scriptID)` +##### `void set_script(object obj, int scriptID)` - Accepts a pointer to an object and **scriptID**, and applies the given script to an object (scriptID accepts the same values as `create_object_sid`) - If used on an object that is already scripted, it will remove the existing script first; you cannot have multiple scripts attached to a single object. Calling `set_script` on `self_obj` will have all sorts of wacky side effects, and should be avoided. - If you add `0x80000000` to the SID when calling `set_script`, `map_enter_p_proc` will be SKIPPED. The `start` proc will always be run. ----- -##### `int get_script(object)` +##### `int get_script(object obj)` - Accepts a pointer to an object and returns its scriptID (line number in **scripts.lst**), or 0 if the object is unscripted. - Returns -1 on argument error. ----- -##### `void set_self(int obj)` +##### `void set_self(object setObj)` - Overrides the script's `self_obj` for the next function call. - It is primarily used to allow the calling of functions which take an implicit `self_obj` parameter (e.g. `drop_obj`) from global scripts, but it can also be used from normal scripts. - `self_obj` will be reverted to its original value after the next function call. @@ -206,11 +208,11 @@ FUNCTION REFERENCE - Be careful not to let the player obtain a perk when no perks are available to pick, or the game may crash. ----- -##### `object get_last_target(object)` +##### `object get_last_target(object critter)` - Will return the last critter to be deliberately attacked. ----- -##### `object get_last_attacker(object)` +##### `object get_last_attacker(object critter)` - Will return the last critter to deliberately launch an attack against the argument critter. - If a critter has not launched/received an attack, it will return 0. This is only stored for the duration of combat, and outside of combat both functions will always return 0. @@ -221,7 +223,7 @@ FUNCTION REFERENCE - `mod` will add this much percent to each success chance. For example, if your chance is 50% and `mod` is 20, you will get 70% actual success rate. ----- -##### `void set_critter_pickpocket_mod(object, int max, int mod)` +##### `void set_critter_pickpocket_mod(object critter, int max, int mod)` - The same as above, but applies only to specific critter. ----- @@ -303,19 +305,19 @@ FUNCTION REFERENCE --- ### Some utility/math functions are available: -##### `array string_split(string, split)` +##### `array string_split(string text, split)` - Takes a string and a separator, searches the string for all instances of the separator, and returns a temp array filled with the pieces of the string split at each instance. If you give an empty string as the separator, the string is split into individual characters. - You can use this to search for a substring in a string like this: `strlen(get_array(string_split(haystack, needle), 0))` ----- -##### `string substr(string, start, length)` +##### `string substr(string text, start, length)` - Cuts a substring from a string starting at `start` up to `length` characters. The first character position is 0 (zero). - If `start` is negative - it indicates starting position from the end of the string (for example, `substr("test", -2, 2)` will return last 2 charactes: "st"). - If `length` is negative - it means so many characters will be omitted from the end of string (example: `substr("test", 0, -2)` will return string without last 2 characters: "te"). - If `length` is zero - it will return a string from the starting position to the end of the string (new behavior for sfall 4.2.2/3.8.22). ----- -##### `int strlen(string string)` +##### `int strlen(string text)` - Returns string length. ----- @@ -328,7 +330,7 @@ FUNCTION REFERENCE - Returns type of the given value: `VALTYPE_INT`, `VALTYPE_FLOAT` or `VALTYPE_STR`. ----- -##### `int charcode(string string)` +##### `int charcode(string text)` - Returns ASCII code for the first character in given string. ----- @@ -385,7 +387,7 @@ FUNCTION REFERENCE - Just pass 1 as `y` (don't ask...) ----- -##### `void register_hook_proc(int hook, procedure proc)` +##### `void register_hook_proc(int hookID, procedure proc)` - Works just like `register_hook`, but allows to specify which procedure to use for given hook script (instead of `start`). - Use zero (0) as second argument to unregister hook script from current global script. - Only use in global scripts. @@ -393,7 +395,7 @@ FUNCTION REFERENCE - See **hookscripts.md** for more details. ----- -##### `void register_hook_proc_spec(int hook, procedure proc)` +##### `void register_hook_proc_spec(int hookID, procedure proc)` - Works just like `register_hook_proc`, but allows to register a script at the end of the hook script execution chain (i.e. the script will be executed after all previously registered scripts for the same hook, including the `hs_*.int` script). - To unregister hook script from current global script, use the `register_hook_proc` function. diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 7e7462098..186e495d9 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -233,7 +233,7 @@ GEM jekyll-seo-tag (~> 2.1) minitest (5.15.0) multipart-post (2.1.1) - nokogiri (1.13.6) + nokogiri (1.13.9) mini_portile2 (~> 2.8.0) racc (~> 1.4) octokit (4.22.0) diff --git a/docs/global-scripts.md b/docs/global-scripts.md index 1d454298a..d6a3ce363 100644 --- a/docs/global-scripts.md +++ b/docs/global-scripts.md @@ -9,11 +9,13 @@ permalink: /global-scripts/ # Global scripts -As well as the new functions, sfall also adds global scripts. These run independent of any loaded maps, but do not have an attached object. (i.e. using `self_obj` without using `set_self` first will crash the script.) To use a global script, the script must have a name which begins with `gl` and contains a procedure called `start`, `map_enter_p_proc`, `map_exit_p_proc`, or `map_update_p_proc`. The start procedure will be executed once when the player loads a saved game or starts a new game. The `map_*_p_proc` procedures will be executed once when a map is being entered/left/updated. If you wish the script to be executed repeatedly, call `set_global_script_repeat` on the first run of the start procedure using the number of frames between each run as the argument. (0 disables the script, 1 runs it every frame, 2 runs it every other frame etc.) +As well as the new functions, sfall also adds global scripts. These run independent of any loaded maps, but do not have an attached object (i.e. using `self_obj` without using `set_self` first will crash the script). + +To use a global script, the script must have a name which begins with `gl` and contains a procedure called `start`, `map_enter_p_proc`, `map_exit_p_proc`, or `map_update_p_proc`. The start procedure will be executed once when the player loads a saved game or starts a new game. The `map_*_p_proc` procedures will be executed once when a map is being entered/left/updated. If you wish the script to be executed repeatedly, call `set_global_script_repeat` on the first run of the start procedure using the number of frames between each run as the argument (0 disables the script, 1 runs it every frame, 2 runs it every other frame etc.). Global scripts have multiple modes, which can be set using the `set_global_script_type` function. - In the default mode (i.e. mode 0) their execution is linked to the local map game loop, so the script will not run in dialogs or on the world map. - [Using mode 1 requires the input wrapper to be enabled. Use `available_global_script_types` to check what is available.] - Obsolete. + _[Using mode 1 requires the input wrapper to be enabled. Use `available_global_script_types` to check what is available.]_ - **Obsolete**. - In mode 1 their execution is linked to the player input, and so they will run whenever the mouse cursor is visible on screen, including the world map, character dialogs etc. - In mode 2, execution is linked to the world map loop, so the script will only be executed on the world map and not on the local map or in any dialog windows. - Mode 3 is a combination of modes 0 and 2, so scripts will be executed on both local maps and the world map, but not in dialog windows. diff --git a/sfall/version.h b/sfall/version.h index 8bee108e6..f202f5f89 100644 --- a/sfall/version.h +++ b/sfall/version.h @@ -24,7 +24,7 @@ #define VERSION_MAJOR 4 #define VERSION_MINOR 3 -#define VERSION_BUILD 7 -#define VERSION_REV 1 +#define VERSION_BUILD 8 +#define VERSION_REV 0 -#define VERSION_STRING "4.3.7.1" +#define VERSION_STRING "4.3.8" From 3b8d2a452703bb1754745931a390b9e8678e602f Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 27 Oct 2022 17:20:41 +0800 Subject: [PATCH 07/33] Edited the format for window title Reorganized RMOBJ_* defines in define_extra.h. --- artifacts/scripting/headers/define_extra.h | 23 +++++++++++++--------- sfall/WinProc.cpp | 5 +++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/artifacts/scripting/headers/define_extra.h b/artifacts/scripting/headers/define_extra.h index ca812cfc0..aaf893e5b 100644 --- a/artifacts/scripting/headers/define_extra.h +++ b/artifacts/scripting/headers/define_extra.h @@ -122,25 +122,22 @@ #define MSGBOX_CLEAN (0x20) // no buttons // Some possible defines for the 4th argument to HOOK_REMOVEINVOBJ -#define RMOBJ_DROP 4831349 // If the object is dropped manually by the player from the inventory screen -#define RMOBJ_TRADE 4683293 // If the object is offered up as a trade -#define RMOBJ_DROPMULTI 4571599 // When dropping a part of a stack (RMOBJ_DROP occurs first) +#define RMOBJ_ITEM_REMOVED_INVEN 4831349 // removing or destroying an item (obj_remove_from_inven_) +#define RMOBJ_ITEM_REMOVED 4548572 // (op_rm_obj_from_inven_) +#define RMOBJ_ITEM_REMOVED_MULTI 4563866 // (op_rm_mult_objs_from_inven_) +#define RMOBJ_ITEM_DESTROYED 4543215 // (op_destroy_object_) +#define RMOBJ_ITEM_DESTROY_MULTI 4571599 // (op_destroy_mult_objs_) +#define RMOBJ_ITEM_MOVE 4683293 // (item_move_func_) #define RMOBJ_CONSUME_DRUG 4666772 // (inven_action_cursor_) -//#define RMOBJ_CONTAINER 4683293 // same as RMOBJ_TRADE (item_move_func_) #define RMOBJ_USE_OBJ 4666865 // (inven_action_cursor_) #define RMOBJ_EQUIP_ARMOR 4658121 // (inven_pickup_) #define RMOBJ_EQUIP_WEAPON 4658675 // (switch_hand_) #define RMOBJ_UNLOAD_WEAPON 4667030 // (inven_action_cursor_) -//#define RMOBJ_LOAD_WEAPON 4831349 // same as RMOBJ_DROP (obj_remove_from_inven_) #define RMOBJ_USE_DRUG_ON 4834866 // (obj_use_item_on_) #define RMOBJ_STEAL_VIEW 4668206 // (loot_container_) -//#define RMOBJ_DROP_DYNAMITE 4666865 // same as RMOBJ_USE_OBJ -#define RMOBJ_ITEM_DESTROYED 4543215 // (op_destroy_object_) -#define RMOBJ_ITEM_REMOVED 4548572 // (op_rm_obj_from_inven_) #define RMOBJ_ARMOR_EQUIPED 4651961 // removing armor from the player's slot when entering INVENTORY/LOOT/BARTER/USE inventory #define RMOBJ_LEFT_HAND_EQUIPED 4651899 // removing item from the player's left slot when entering INVENTORY/LOOT/BARTER/USE inventory #define RMOBJ_RIGHT_HAND_EQUIPED 4651934 // removing item from the player's right slot when entering INVENTORY/LOOT/BARTER/USE inventory -#define RMOBJ_RM_MULT_OBJS 4563866 // (op_rm_mult_objs_from_inven_) #define RMOBJ_REPLACE_WEAPON 4658526 // (switch_hand_) #define RMOBJ_THROW 4266040 // (action_ranged_) #define RMOBJ_SUB_CONTAINER 4683191 // search and remove the item from nested containers in the inventory @@ -151,6 +148,14 @@ #define RMOBJ_BARTER_WEAPON 4675722 // removing weapon from NPC's slot before entering the barter screen #define RMOBJ_INVEN_DROP_CAPS 4667295 // if money/caps are dropped manually by the player from the inventory screen #define RMOBJ_DROP_INTO_CONTAINER 4678833 // when dropping items into a container item (bag/backpack) +// old defines +#define RMOBJ_RM_MULT_OBJS RMOBJ_ITEM_REMOVED_MULTI +#define RMOBJ_TRADE RMOBJ_ITEM_MOVE // If the object is offered up as a trade +#define RMOBJ_DROP RMOBJ_ITEM_REMOVED_INVEN // If the object is dropped manually by the player from the inventory screen +#define RMOBJ_DROPMULTI RMOBJ_ITEM_DESTROY_MULTI // When dropping a part of a stack (RMOBJ_ITEM_MOVE occurs first) +//#define RMOBJ_DROP_DYNAMITE RMOBJ_USE_OBJ +//#define RMOBJ_CONTAINER RMOBJ_ITEM_MOVE +//#define RMOBJ_LOAD_WEAPON RMOBJ_ITEM_REMOVED_INVEN // common prototype offsets for get/set_proto_data #define PROTO_PID (1) diff --git a/sfall/WinProc.cpp b/sfall/WinProc.cpp index d07fdf3fc..a2b0ac187 100644 --- a/sfall/WinProc.cpp +++ b/sfall/WinProc.cpp @@ -177,10 +177,11 @@ void WinProc::SetTitle(long wWidth, long wHeight, long gMode) { if (gMode >= 4) std::strcpy(mode, "DX9"); if (HRP::Setting::ScreenWidth() != wWidth || HRP::Setting::ScreenHeight() != wHeight) { - std::sprintf(windowTitle, "%s @sfall " VERSION_STRING " %ix%i >> %ix%i [%s]", + std::sprintf(windowTitle, "%s @sfall " VERSION_STRING " : %ix%i >> %ix%i [%s]", (const char*)0x50AF08, HRP::Setting::ScreenWidth(), HRP::Setting::ScreenHeight(), wWidth, wHeight, mode); } else { - std::sprintf(windowTitle, "%s @sfall " VERSION_STRING " [%s]", (const char*)0x50AF08, mode); + std::sprintf(windowTitle, "%s @sfall " VERSION_STRING " : %ix%i [%s]", + (const char*)0x50AF08, HRP::Setting::ScreenWidth(), HRP::Setting::ScreenHeight(), mode); } SetWindowTextA(window, windowTitle); } From f7d94e16c93c5aa9f76ca304330fe0288f0adf0c Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 29 Oct 2022 11:32:25 +0800 Subject: [PATCH 08/33] Tweaked HOOK_INVENTORYMOVE for dropping caps * before the amount was set in the dropped object only after the hook. Edits to hook script documents. --- artifacts/scripting/functions.yml | 21 ++++++++------ artifacts/scripting/hooks.yml | 6 ++++ artifacts/scripting/hookscripts.md | 34 ++++++++++++++++------- docs/hooks.md | 2 +- sfall/Modules/HookScripts/InventoryHs.cpp | 6 ++++ 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/artifacts/scripting/functions.yml b/artifacts/scripting/functions.yml index 6a6fe04ff..8ff9c91f1 100644 --- a/artifacts/scripting/functions.yml +++ b/artifacts/scripting/functions.yml @@ -1178,34 +1178,34 @@ opcode: 0x81e5 - name: set_sfall_arg detail: void set_sfall_arg(int argNum, int value) - doc: Changes argument value. The argument number (argNum) is 0-indexed. This is useful if you have several hook scripts attached to one hook point (see `register_hook_proc`). + doc: Changes argument value. The argument number (`argNum`) is 0-indexed. This is useful if you have several hook scripts attached to one hook point (see `register_hook_proc`). opcode: 0x823d - name: register_hook detail: void register_hook(int hookID) - doc: Used from a normal global script if you want to run it at the same point a full hook script would normally run. In case of this function, `start` proc will be executed in current global script. You can use all above functions like normal. + doc: Used from a normal global script if you want to run it at the same point a full hook script would normally run. In case of this function, `start` procedure will be executed in current global script. You can use all above functions like normal. opcode: 0x8207 - name: register_hook_proc detail: void register_hook_proc(int hookID, proc procedure) doc: | - The same as `register_hook`, except that you specifically define which procedure in the current script should be called as a hook (instead of "start" by default). Pass procedure the same as how you use dialog option functions. This IS the recommended way to use hook scripts, as it gives both modularity (each mod logic in a separate global script, no conflicts if you don't use "hs_*.int" scripts) and flexibility (you can place all related hook scripts for specific mod in a single script!). + The same as `register_hook`, except that you specifically define which procedure in the current script should be called as a hook (instead of "start" by default). Pass procedure the same as how you use dialog option functions. This IS the recommended way to use hook scripts, as it gives both modularity (each mod logic in a separate global script with no conflicts) and flexibility. You can place all related hook scripts for a specific mod in one global script! Use zero (0) as second argument to unregister hook script from current global script. - __NOTE:__ you can hook several scripts to a single hook point, for example if it's different mods from different authors or just some different aspects of one larger mod. In this case scripts are executed in reverse order of how they were registered. When one of the scripts in a chain returns value with `set_sfall_return`, the next script may override this value if calls `set_sfall_return` again. Sometimes you need to multiply certain value in a chain of hook scripts. + __NOTE:__ you can hook several scripts to a single hook point, for example if it's different mods from different authors or just some different aspects of one larger mod. When one of the scripts in a chain returns value with `set_sfall_return`, the next script may override this value if calls `set_sfall_return` again. - Example: let's say we have a Mod A which reduces all "to hit" chances by 50%. The code might look like this: + __Example:__ Sometimes you need to multiply certain value in a chain of hook scripts. Let's say we have a **Mod A** which reduces all "to hit" chances by 50%. The code might look like this: ```js original_chance = get_sfall_arg; set_sfall_return(original_chance / 2); ``` - Mod B also want to affect hit chances globally, by increasing them by 50%. Now in order for both mods to work well together, we need to add this line to Mod A hook script: + **Mod B** also want to affect hit chances globally, by increasing them by 50%. Now in order for both mods to work well together, we need to add this line to **Mod A** hook script: ```js set_sfall_arg(0, (original_chance / 2)); ``` - This basically changes hook argument for the next script. Mod B code: + This basically changes hook argument for the next script. **Mod B** code: ```js original_chance = get_sfall_arg; set_sfall_return(original_chance * 1.5); @@ -1218,7 +1218,12 @@ opcode: 0x8262 - name: register_hook_proc_spec detail: void register_hook_proc_spec(int hookID, procedure proc) - doc: Works very similar to `register_hook_proc`, except that it registers the current script at the end of the hook script execution chain (i.e. the script will be executed after all previously registered scripts for the same hook, including the `hs_*.int` script). All scripts hooked to a single hook point with this function are executed in exact order of how they were registered, as opposed to the description below, which refers to using `register_hook/register_hook_proc` functions. + doc: Works the same as `register_hook_proc`, except that it registers the current script at the end of the hook script execution chain (i.e. the script will be executed after all previously registered scripts for the same hook, including the `hs_.int` script). In addition, all scripts hooked to a single hook point with this function are executed in the exact order of how they were registered. In the case of using `register_hook` and `register_hook_proc` functions, scripts are executed in reverse order of how they were registered. + + **The execution chain of script procedures for a hook is as follows:** + 1. Procedures registered with `register_hook` and `register_hook_proc` functions (executed in reverse order of registration). + 2. The `hs_.int` script. + 3. Procedures registered with the `register_hook_proc_spec` function (executed in the exact order of registration). - name: Array functions parent: Arrays # not in this files, normal page diff --git a/artifacts/scripting/hooks.yml b/artifacts/scripting/hooks.yml index fb9e4b218..eba64f89e 100644 --- a/artifacts/scripting/hooks.yml +++ b/artifacts/scripting/hooks.yml @@ -408,6 +408,7 @@ id: HOOK_INVENTORYMOVE doc: | Runs before moving items between inventory slots in dude interface. You can override the action. + What you can NOT do with this hook: - force moving items to inappropriate slots (like gun in armor slot) What you can do: @@ -432,6 +433,11 @@ int ret0 - Override setting (-1 - use engine handler, any other value - prevent relocation of item/reloading weapon/picking up item) ``` + Notes for the event of dropping items on the ground: + - the event is called for each item when dropping multiple items from the stack + - for ammo type items, the number of dropped ammo in a pack can be found by using the `get_weapon_ammo_count` function + - for the `PID_BOTTLE_CAPS` item, the event is called only once, and the number of dropped units can be found from the value of the `OBJ_DATA_CUR_CHARGES` object field (or with the `get_weapon_ammo_count` function) + - name: InvenWield id: HOOK_INVENWIELD doc: | diff --git a/artifacts/scripting/hookscripts.md b/artifacts/scripting/hookscripts.md index 037f1a01f..16191be66 100644 --- a/artifacts/scripting/hookscripts.md +++ b/artifacts/scripting/hookscripts.md @@ -7,7 +7,7 @@ In addition to the bit of code it overrides, the script will be run once when fi ### Hooks compatibility -To aid in mods compatibility, avoid using `hs_xxx.int` scripts. Instead it is recommended to use a normal global script combined with `register_hook_proc` or `register_hook`. +To aid in mods compatibility, avoid using the predefined `hs_.int` scripts. Instead it is recommended to use a normal global script combined with `register_hook_proc` or `register_hook`. Example setup for a hook-script based mod: ```js @@ -42,29 +42,37 @@ Returns all hook arguments as a new temp array. Used to return the new values from the script. Each time it's called it sets the next value, or if you've already set all return values it does nothing. #### `void set_sfall_arg(int argNum, int value)` -Changes argument value. The argument number (argNum) is 0-indexed. This is useful if you have several hook scripts attached to one hook point (see below). +Changes argument value. The argument number (`argNum`) is 0-indexed. This is useful if you have several hook scripts attached to one hook point (see below). #### `void register_hook(int hookID)` -Used from a normal global script if you want to run it at the same point a full hook script would normally run. In case of this function, `start` proc will be executed in the current global script. You can use all above functions like normal. +Used from a normal global script if you want to run it at the same point a full hook script would normally run. In case of this function, `start` procedure will be executed in the current global script. You can use all above functions like normal. #### `void register_hook_proc(int hookID, procedure proc)` -The same as `register_hook`, except that you specifically define which procedure in the current script should be called as a hook (instead of "start" by default). Pass procedure the same as how you use dialog option functions. -This IS the recommended way to use hook scripts, as it gives both modularity (each mod logic in a separate global script, no conflicts if you don't use `hs_*.int` scripts) and flexibility (you can place all related hook scripts for specific mod in a single script!). +The same as `register_hook`, except that you specifically define which procedure in the current script should be called as a hook (instead of "start" by default). Pass the procedure the same as how you use dialog option functions. +This IS the recommended way to use hook scripts, as it gives both modularity (each mod logic in a separate global script with no conflicts) and flexibility. You can place all related hook scripts for a specific mod in one global script! Use zero (0) as the second argument to unregister the hook from the current global script. #### `void register_hook_proc_spec(int hookID, procedure proc)` -Works very similar to `register_hook_proc`, except that it registers the current script at the end of the hook script execution chain (i.e. the script will be executed after all previously registered scripts for the same hook, including the `hs_*.int` script). All scripts hooked to a single hook point with this function are executed in exact order of how they were registered, as opposed to the description below, which refers to using `register_hook` and `register_hook_proc` functions. +Works the same as `register_hook_proc`, except that it registers the current script at the end of the hook script execution chain (i.e. the script will be executed after all previously registered scripts for the same hook, including the `hs_.int` script). +In addition, all scripts hooked to a single hook point with this function are executed in the exact order of how they were registered. In the case of using `register_hook` and `register_hook_proc` functions, scripts are executed in reverse order of how they were registered. -__NOTE:__ You can hook several scripts to a single hook point, for example, if it's different mods from different authors or just some different aspects of one larger mod. In this case scripts are executed in reverse order of how they were registered. When one of the scripts in a chain returns value with `set_sfall_return`, the next script may override this value if calls `set_sfall_return` again. Sometimes you need to multiply certain value in a chain of hook scripts. +**The execution chain of script procedures for a hook is as follows:** +1. Procedures registered with `register_hook` and `register_hook_proc` functions (executed in reverse order of registration). +2. The `hs_.int` script. +3. Procedures registered with the `register_hook_proc_spec` function (executed in the exact order of registration). -Example: let's say we have a Mod A which reduces all "to hit" chances by 50%. The code might look like this: +You can hook several scripts to a single hook point, for example, if it's different mods from different authors or just some different aspects of one larger mod. +When one of the scripts in a chain returns value with `set_sfall_return`, the next script may override this value if calls `set_sfall_return` again. + +__Example:__ Sometimes you need to multiply certain value in a chain of hook scripts. +Let's say we have a **Mod A** which reduces all "to hit" chances by 50%. The code might look like this: ```js original_chance = get_sfall_arg; set_sfall_return(original_chance / 2); ``` -Mod B also want to affect hit chances globally, by increasing them by 50%. Now in order for both mods to work well together, we need to add this line to **Mod A** hook script: +**Mod B** also want to affect hit chances globally, by increasing them by 50%. Now in order for both mods to work well together, we need to add this line to **Mod A** hook script: ```js set_sfall_arg(0, (original_chance / 2)); ``` @@ -504,7 +512,8 @@ int ret0 - overrides the returned result of the function: #### `HOOK_INVENTORYMOVE (hs_inventorymove.int)` -Runs before moving items between inventory slots in dude interface. You can override the action.\ +Runs before moving items between inventory slots in dude interface. You can override the action. + What you can NOT do with this hook: - force moving items to inappropriate slots (like gun in armor slot) @@ -530,6 +539,11 @@ Item arg2 - Item being replaced, weapon being reloaded, or container being fi int ret0 - Override setting (-1 - use engine handler, any other value - prevent relocation of item/reloading weapon/picking up item) ``` +Notes for the event of dropping items on the ground: +- the event is called for each item when dropping multiple items from the stack +- for ammo type items, the number of dropped ammo in a pack can be found by using the `get_weapon_ammo_count` function +- for the `PID_BOTTLE_CAPS` item, the event is called only once, and the number of dropped units can be found from the value of the `OBJ_DATA_CUR_CHARGES` object field (or with the `get_weapon_ammo_count` function) + ------------------------------------------- #### `HOOK_INVENWIELD (hs_invenwield.int)` diff --git a/docs/hooks.md b/docs/hooks.md index 10841a033..ba42b7995 100644 --- a/docs/hooks.md +++ b/docs/hooks.md @@ -15,7 +15,7 @@ See [hook types]({{ site.baseurl }}/hook-types/) and hook [functions reference]( ## Hooks compatibility -To aid in mods compatibility, avoid using `hs_xxx` .int scripts. Instead it is recommended to use a normal global script combined with [register_hook_proc]({{ site.baseurl }}/hook-functions/#register_hook_proc) or [register_hook]({{ site.baseurl }}/hook-functions/#register_hook). +To aid in mods compatibility, avoid using the predefined `hs_.int` scripts. Instead it is recommended to use a normal global script combined with [register_hook_proc]({{ site.baseurl }}/hook-functions/#register_hook_proc) or [register_hook]({{ site.baseurl }}/hook-functions/#register_hook). Example setup for a hook-script based mod: diff --git a/sfall/Modules/HookScripts/InventoryHs.cpp b/sfall/Modules/HookScripts/InventoryHs.cpp index c90ad7fbf..da9b8c03a 100644 --- a/sfall/Modules/HookScripts/InventoryHs.cpp +++ b/sfall/Modules/HookScripts/InventoryHs.cpp @@ -213,7 +213,13 @@ static void __declspec(naked) InvenActionCursorObjDropHook() { nextHookDropSkip = 0; goto skipHook; } else { + using namespace fo::Fields; __asm { + cmp dword ptr [esp], 0x47379A + 5; // caps call address + jnz notCaps; + mov [edx + charges], ebx; // edx - caps, ebx - amount-1 + add dword ptr [edx + charges], 1; +notCaps: pushadc; xor ecx, ecx; // no itemReplace push 6; // event: item drop ground From 8521c1772bcea428820758470645a7c46c0c4448 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 16 Nov 2022 12:09:24 +0800 Subject: [PATCH 09/33] Minor edits to a few ASM hacks (Changed 2-bytes null jcc to just 2 nop) --- sfall/Modules/DebugEditor.cpp | 2 +- sfall/Modules/Inventory.cpp | 2 +- sfall/Modules/MiscPatches.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sfall/Modules/DebugEditor.cpp b/sfall/Modules/DebugEditor.cpp index 972e16cf1..2a9a87ddb 100644 --- a/sfall/Modules/DebugEditor.cpp +++ b/sfall/Modules/DebugEditor.cpp @@ -440,7 +440,7 @@ static void DebugModePatch() { if (dbgMode & 1) { SafeWrite16(0x4C6E75, 0x66EB); // jmps 0x4C6EDD SafeWrite8(0x4C6EF2, CodeType::JumpShort); - SafeWrite8(0x4C7034, 0x0); + SafeWrite16(0x4C7033, 0x9090); MakeCall(0x4DC319, win_debug_hook, 2); } } else { diff --git a/sfall/Modules/Inventory.cpp b/sfall/Modules/Inventory.cpp index 24e36218d..d7ceceaf5 100644 --- a/sfall/Modules/Inventory.cpp +++ b/sfall/Modules/Inventory.cpp @@ -638,7 +638,7 @@ void Inventory::init() { sizeLimitMode -= 4; // item_total_weight_ patch SafeWrite8(0x477EB3, CodeType::JumpShort); - SafeWriteBatch(0, {0x477EF5, 0x477F11, 0x477F29}); + SafeWriteBatch(0x9090, {0x477EF4, 0x477F10, 0x477F28}); } invSizeMaxLimit = IniReader::GetConfigInt("Misc", "CritterInvSizeLimit", 100); diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index 80add436f..8dec44ee6 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -635,7 +635,7 @@ static void DisablePipboyAlarmPatch() { if (IniReader::GetConfigInt("Misc", "DisablePipboyAlarm", 0)) { dlog("Applying Disable Pip-Boy alarm button patch.", DL_INIT); SafeWrite8(0x499518, CodeType::Ret); - SafeWrite8(0x443601, 0x0); + SafeWrite8(0x443601, 0); dlogr(" Done", DL_INIT); } } @@ -671,7 +671,7 @@ static void DialogueFix() { static void AlwaysReloadMsgs() { if (IniReader::GetConfigInt("Misc", "AlwaysReloadMsgs", 0)) { dlog("Applying always reload messages patch.", DL_INIT); - SafeWrite8(0x4A6B8D, 0x0); + SafeWrite8(0x4A6B8D, 0); // jnz $+6 dlogr(" Done", DL_INIT); } } @@ -679,7 +679,7 @@ static void AlwaysReloadMsgs() { static void MusicInDialoguePatch() { if (IniReader::GetConfigInt("Misc", "EnableMusicInDialogue", 0)) { dlog("Applying music in dialogue patch.", DL_INIT); - SafeWrite8(0x44525B, 0); + SafeWrite16(0x44525A, 0x9090); //BlockCall(0x450627); dlogr(" Done", DL_INIT); } From 9ecd5985447b9b87c78c4ae2064bcd4a66a5cf2d Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 26 Nov 2022 09:43:02 +0800 Subject: [PATCH 10/33] Fixed args for HOOK_RESTTIMER --- artifacts/scripting/headers/define_extra.h | 2 +- sfall/Modules/HookScripts/MiscHs.cpp | 16 ++++++++-------- sfall/Modules/Karma.h | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/artifacts/scripting/headers/define_extra.h b/artifacts/scripting/headers/define_extra.h index aaf893e5b..d9375b322 100644 --- a/artifacts/scripting/headers/define_extra.h +++ b/artifacts/scripting/headers/define_extra.h @@ -146,7 +146,7 @@ //#define RMOBJ_AI_USE_DRUG_ON_2 4360176 // same as RMOBJ_AI_USE_DRUG_ON (obsolete, use only for sfall before 4.3.1/3.8.31) #define RMOBJ_BARTER_ARMOR 4675656 // removing armor from NPC's slot before entering the barter screen #define RMOBJ_BARTER_WEAPON 4675722 // removing weapon from NPC's slot before entering the barter screen -#define RMOBJ_INVEN_DROP_CAPS 4667295 // if money/caps are dropped manually by the player from the inventory screen +#define RMOBJ_INVEN_DROP_CAPS 4667295 // if multiple money/caps are dropped manually by the player from the inventory screen #define RMOBJ_DROP_INTO_CONTAINER 4678833 // when dropping items into a container item (bag/backpack) // old defines #define RMOBJ_RM_MULT_OBJS RMOBJ_ITEM_REMOVED_MULTI diff --git a/sfall/Modules/HookScripts/MiscHs.cpp b/sfall/Modules/HookScripts/MiscHs.cpp index dc8dfd27c..e30c618f8 100644 --- a/sfall/Modules/HookScripts/MiscHs.cpp +++ b/sfall/Modules/HookScripts/MiscHs.cpp @@ -373,7 +373,7 @@ static void CarTravelHook_Script() { consumption = static_cast(rets[1]); } // consume fuel - fo::var::carGasAmount = max(originalGas - consumption, 0); + fo::var::carGasAmount = max(0, originalGas - consumption); EndHook(); } @@ -457,9 +457,9 @@ static long __fastcall RestTimerHook_Script(DWORD hours, DWORD minutes, DWORD ga static void __declspec(naked) RestTimerLoopHook() { __asm { pushadc; - mov edx, [esp + 20 + 0x44]; // minutes_ - mov ecx, [esp + 20 + 0x40]; // hours_ - push [esp + 16]; // addrHook + mov edx, [esp + 16 + 0x44]; // minutes_ + mov ecx, [esp + 16 + 0x40]; // hours_ + push [esp + 12]; // addrHook push eax; // gameTime call RestTimerHook_Script; pop ecx; @@ -477,9 +477,9 @@ static void __declspec(naked) RestTimerEscapeHook() { cmp eax, 0x1B; // ESC ASCII code jnz skip; pushadc; - mov edx, [esp + 20 + 0x44]; // minutes_ - mov ecx, [esp + 20 + 0x40]; // hours_ - push [esp + 16]; // addrHook + mov edx, [esp + 16 + 0x44]; // minutes_ + mov ecx, [esp + 16 + 0x40]; // hours_ + push [esp + 12]; // addrHook push eax; // gameTime call RestTimerHook_Script; pop ecx; @@ -717,7 +717,7 @@ void Inject_WithinPerceptionHook() { void Inject_CarTravelHook() { MakeJump(0x4BFEF1, CarTravelHack); - BlockCall(0x4BFF6E); // vanilla wnCarUseGas(100) call + BlockCall(0x4BFF6E); // vanilla wmCarUseGas(100) call } void Inject_SetGlobalVarHook() { diff --git a/sfall/Modules/Karma.h b/sfall/Modules/Karma.h index 4be555dc5..d13fafcf9 100644 --- a/sfall/Modules/Karma.h +++ b/sfall/Modules/Karma.h @@ -26,8 +26,9 @@ namespace sfall class Karma : public Module { public: const char* name() { return "Karma"; } - static void DisplayKarma(int value); void init(); + + static void DisplayKarma(int value); }; extern bool displayKarmaChanges; From 024a13c6a8fb61e74a292dcc4edbbfe1a891204f Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 30 Nov 2022 14:27:46 +0800 Subject: [PATCH 11/33] Minor edits to code and documents --- artifacts/ddraw.ini | 2 +- artifacts/scripting/hooks.yml | 4 ++-- artifacts/scripting/hookscripts.md | 4 ++-- sfall/Modules/HookScripts.cpp | 4 ++-- sfall/Modules/HookScripts.h | 2 -- sfall/Modules/HookScripts/Common.cpp | 2 +- sfall/Modules/HookScripts/Common.h | 2 +- sfall/Modules/HookScripts/MiscHs.cpp | 11 +++++++---- sfall/Modules/MiscPatches.cpp | 8 ++++---- sfall/Modules/Scripting/Handlers/Worldmap.cpp | 2 +- 10 files changed, 21 insertions(+), 20 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 36e51ff0e..a07deb1cf 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -752,7 +752,7 @@ AIBestWeaponFix=1 AIDrugUsePerfFix=0 ;Set to 1 to fix the bug of using First Aid/Doctor skills when using them on the player -;This will cause the party member to apply his/her skills when you use First Aid/Doctor skills on the player, but only if +;This will cause the party member to perform First Aid/Doctor skills when you use them on the player, but only if ;the player is standing next to the party member ;Note that because the related engine function is not fully implemented, enabling this option without a global script ;that overrides First Aid/Doctor functions has very limited usefulness diff --git a/artifacts/scripting/hooks.yml b/artifacts/scripting/hooks.yml index eba64f89e..7f47fa4f0 100644 --- a/artifacts/scripting/hooks.yml +++ b/artifacts/scripting/hooks.yml @@ -603,7 +603,7 @@ ``` Obj arg0 - the object - int ret0 - a pointer to the new text received by using "get_string_pointer" function + int ret0 - a pointer to the new text received by using the get_string_pointer function ``` - name: UseSkillOn @@ -619,7 +619,7 @@ int arg2 - skill being used int ret0 - a new critter to override the user critter. Pass -1 to cancel the skill use, pass 0 to skip this return value - int ret1 - pass 1 to allow the skill being used in combat (only for dude_obj or critter being controlled by the player) + int ret1 - pass 1 to allow the skill to be used in combat (only for dude_obj or critter being controlled by the player) ``` - name: OnExplosion diff --git a/artifacts/scripting/hookscripts.md b/artifacts/scripting/hookscripts.md index 16191be66..cc6935571 100644 --- a/artifacts/scripting/hookscripts.md +++ b/artifacts/scripting/hookscripts.md @@ -692,7 +692,7 @@ Does not run if the script of the object overrides the description. ``` Obj arg0 - the object -int ret0 - a pointer to the new text received by using get_string_pointer function +int ret0 - a pointer to the new text received by using the get_string_pointer function ``` ------------------------------------------- @@ -709,7 +709,7 @@ Obj arg1 - the target object/critter int arg2 - skill being used int ret0 - a new critter to override the user critter. Pass -1 to cancel the skill use, pass 0 to skip this return value -int ret1 - pass 1 to allow the skill being used in combat (only for dude_obj or critter being controlled by the player) +int ret1 - pass 1 to allow the skill to be used in combat (only for dude_obj or critter being controlled by the player) ``` ------------------------------------------- diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index 27a2e7e9d..b1e158e70 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -184,7 +184,7 @@ void HookScripts::LoadHookScript(const char* name, int id) { } } -void HookScripts::InitHookScriptFile(const char* name, int id) { +static void InitHookScriptFile(const char* name, int id) { ScriptProgram prog; dlog("> ", DL_HOOK); dlog(name, DL_HOOK); @@ -231,7 +231,7 @@ void HookScripts::InitHookScripts() { dlogr("Running hook scripts...", DL_HOOK); for (auto& hook : HookScripts::hookScriptFilesList) { - HookScripts::InitHookScriptFile(hook.name.c_str(), hook.id); + InitHookScriptFile(hook.name.c_str(), hook.id); } initingHookScripts = 1; diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index fa069ebd1..b51f7f9c1 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -85,7 +85,6 @@ struct HookFile { }; class HookScripts : public Module { - public: const char* name() { return "HookScripts"; } void init(); @@ -95,7 +94,6 @@ class HookScripts : public Module { static std::vector hookScriptFilesList; static void LoadHookScript(const char* name, int id); - static void InitHookScriptFile(const char* name, int id); static void LoadHookScripts(); static void InitHookScripts(); static void HookScriptClear(); diff --git a/sfall/Modules/HookScripts/Common.cpp b/sfall/Modules/HookScripts/Common.cpp index 766a46fba..b504af5d3 100644 --- a/sfall/Modules/HookScripts/Common.cpp +++ b/sfall/Modules/HookScripts/Common.cpp @@ -164,7 +164,7 @@ void __stdcall EndHook() { } // BEGIN HOOKS -void HookCommon::KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey) { +void __stdcall HookCommon::KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey) { if (!IsGameLoaded() || !HookScripts::HookHasScript(HOOK_KEYPRESS)) { return; } diff --git a/sfall/Modules/HookScripts/Common.h b/sfall/Modules/HookScripts/Common.h index 436335b11..a093849db 100644 --- a/sfall/Modules/HookScripts/Common.h +++ b/sfall/Modules/HookScripts/Common.h @@ -18,7 +18,7 @@ class HookCommon { static void __stdcall SetHSReturn(DWORD d); static void GameModeChangeHook(DWORD exit); - static void KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey); + static void __stdcall KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey); static void __stdcall MouseClickHook(DWORD button, bool pressed); static void Reset(); diff --git a/sfall/Modules/HookScripts/MiscHs.cpp b/sfall/Modules/HookScripts/MiscHs.cpp index e30c618f8..2c6221b62 100644 --- a/sfall/Modules/HookScripts/MiscHs.cpp +++ b/sfall/Modules/HookScripts/MiscHs.cpp @@ -99,6 +99,7 @@ void SourceUseSkillOnInit() { sourceSkillOn = fo::var::obj_dude; } static char resultSkillOn; // -1 - cancel handler, 1 - replace user static long bakupCombatState; + static void __fastcall UseSkillOnHook_Script(DWORD source, DWORD target, register DWORD skillId) { BeginHook(); argCount = 3; @@ -612,7 +613,7 @@ static void __declspec(naked) wmRndEncounterOccurred_hook() { jmp fo::funcoffs::wmInterfaceRefresh_; break: mov eax, hkEncounterMapID; - cmp ds:[FO_VAR_Move_on_Car], 0; + cmp dword ptr ds:[FO_VAR_Move_on_Car], 0; je noCar; mov edx, FO_VAR_carCurrentArea; call fo::funcoffs::wmMatchAreaContainingMapIdx_; @@ -623,7 +624,7 @@ static void __declspec(naked) wmRndEncounterOccurred_hook() { mov hkEncounterMapID, -1; cancelEnc: inc eax; // 0 - continue movement, 1 - interrupt - mov ds:[FO_VAR_wmEncounterIconShow], 0; + mov dword ptr ds:[FO_VAR_wmEncounterIconShow], 0; add esp, 4; mov ebx, 0x4C0BC7; jmp ebx; @@ -739,8 +740,10 @@ void Inject_UseSkillOnHook() { MakeCalls(skill_use_hack, {0x4AB05D, 0x4AB558, 0x4ABA60}); // fix checking obj_dude's target // replace _obj_dude with source skill user (skill_use_ function) - SafeWriteBatch((DWORD)&sourceSkillOn, {0x4AAF47, 0x4AB051, 0x4AB3FB, 0x4AB550, 0x4AB8FA, 0x4ABA54}); - SafeWriteBatch((DWORD)&sourceSkillOn, {0x4AB0EF, 0x4AB5C0, 0x4ABAF2}); // fix for time + SafeWriteBatch((DWORD)&sourceSkillOn, { + 0x4AAF47, 0x4AB051, 0x4AB3FB, 0x4AB550, 0x4AB8FA, 0x4ABA54, + 0x4AB0EF, 0x4AB5C0, 0x4ABAF2 // fix for time increment + }); } void Inject_EncounterHook() { diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index 8dec44ee6..617e77f0d 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -40,7 +40,7 @@ static void __declspec(naked) GNW95_process_message_hack() { __asm { push idle; call Sleep; - cmp ds:[FO_VAR_GNW95_isActive], 0; + cmp dword ptr ds:[FO_VAR_GNW95_isActive], 0; retn; } } @@ -727,12 +727,12 @@ static void KeepSelectModePatch() { } static void PartyMemberSkillPatch() { - // Fixed getting distance from source to target when using skills - // Note: this will cause the party member to apply his/her skill when you use First Aid/Doctor skill on the player, but only if + // Fix getting distance from source to target when using skills + // Note: this will cause the party member to perform First Aid/Doctor skills when you use them on the player, but only if // the player is standing next to the party member. Because the related engine function is not fully implemented, enabling // this option without a global script that overrides First Aid/Doctor functions has very limited usefulness if (IniReader::GetConfigInt("Misc", "PartyMemberSkillFix", 0)) { - dlog("Applying party member using First Aid/Doctor skill patch.", DL_INIT); + dlog("Applying First Aid/Doctor skill use patch for party members.", DL_INIT); HookCall(0x412836, action_use_skill_on_hook); dlogr(" Done", DL_INIT); } diff --git a/sfall/Modules/Scripting/Handlers/Worldmap.cpp b/sfall/Modules/Scripting/Handlers/Worldmap.cpp index 4dd2bab6a..52b1810dd 100644 --- a/sfall/Modules/Scripting/Handlers/Worldmap.cpp +++ b/sfall/Modules/Scripting/Handlers/Worldmap.cpp @@ -73,7 +73,7 @@ static void __declspec(naked) wmRndEncounterOccurred_hack() { __asm { test ForceEncounterFlags, 0x1; // _NoCar flag jnz noCar; - cmp ds:[FO_VAR_Move_on_Car], 0; + cmp dword ptr ds:[FO_VAR_Move_on_Car], 0; jz noCar; mov edx, FO_VAR_carCurrentArea; mov eax, ForceEncounterMapID; From 05f2fb40014e7a0f85960742d18ecf3a263310dd Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 3 Dec 2022 13:18:06 +0800 Subject: [PATCH 12/33] Minor edits to Functions_def.h --- sfall/FalloutEngine/Functions_def.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index 3d2451fd3..747557bf4 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -98,21 +98,21 @@ WRAP_WATCOM_FUNC1(long, block_for_tocks, long, ticks) WRAP_WATCOM_FUNC2(long, combat_turn, fo::GameObject*, critter, long, isDudeTurn) // Perform combat turn for a given critter WRAP_WATCOM_FUNC1(long, critter_body_type, fo::GameObject*, critter) WRAP_WATCOM_FUNC1(long, critter_is_dead, fo::GameObject*, critter) +WRAP_WATCOM_FUNC1(long, critter_kill_count_type, fo::GameObject*, critter) WRAP_WATCOM_FUNC1(const char*, critter_name, fo::GameObject*, critter) // Returns the name of the critter WRAP_WATCOM_FUNC1(void, critter_pc_set_name, const char*, newName) // Change the name of playable character WRAP_WATCOM_FUNC1(long, critterIsOverloaded, fo::GameObject*, critter) WRAP_WATCOM_FUNC1(void, display_print, const char*, msg) // Displays message in main UI console window WRAP_WATCOM_FUNC0(void, display_stats) -WRAP_WATCOM_FUNC1(long, critter_kill_count_type, fo::GameObject*, critter) WRAP_WATCOM_FUNC2(void, endgame_load_palette, long, artType, long, fid) WRAP_WATCOM_FUNC1(void, EndLoad, fo::DbFile*, file) // Execute script proc by internal proc number (from script's proc table, basically a sequential number of a procedure as defined in code, starting from 1) WRAP_WATCOM_FUNC2(void, executeProcedure, fo::Program*, sptr, long, procNum) +WRAP_WATCOM_FUNC1(const char*, findCurrentProc, fo::Program*, program) // Returns the name of current procedure by program pointer WRAP_WATCOM_FUNC1(long, folder_print_line, const char*, text) WRAP_WATCOM_FUNC1(long, folder_print_seperator, const char*, text) -WRAP_WATCOM_FUNC1(const char*, findCurrentProc, fo::Program*, program) // Returns the name of current procedure by program pointer -WRAP_WATCOM_FUNC1(long, FMtext_width, const char*, text) WRAP_WATCOM_FUNC1(void, freeColorBlendTable, long, color) +WRAP_WATCOM_FUNC1(long, FMtext_width, const char*, text) WRAP_WATCOM_FUNC1(long, game_get_global_var, long, globalVar) WRAP_WATCOM_FUNC0(long, get_input) WRAP_WATCOM_FUNC1(fo::BlendColorTableData*, getColorBlendTable, long, color) @@ -222,21 +222,21 @@ WRAP_WATCOM_FUNC1(long, register_begin, long, regType) WRAP_WATCOM_FUNC0(long, register_end) WRAP_WATCOM_FUNC3(long, register_object_animate, fo::GameObject*, object, long, anim, long, delay) WRAP_WATCOM_FUNC3(long, register_object_animate_and_hide, fo::GameObject*, object, long, anim, long, delay) -// WRAP_WATCOM_FUNC3(long, register_object_animate_and_move_straight_, fo::GameObject*, object; -// WRAP_WATCOM_FUNC3(long, register_object_animate_forever_, fo::GameObject*, object; -// WRAP_WATCOM_FUNC3(long, register_object_animate_reverse_, fo::GameObject*, object; +//WRAP_WATCOM_FUNC3(long, register_object_animate_and_move_straight_, fo::GameObject*, object; +//WRAP_WATCOM_FUNC3(long, register_object_animate_forever_, fo::GameObject*, object; +//WRAP_WATCOM_FUNC3(long, register_object_animate_reverse_, fo::GameObject*, object; WRAP_WATCOM_FUNC3(long, register_object_change_fid, fo::GameObject*, object, long, artFid, long, delay) -// WRAP_WATCOM_FUNC3(long, register_object_check_falling_, fo::GameObject*, object; +//WRAP_WATCOM_FUNC3(long, register_object_check_falling_, fo::GameObject*, object; WRAP_WATCOM_FUNC1(long, register_object_dec_rotation, fo::GameObject*, object) WRAP_WATCOM_FUNC1(long, register_object_erase, fo::GameObject*, object) WRAP_WATCOM_FUNC3(long, register_object_funset, fo::GameObject*, object, long, action, long, delay) WRAP_WATCOM_FUNC1(long, register_object_inc_rotation, fo::GameObject*, object) WRAP_WATCOM_FUNC3(long, register_object_light, fo::GameObject*, object, long, lightRadius, long, delay) -// WRAP_WATCOM_FUNC3(long, register_object_move_on_stairs_, fo::GameObject*, object; -// WRAP_WATCOM_FUNC3(long, register_object_move_straight_to_tile_, fo::GameObject*, object; -// WRAP_WATCOM_FUNC3(long, register_object_must_call_, fo::GameObject*, object; +//WRAP_WATCOM_FUNC3(long, register_object_move_on_stairs_, fo::GameObject*, object; +//WRAP_WATCOM_FUNC3(long, register_object_move_straight_to_tile_, fo::GameObject*, object; +//WRAP_WATCOM_FUNC3(long, register_object_must_call_, fo::GameObject*, object; WRAP_WATCOM_FUNC1(long, register_object_must_erase, fo::GameObject*, object) -// WRAP_WATCOM_FUNC3(long, register_object_outline_, fo::GameObject*, object; +//WRAP_WATCOM_FUNC3(long, register_object_outline_, fo::GameObject*, object; WRAP_WATCOM_FUNC3(long, register_object_take_out, fo::GameObject*, object, long, holdFrameId, long, nothing) WRAP_WATCOM_FUNC3(long, register_object_turn_towards, fo::GameObject*, object, long, tileNum, long, nothing) WRAP_WATCOM_FUNC2(long, roll_random, long, minValue, long, maxValue) From 52e796815a8163312645a2d368412a30f5a20526 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 17 Dec 2022 10:35:39 +0800 Subject: [PATCH 13/33] Fixed a crash bug in FullItemDescInBarter * when weapon/ammo has no description, it'd trigger UB from strncpy_s. --- sfall/Modules/BugFixes.cpp | 3 +++ sfall/Translate.cpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index 0e8bcd601..a6a972db9 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -1693,6 +1693,9 @@ static bool showItemDescription = false; static void __stdcall AppendText(const char* text, const char* desc) { if (showItemDescription && currDescLen == 0) { + if (desc == nullptr) { + desc = fo::util::MessageSearch(&fo::var::proto_main_msg_file, 493); + } strncpy_s(messageBuffer, desc, 161); int len = strlen(messageBuffer); if (len > 160) { diff --git a/sfall/Translate.cpp b/sfall/Translate.cpp index 7238f74f5..0d0150388 100644 --- a/sfall/Translate.cpp +++ b/sfall/Translate.cpp @@ -49,7 +49,7 @@ std::vector Translate::GetList(const char* section, const char* set static void MakeLangTranslationPath(const char* config) { char patches[65], language[32]; - char fileConfig[65] = ".\\"; + char fileConfig[67] = ".\\"; std::strcpy(&fileConfig[2], config); IniReader::GetString("system", "language", "english", language, 32, fileConfig); @@ -74,7 +74,7 @@ static void InitMessagesTranslate() { combatBlockedMessage = Translate::Get("sfall", "BlockedCombat", "You cannot enter combat at this time."); combatSaveFailureMsg = Translate::Get("sfall", "SaveInCombat", "Cannot save at this time."); saveSfallDataFailMsg = Translate::Get("sfall", "SaveSfallDataFail", "ERROR saving extended savegame information! " - "Check if other programs interfere with savegame files/folders and try again!"); + "Check if other programs interfere with savegame files/folders and try again."); } void Translate::init(const char* config) { From 33e6cb0cb81fea64d943230bab5674afca244ede Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 22 Dec 2022 09:34:52 +0800 Subject: [PATCH 14/33] Fixed broken read_string script function * actually it has never worked. --- sfall/Modules/Scripting/Handlers/Memory.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sfall/Modules/Scripting/Handlers/Memory.cpp b/sfall/Modules/Scripting/Handlers/Memory.cpp index be668827e..ef27688f1 100644 --- a/sfall/Modules/Scripting/Handlers/Memory.cpp +++ b/sfall/Modules/Scripting/Handlers/Memory.cpp @@ -81,17 +81,21 @@ void __declspec(naked) op_read_int() { } void __declspec(naked) op_read_string() { + static const char* emptyStr = ""; __asm { _GET_ARG_INT(error); test eax, eax; jz error; mov edx, eax; result: + mov eax, ebx; + call fo::funcoffs::interpretAddString_; + mov edx, eax; mov eax, ebx; _J_RET_VAL_TYPE(VAR_TYPE_STR); // retn; error: - xor edx, edx; + mov edx, emptyStr; jmp result; } } From 48e2a63cdfc0a7eac070da3d2e7433196b6f2d1e Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 26 Dec 2022 08:43:40 +0800 Subject: [PATCH 15/33] Edits to sfall_ver_* script functions * they take no arguments and only return constants, simpler structure in ASM is enough. --- docs/Gemfile.lock | 4 ++-- sfall/Modules/Scripting/Handlers/Core.cpp | 21 +++++++++++++++------ sfall/Modules/Scripting/Handlers/Core.h | 6 +++--- sfall/Modules/Scripting/Opcodes.cpp | 6 +++--- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 186e495d9..1fd681afc 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -233,7 +233,7 @@ GEM jekyll-seo-tag (~> 2.1) minitest (5.15.0) multipart-post (2.1.1) - nokogiri (1.13.9) + nokogiri (1.13.10) mini_portile2 (~> 2.8.0) racc (~> 1.4) octokit (4.22.0) @@ -242,7 +242,7 @@ GEM pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (4.0.6) - racc (1.6.0) + racc (1.6.1) rb-fsevent (0.11.1) rb-inotify (0.10.1) ffi (~> 1.0) diff --git a/sfall/Modules/Scripting/Handlers/Core.cpp b/sfall/Modules/Scripting/Handlers/Core.cpp index 84ef66b62..fa586138b 100644 --- a/sfall/Modules/Scripting/Handlers/Core.cpp +++ b/sfall/Modules/Scripting/Handlers/Core.cpp @@ -216,16 +216,25 @@ void mf_remove_timer_event(OpcodeContext& ctx) { } } -void op_sfall_ver_major(OpcodeContext& ctx) { - ctx.setReturn(VERSION_MAJOR); +void __declspec(naked) op_sfall_ver_major() { + __asm { + mov edx, VERSION_MAJOR; + _J_RET_VAL_TYPE(VAR_TYPE_INT); + } } -void op_sfall_ver_minor(OpcodeContext& ctx) { - ctx.setReturn(VERSION_MINOR); +void __declspec(naked) op_sfall_ver_minor() { + __asm { + mov edx, VERSION_MINOR; + _J_RET_VAL_TYPE(VAR_TYPE_INT); + } } -void op_sfall_ver_build(OpcodeContext& ctx) { - ctx.setReturn(VERSION_BUILD); +void __declspec(naked) op_sfall_ver_build() { + __asm { + mov edx, VERSION_BUILD; + _J_RET_VAL_TYPE(VAR_TYPE_INT); + } } } diff --git a/sfall/Modules/Scripting/Handlers/Core.h b/sfall/Modules/Scripting/Handlers/Core.h index 67528ac63..b1da13927 100644 --- a/sfall/Modules/Scripting/Handlers/Core.h +++ b/sfall/Modules/Scripting/Handlers/Core.h @@ -64,11 +64,11 @@ void mf_add_g_timer_event(OpcodeContext&); void mf_remove_timer_event(OpcodeContext&); -void op_sfall_ver_major(OpcodeContext&); +void __declspec() op_sfall_ver_major(); -void op_sfall_ver_minor(OpcodeContext&); +void __declspec() op_sfall_ver_minor(); -void op_sfall_ver_build(OpcodeContext&); +void __declspec() op_sfall_ver_build(); } } diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index bca3f1ae7..db9724707 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -150,9 +150,6 @@ static SfallOpcodeInfo opcodeInfoArray[] = { {0x20d, "list_begin", op_list_begin, 1, true, 0, {ARG_INT}}, {0x20e, "list_next", op_list_next, 1, true, 0, {ARG_INT}}, {0x20f, "list_end", op_list_end, 1, false, 0, {ARG_INT}}, - {0x210, "sfall_ver_major", op_sfall_ver_major, 0, true}, - {0x211, "sfall_ver_minor", op_sfall_ver_minor, 0, true}, - {0x212, "sfall_ver_build", op_sfall_ver_build, 0, true}, {0x216, "set_critter_burst_disable", op_set_critter_burst_disable, 2, false, 0, {ARG_OBJECT, ARG_INT}}, {0x217, "get_weapon_ammo_pid", op_get_weapon_ammo_pid, 1, true, -1, {ARG_OBJECT}}, {0x218, "set_weapon_ammo_pid", op_set_weapon_ammo_pid, 2, false, 0, {ARG_OBJECT, ARG_INT}}, @@ -391,6 +388,9 @@ void Opcodes::InitNew() { opcodes[0x1f6] = op_nb_create_char; opcodes[0x206] = op_set_self; + opcodes[0x210] = op_sfall_ver_major; + opcodes[0x211] = op_sfall_ver_minor; + opcodes[0x212] = op_sfall_ver_build; opcodes[0x213] = op_hero_select_win; opcodes[0x214] = op_set_hero_race; opcodes[0x215] = op_set_hero_style; From 9bdd633fcd29e591e361dfd95e5aab8cde35fb22 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 31 Dec 2022 09:48:02 +0800 Subject: [PATCH 16/33] Cosmetic edits: updated/unified the copyright header years --- sfall/CRC.cpp | 2 +- sfall/CRC.h | 2 +- sfall/Delegate.h | 18 ++++++++++++++++++ sfall/FalloutEngine/AsmMacros.h | 2 +- sfall/FalloutEngine/EngineUtils.cpp | 2 +- sfall/FalloutEngine/EngineUtils.h | 2 +- sfall/FalloutEngine/Enums.h | 2 +- sfall/FalloutEngine/Fallout2.h | 2 +- sfall/FalloutEngine/FunctionOffsets.cpp | 2 +- sfall/FalloutEngine/FunctionOffsets.h | 2 +- sfall/FalloutEngine/Functions.cpp | 2 +- sfall/FalloutEngine/Functions.h | 2 +- sfall/FalloutEngine/Structs.h | 2 +- sfall/FalloutEngine/Variables.cpp | 2 +- sfall/FalloutEngine/Variables.h | 2 +- sfall/Game/AI/AIHelpers.cpp | 2 +- sfall/Game/AI/AIHelpers.h | 2 +- sfall/Game/GUI/Text.cpp | 2 +- sfall/Game/GUI/Text.h | 2 +- sfall/Game/GUI/render.cpp | 2 +- sfall/Game/GUI/render.h | 2 +- sfall/Game/combatAI.cpp | 2 +- sfall/Game/combatAI.h | 2 +- sfall/Game/inventory.cpp | 2 +- sfall/Game/inventory.h | 2 +- sfall/Game/items.cpp | 2 +- sfall/Game/items.h | 2 +- sfall/Game/objects.cpp | 2 +- sfall/Game/objects.h | 2 +- sfall/Game/skills.cpp | 2 +- sfall/Game/skills.h | 2 +- sfall/Game/stats.cpp | 2 +- sfall/Game/stats.h | 2 +- sfall/Game/template.cpp | 2 +- sfall/Game/template.h | 2 +- sfall/Game/tilemap.cpp | 2 +- sfall/Game/tilemap.h | 2 +- sfall/HRP/Character.cpp | 2 +- sfall/HRP/Character.h | 2 +- sfall/HRP/CreditsScreen.cpp | 2 +- sfall/HRP/CreditsScreen.h | 2 +- sfall/HRP/DeathScreen.cpp | 2 +- sfall/HRP/DeathScreen.h | 2 +- sfall/HRP/Dialog.cpp | 2 +- sfall/HRP/Dialog.h | 2 +- sfall/HRP/HelpScreen.cpp | 2 +- sfall/HRP/HelpScreen.h | 2 +- sfall/HRP/Image.cpp | 2 +- sfall/HRP/Image.h | 2 +- sfall/HRP/Init.cpp | 2 +- sfall/HRP/Init.h | 2 +- sfall/HRP/InterfaceBar.cpp | 2 +- sfall/HRP/InterfaceBar.h | 2 +- sfall/HRP/Inventory.cpp | 2 +- sfall/HRP/Inventory.h | 2 +- sfall/HRP/LoadSave.cpp | 2 +- sfall/HRP/LoadSave.h | 2 +- sfall/HRP/MainMenu.cpp | 2 +- sfall/HRP/MainMenu.h | 2 +- sfall/HRP/MiscInterface.cpp | 2 +- sfall/HRP/MiscInterface.h | 2 +- sfall/HRP/MoviesScreen.cpp | 2 +- sfall/HRP/MoviesScreen.h | 2 +- sfall/HRP/SlidesScreen.cpp | 2 +- sfall/HRP/SlidesScreen.h | 2 +- sfall/HRP/SplashScreen.cpp | 2 +- sfall/HRP/SplashScreen.h | 2 +- sfall/HRP/ViewMap/EdgeBorder.cpp | 2 +- sfall/HRP/ViewMap/EdgeBorder.h | 2 +- sfall/HRP/ViewMap/EdgeClipping.cpp | 2 +- sfall/HRP/ViewMap/EdgeClipping.h | 2 +- sfall/HRP/ViewMap/ViewMap.cpp | 2 +- sfall/HRP/ViewMap/ViewMap.h | 2 +- sfall/HRP/Worldmap.cpp | 2 +- sfall/HRP/Worldmap.h | 2 +- sfall/IniReader.cpp | 2 +- sfall/IniReader.h | 2 +- sfall/InputFuncs.cpp | 2 +- sfall/InputFuncs.h | 2 +- sfall/Logging.cpp | 2 +- sfall/Logging.h | 2 +- sfall/Modules/AI.cpp | 2 +- sfall/Modules/AI.h | 2 +- sfall/Modules/Animations.cpp | 2 +- sfall/Modules/Animations.h | 2 +- sfall/Modules/BarBoxes.cpp | 2 +- sfall/Modules/BarBoxes.h | 18 ++++++++++++++++++ sfall/Modules/Books.cpp | 2 +- sfall/Modules/Books.h | 2 +- sfall/Modules/BugFixes.cpp | 18 ++++++++++++++++++ sfall/Modules/BugFixes.h | 18 ++++++++++++++++++ sfall/Modules/BurstMods.cpp | 2 +- sfall/Modules/BurstMods.h | 2 +- sfall/Modules/Combat.cpp | 2 +- sfall/Modules/Combat.h | 2 +- sfall/Modules/Console.cpp | 2 +- sfall/Modules/Console.h | 2 +- sfall/Modules/Credits.cpp | 2 +- sfall/Modules/Credits.h | 2 +- sfall/Modules/Criticals.cpp | 2 +- sfall/Modules/Criticals.h | 2 +- sfall/Modules/CritterPoison.cpp | 2 +- sfall/Modules/CritterPoison.h | 2 +- sfall/Modules/CritterStats.cpp | 2 +- sfall/Modules/CritterStats.h | 2 +- sfall/Modules/DamageMod.cpp | 2 +- sfall/Modules/DamageMod.h | 2 +- sfall/Modules/DebugEditor.cpp | 2 +- sfall/Modules/DebugEditor.h | 18 ++++++++++++++++++ sfall/Modules/Drugs.cpp | 2 +- sfall/Modules/Drugs.h | 2 +- sfall/Modules/Elevators.cpp | 2 +- sfall/Modules/Elevators.h | 2 +- sfall/Modules/EngineTweaks.cpp | 2 +- sfall/Modules/EngineTweaks.h | 2 +- sfall/Modules/Explosions.cpp | 2 +- sfall/Modules/Explosions.h | 2 +- sfall/Modules/ExtraSaveSlots.cpp | 2 +- sfall/Modules/ExtraSaveSlots.h | 2 +- sfall/Modules/FileSystem.cpp | 2 +- sfall/Modules/FileSystem.h | 2 +- sfall/Modules/Graphics.cpp | 2 +- sfall/Modules/Graphics.h | 2 +- sfall/Modules/HeroAppearance.cpp | 2 +- sfall/Modules/HeroAppearance.h | 2 +- sfall/Modules/HookScripts.cpp | 2 +- sfall/Modules/HookScripts.h | 2 +- sfall/Modules/Input.cpp | 18 ++++++++++++++++++ sfall/Modules/Input.h | 18 ++++++++++++++++++ sfall/Modules/Interface.cpp | 2 +- sfall/Modules/Interface.h | 18 ++++++++++++++++++ sfall/Modules/Inventory.cpp | 2 +- sfall/Modules/Inventory.h | 2 +- sfall/Modules/Karma.cpp | 2 +- sfall/Modules/Karma.h | 2 +- sfall/Modules/KillCounter.cpp | 2 +- sfall/Modules/KillCounter.h | 2 +- sfall/Modules/LoadGameHook.cpp | 2 +- sfall/Modules/LoadGameHook.h | 2 +- sfall/Modules/LoadOrder.cpp | 2 +- sfall/Modules/LoadOrder.h | 2 +- sfall/Modules/MainLoopHook.cpp | 18 ++++++++++++++++++ sfall/Modules/MainLoopHook.h | 18 ++++++++++++++++++ sfall/Modules/MainMenu.cpp | 2 +- sfall/Modules/MainMenu.h | 2 +- sfall/Modules/Message.cpp | 2 +- sfall/Modules/Message.h | 2 +- sfall/Modules/MetaruleExtender.cpp | 2 +- sfall/Modules/MetaruleExtender.h | 2 +- sfall/Modules/MiscPatches.cpp | 2 +- sfall/Modules/MiscPatches.h | 2 +- sfall/Modules/Module.h | 2 +- sfall/Modules/Movies.cpp | 2 +- sfall/Modules/Movies.h | 2 +- sfall/Modules/Objects.cpp | 2 +- sfall/Modules/Objects.h | 18 ++++++++++++++++++ sfall/Modules/PartyControl.cpp | 2 +- sfall/Modules/PartyControl.h | 2 +- sfall/Modules/Perks.cpp | 2 +- sfall/Modules/Perks.h | 2 +- sfall/Modules/PlayerModel.cpp | 2 +- sfall/Modules/PlayerModel.h | 2 +- sfall/Modules/Premade.cpp | 2 +- sfall/Modules/Premade.h | 2 +- sfall/Modules/QuestList.cpp | 2 +- sfall/Modules/QuestList.h | 2 +- sfall/Modules/Reputations.cpp | 2 +- sfall/Modules/Reputations.h | 18 ++++++++++++++++++ sfall/Modules/ScriptExtender.cpp | 2 +- sfall/Modules/ScriptExtender.h | 2 +- sfall/Modules/ScriptShaders.cpp | 2 +- sfall/Modules/ScriptShaders.h | 18 ++++++++++++++++++ sfall/Modules/Scripting/Arrays.cpp | 18 ++++++++++++++++++ sfall/Modules/Scripting/Arrays.h | 18 ++++++++++++++++++ sfall/Modules/Scripting/Handlers/Anims.cpp | 2 +- sfall/Modules/Scripting/Handlers/Anims.h | 2 +- sfall/Modules/Scripting/Handlers/Arrays.cpp | 2 +- sfall/Modules/Scripting/Handlers/Arrays.h | 2 +- sfall/Modules/Scripting/Handlers/Combat.cpp | 2 +- sfall/Modules/Scripting/Handlers/Combat.h | 2 +- sfall/Modules/Scripting/Handlers/Core.cpp | 2 +- sfall/Modules/Scripting/Handlers/Core.h | 2 +- .../Modules/Scripting/Handlers/FileSystem.cpp | 2 +- sfall/Modules/Scripting/Handlers/FileSystem.h | 2 +- sfall/Modules/Scripting/Handlers/Graphics.cpp | 2 +- sfall/Modules/Scripting/Handlers/Graphics.h | 2 +- sfall/Modules/Scripting/Handlers/Interface.cpp | 2 +- sfall/Modules/Scripting/Handlers/Interface.h | 2 +- sfall/Modules/Scripting/Handlers/Inventory.cpp | 2 +- sfall/Modules/Scripting/Handlers/Inventory.h | 2 +- sfall/Modules/Scripting/Handlers/Math.cpp | 2 +- sfall/Modules/Scripting/Handlers/Math.h | 2 +- sfall/Modules/Scripting/Handlers/Memory.cpp | 2 +- sfall/Modules/Scripting/Handlers/Memory.h | 2 +- sfall/Modules/Scripting/Handlers/Metarule.cpp | 2 +- sfall/Modules/Scripting/Handlers/Metarule.h | 2 +- sfall/Modules/Scripting/Handlers/Misc.cpp | 2 +- sfall/Modules/Scripting/Handlers/Misc.h | 2 +- sfall/Modules/Scripting/Handlers/Objects.cpp | 2 +- sfall/Modules/Scripting/Handlers/Objects.h | 2 +- sfall/Modules/Scripting/Handlers/Perks.cpp | 2 +- sfall/Modules/Scripting/Handlers/Perks.h | 2 +- sfall/Modules/Scripting/Handlers/Stats.cpp | 2 +- sfall/Modules/Scripting/Handlers/Stats.h | 2 +- sfall/Modules/Scripting/Handlers/Utils.cpp | 2 +- sfall/Modules/Scripting/Handlers/Utils.h | 2 +- sfall/Modules/Scripting/Handlers/Worldmap.cpp | 2 +- sfall/Modules/Scripting/Handlers/Worldmap.h | 2 +- sfall/Modules/Scripting/OpcodeContext.cpp | 2 +- sfall/Modules/Scripting/OpcodeContext.h | 2 +- sfall/Modules/Scripting/Opcodes.cpp | 2 +- sfall/Modules/Scripting/Opcodes.h | 2 +- sfall/Modules/Scripting/ScriptValue.cpp | 2 +- sfall/Modules/Scripting/ScriptValue.h | 2 +- sfall/Modules/Skills.cpp | 2 +- sfall/Modules/Skills.h | 2 +- sfall/Modules/Sound.cpp | 2 +- sfall/Modules/Sound.h | 2 +- sfall/Modules/SpeedPatch.cpp | 2 +- sfall/Modules/SpeedPatch.h | 2 +- sfall/Modules/Stats.cpp | 2 +- sfall/Modules/Stats.h | 2 +- sfall/Modules/SubModules/CombatBlock.cpp | 2 +- sfall/Modules/SubModules/CombatBlock.h | 2 +- sfall/Modules/SubModules/DirectDraw.cpp | 2 +- sfall/Modules/SubModules/DirectDraw.h | 2 +- sfall/Modules/SubModules/EnginePerks.cpp | 2 +- sfall/Modules/SubModules/EnginePerks.h | 2 +- sfall/Modules/SubModules/ObjectName.cpp | 2 +- sfall/Modules/SubModules/ObjectName.h | 2 +- sfall/Modules/SubModules/WindowRender.cpp | 2 +- sfall/Modules/SubModules/WindowRender.h | 2 +- sfall/Modules/TalkingHeads.cpp | 2 +- sfall/Modules/TalkingHeads.h | 18 ++++++++++++++++++ sfall/Modules/Tiles.cpp | 2 +- sfall/Modules/Tiles.h | 2 +- sfall/Modules/Unarmed.cpp | 2 +- sfall/Modules/Unarmed.h | 2 +- sfall/Modules/Worldmap.cpp | 2 +- sfall/Modules/Worldmap.h | 2 +- sfall/ReplacementFuncs.h | 14 +++++++++++++- sfall/Translate.cpp | 2 +- sfall/Translate.h | 2 +- sfall/WinProc.cpp | 14 +++++++++++++- sfall/WinProc.h | 14 +++++++++++++- sfall/ddraw.cpp | 2 +- sfall/main.cpp | 2 +- sfall/main.h | 2 +- sfall/version.h | 4 ++-- 249 files changed, 558 insertions(+), 234 deletions(-) diff --git a/sfall/CRC.cpp b/sfall/CRC.cpp index 44806fe69..0c3b5e974 100644 --- a/sfall/CRC.cpp +++ b/sfall/CRC.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/CRC.h b/sfall/CRC.h index 23e8d8925..d6dc13bb1 100644 --- a/sfall/CRC.h +++ b/sfall/CRC.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Delegate.h b/sfall/Delegate.h index 6dd612153..360c99de1 100644 --- a/sfall/Delegate.h +++ b/sfall/Delegate.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include diff --git a/sfall/FalloutEngine/AsmMacros.h b/sfall/FalloutEngine/AsmMacros.h index 3f88af907..9d49f977a 100644 --- a/sfall/FalloutEngine/AsmMacros.h +++ b/sfall/FalloutEngine/AsmMacros.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/EngineUtils.cpp b/sfall/FalloutEngine/EngineUtils.cpp index 7869db436..f05f1b1cd 100644 --- a/sfall/FalloutEngine/EngineUtils.cpp +++ b/sfall/FalloutEngine/EngineUtils.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/EngineUtils.h b/sfall/FalloutEngine/EngineUtils.h index 7b502bd93..0675e11c6 100644 --- a/sfall/FalloutEngine/EngineUtils.h +++ b/sfall/FalloutEngine/EngineUtils.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/Enums.h b/sfall/FalloutEngine/Enums.h index fffabb780..04949120a 100644 --- a/sfall/FalloutEngine/Enums.h +++ b/sfall/FalloutEngine/Enums.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/Fallout2.h b/sfall/FalloutEngine/Fallout2.h index bc5e4885e..365f6e300 100644 --- a/sfall/FalloutEngine/Fallout2.h +++ b/sfall/FalloutEngine/Fallout2.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/FunctionOffsets.cpp b/sfall/FalloutEngine/FunctionOffsets.cpp index e996aad2c..676213e5f 100644 --- a/sfall/FalloutEngine/FunctionOffsets.cpp +++ b/sfall/FalloutEngine/FunctionOffsets.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/FunctionOffsets.h b/sfall/FalloutEngine/FunctionOffsets.h index f15c0f81e..d0a153a5b 100644 --- a/sfall/FalloutEngine/FunctionOffsets.h +++ b/sfall/FalloutEngine/FunctionOffsets.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/Functions.cpp b/sfall/FalloutEngine/Functions.cpp index 0aad23861..81a1b443f 100644 --- a/sfall/FalloutEngine/Functions.cpp +++ b/sfall/FalloutEngine/Functions.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/Functions.h b/sfall/FalloutEngine/Functions.h index c47f2d504..560249a0b 100644 --- a/sfall/FalloutEngine/Functions.h +++ b/sfall/FalloutEngine/Functions.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/Structs.h b/sfall/FalloutEngine/Structs.h index 1d0432289..d2944d4af 100644 --- a/sfall/FalloutEngine/Structs.h +++ b/sfall/FalloutEngine/Structs.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/Variables.cpp b/sfall/FalloutEngine/Variables.cpp index a016e5f56..cc2efedcf 100644 --- a/sfall/FalloutEngine/Variables.cpp +++ b/sfall/FalloutEngine/Variables.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/FalloutEngine/Variables.h b/sfall/FalloutEngine/Variables.h index 7ee11b9e6..7a2de7736 100644 --- a/sfall/FalloutEngine/Variables.h +++ b/sfall/FalloutEngine/Variables.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Game/AI/AIHelpers.cpp b/sfall/Game/AI/AIHelpers.cpp index 5bfa6c929..35f0d5357 100644 --- a/sfall/Game/AI/AIHelpers.cpp +++ b/sfall/Game/AI/AIHelpers.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/AI/AIHelpers.h b/sfall/Game/AI/AIHelpers.h index 4615f527a..68f0052b1 100644 --- a/sfall/Game/AI/AIHelpers.h +++ b/sfall/Game/AI/AIHelpers.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/GUI/Text.cpp b/sfall/Game/GUI/Text.cpp index 4c633718c..d3a035320 100644 --- a/sfall/Game/GUI/Text.cpp +++ b/sfall/Game/GUI/Text.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/GUI/Text.h b/sfall/Game/GUI/Text.h index 61399e930..03bf7ff16 100644 --- a/sfall/Game/GUI/Text.h +++ b/sfall/Game/GUI/Text.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/GUI/render.cpp b/sfall/Game/GUI/render.cpp index b9e5c4838..faa022a24 100644 --- a/sfall/Game/GUI/render.cpp +++ b/sfall/Game/GUI/render.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/GUI/render.h b/sfall/Game/GUI/render.h index 8cb723d92..d8f6ee3fb 100644 --- a/sfall/Game/GUI/render.h +++ b/sfall/Game/GUI/render.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/combatAI.cpp b/sfall/Game/combatAI.cpp index b9878324e..62ab8de48 100644 --- a/sfall/Game/combatAI.cpp +++ b/sfall/Game/combatAI.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/combatAI.h b/sfall/Game/combatAI.h index 243f852c3..5129ca0fd 100644 --- a/sfall/Game/combatAI.h +++ b/sfall/Game/combatAI.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/inventory.cpp b/sfall/Game/inventory.cpp index 45bd0a9e5..aa344c7bd 100644 --- a/sfall/Game/inventory.cpp +++ b/sfall/Game/inventory.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/inventory.h b/sfall/Game/inventory.h index 1ece631de..df7ddb673 100644 --- a/sfall/Game/inventory.h +++ b/sfall/Game/inventory.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/items.cpp b/sfall/Game/items.cpp index c60217730..e14016289 100644 --- a/sfall/Game/items.cpp +++ b/sfall/Game/items.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/items.h b/sfall/Game/items.h index bfeab4dad..066333ea1 100644 --- a/sfall/Game/items.h +++ b/sfall/Game/items.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/objects.cpp b/sfall/Game/objects.cpp index 84ab589b2..7cf0f6084 100644 --- a/sfall/Game/objects.cpp +++ b/sfall/Game/objects.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/objects.h b/sfall/Game/objects.h index d2bd399a6..ed7d259f5 100644 --- a/sfall/Game/objects.h +++ b/sfall/Game/objects.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/skills.cpp b/sfall/Game/skills.cpp index 990e6ef51..ffb38a86b 100644 --- a/sfall/Game/skills.cpp +++ b/sfall/Game/skills.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/skills.h b/sfall/Game/skills.h index f31e975c0..26afe018a 100644 --- a/sfall/Game/skills.h +++ b/sfall/Game/skills.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/stats.cpp b/sfall/Game/stats.cpp index 5dd352d10..06f61792f 100644 --- a/sfall/Game/stats.cpp +++ b/sfall/Game/stats.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/stats.h b/sfall/Game/stats.h index 00fade354..ecd7d7d9a 100644 --- a/sfall/Game/stats.h +++ b/sfall/Game/stats.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/template.cpp b/sfall/Game/template.cpp index fa9a5ca2b..09ad65506 100644 --- a/sfall/Game/template.cpp +++ b/sfall/Game/template.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/template.h b/sfall/Game/template.h index 4c49f3bca..14facad52 100644 --- a/sfall/Game/template.h +++ b/sfall/Game/template.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/tilemap.cpp b/sfall/Game/tilemap.cpp index 620e1fefc..b186bbe9d 100644 --- a/sfall/Game/tilemap.cpp +++ b/sfall/Game/tilemap.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/Game/tilemap.h b/sfall/Game/tilemap.h index bd2260156..627aa1956 100644 --- a/sfall/Game/tilemap.h +++ b/sfall/Game/tilemap.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Character.cpp b/sfall/HRP/Character.cpp index d85c44314..3db8acdab 100644 --- a/sfall/HRP/Character.cpp +++ b/sfall/HRP/Character.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Character.h b/sfall/HRP/Character.h index 609968e5b..41cc7b548 100644 --- a/sfall/HRP/Character.h +++ b/sfall/HRP/Character.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/CreditsScreen.cpp b/sfall/HRP/CreditsScreen.cpp index 8119b2c00..1307c8812 100644 --- a/sfall/HRP/CreditsScreen.cpp +++ b/sfall/HRP/CreditsScreen.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/CreditsScreen.h b/sfall/HRP/CreditsScreen.h index 4b9bbccfc..65c73403d 100644 --- a/sfall/HRP/CreditsScreen.h +++ b/sfall/HRP/CreditsScreen.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/DeathScreen.cpp b/sfall/HRP/DeathScreen.cpp index b648538fc..9e384d4d6 100644 --- a/sfall/HRP/DeathScreen.cpp +++ b/sfall/HRP/DeathScreen.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/DeathScreen.h b/sfall/HRP/DeathScreen.h index 249c37f30..74ff13819 100644 --- a/sfall/HRP/DeathScreen.h +++ b/sfall/HRP/DeathScreen.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Dialog.cpp b/sfall/HRP/Dialog.cpp index d74996a18..6177ef6b0 100644 --- a/sfall/HRP/Dialog.cpp +++ b/sfall/HRP/Dialog.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Dialog.h b/sfall/HRP/Dialog.h index b6d8eff64..e2cdf3d22 100644 --- a/sfall/HRP/Dialog.h +++ b/sfall/HRP/Dialog.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/HelpScreen.cpp b/sfall/HRP/HelpScreen.cpp index a96324b25..8bff6f73a 100644 --- a/sfall/HRP/HelpScreen.cpp +++ b/sfall/HRP/HelpScreen.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/HelpScreen.h b/sfall/HRP/HelpScreen.h index 3a6b2c6cd..dbcdc240d 100644 --- a/sfall/HRP/HelpScreen.h +++ b/sfall/HRP/HelpScreen.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Image.cpp b/sfall/HRP/Image.cpp index cb24ebb52..3bf65867f 100644 --- a/sfall/HRP/Image.cpp +++ b/sfall/HRP/Image.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Image.h b/sfall/HRP/Image.h index 3faf717fb..e27c98b6d 100644 --- a/sfall/HRP/Image.h +++ b/sfall/HRP/Image.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Init.cpp b/sfall/HRP/Init.cpp index db76cb28f..ca232651f 100644 --- a/sfall/HRP/Init.cpp +++ b/sfall/HRP/Init.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Init.h b/sfall/HRP/Init.h index ba5d0aa70..0581bb69e 100644 --- a/sfall/HRP/Init.h +++ b/sfall/HRP/Init.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/InterfaceBar.cpp b/sfall/HRP/InterfaceBar.cpp index dadb4687c..0d3754ff4 100644 --- a/sfall/HRP/InterfaceBar.cpp +++ b/sfall/HRP/InterfaceBar.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/InterfaceBar.h b/sfall/HRP/InterfaceBar.h index 789d0071b..4b202d135 100644 --- a/sfall/HRP/InterfaceBar.h +++ b/sfall/HRP/InterfaceBar.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Inventory.cpp b/sfall/HRP/Inventory.cpp index b62ffd1d4..88a60e943 100644 --- a/sfall/HRP/Inventory.cpp +++ b/sfall/HRP/Inventory.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Inventory.h b/sfall/HRP/Inventory.h index d095bf3e0..3892831ab 100644 --- a/sfall/HRP/Inventory.h +++ b/sfall/HRP/Inventory.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/LoadSave.cpp b/sfall/HRP/LoadSave.cpp index b01fe0100..f7df15ed8 100644 --- a/sfall/HRP/LoadSave.cpp +++ b/sfall/HRP/LoadSave.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/LoadSave.h b/sfall/HRP/LoadSave.h index 1a62378e9..04d5425c0 100644 --- a/sfall/HRP/LoadSave.h +++ b/sfall/HRP/LoadSave.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/MainMenu.cpp b/sfall/HRP/MainMenu.cpp index 68cfbefea..0e848fe2a 100644 --- a/sfall/HRP/MainMenu.cpp +++ b/sfall/HRP/MainMenu.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/MainMenu.h b/sfall/HRP/MainMenu.h index 00dfd1774..460f6ea63 100644 --- a/sfall/HRP/MainMenu.h +++ b/sfall/HRP/MainMenu.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/MiscInterface.cpp b/sfall/HRP/MiscInterface.cpp index 42688457b..1710bf073 100644 --- a/sfall/HRP/MiscInterface.cpp +++ b/sfall/HRP/MiscInterface.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/MiscInterface.h b/sfall/HRP/MiscInterface.h index 9759fad4d..dc98def28 100644 --- a/sfall/HRP/MiscInterface.h +++ b/sfall/HRP/MiscInterface.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/MoviesScreen.cpp b/sfall/HRP/MoviesScreen.cpp index e3261447c..739f21061 100644 --- a/sfall/HRP/MoviesScreen.cpp +++ b/sfall/HRP/MoviesScreen.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/MoviesScreen.h b/sfall/HRP/MoviesScreen.h index ed1e98ac0..30703a9c4 100644 --- a/sfall/HRP/MoviesScreen.h +++ b/sfall/HRP/MoviesScreen.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/SlidesScreen.cpp b/sfall/HRP/SlidesScreen.cpp index ae6564b92..59c3d9e0d 100644 --- a/sfall/HRP/SlidesScreen.cpp +++ b/sfall/HRP/SlidesScreen.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/SlidesScreen.h b/sfall/HRP/SlidesScreen.h index ed2c2e210..39bbbc80d 100644 --- a/sfall/HRP/SlidesScreen.h +++ b/sfall/HRP/SlidesScreen.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/SplashScreen.cpp b/sfall/HRP/SplashScreen.cpp index 536ea3c96..0a40dfc1b 100644 --- a/sfall/HRP/SplashScreen.cpp +++ b/sfall/HRP/SplashScreen.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/SplashScreen.h b/sfall/HRP/SplashScreen.h index e96e5cfb4..81b2aefbc 100644 --- a/sfall/HRP/SplashScreen.h +++ b/sfall/HRP/SplashScreen.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/ViewMap/EdgeBorder.cpp b/sfall/HRP/ViewMap/EdgeBorder.cpp index e89f13080..50fd7bbbe 100644 --- a/sfall/HRP/ViewMap/EdgeBorder.cpp +++ b/sfall/HRP/ViewMap/EdgeBorder.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/ViewMap/EdgeBorder.h b/sfall/HRP/ViewMap/EdgeBorder.h index c68a0efe1..2427ebf6e 100644 --- a/sfall/HRP/ViewMap/EdgeBorder.h +++ b/sfall/HRP/ViewMap/EdgeBorder.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/ViewMap/EdgeClipping.cpp b/sfall/HRP/ViewMap/EdgeClipping.cpp index 6ce6a6d9b..c96b4ca77 100644 --- a/sfall/HRP/ViewMap/EdgeClipping.cpp +++ b/sfall/HRP/ViewMap/EdgeClipping.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/ViewMap/EdgeClipping.h b/sfall/HRP/ViewMap/EdgeClipping.h index a54e6be3e..ea502929c 100644 --- a/sfall/HRP/ViewMap/EdgeClipping.h +++ b/sfall/HRP/ViewMap/EdgeClipping.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/ViewMap/ViewMap.cpp b/sfall/HRP/ViewMap/ViewMap.cpp index 25219eed7..49cde4cbd 100644 --- a/sfall/HRP/ViewMap/ViewMap.cpp +++ b/sfall/HRP/ViewMap/ViewMap.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/ViewMap/ViewMap.h b/sfall/HRP/ViewMap/ViewMap.h index b88ea61a1..51afa0196 100644 --- a/sfall/HRP/ViewMap/ViewMap.h +++ b/sfall/HRP/ViewMap/ViewMap.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Worldmap.cpp b/sfall/HRP/Worldmap.cpp index a5aa56c8e..a8f1e306a 100644 --- a/sfall/HRP/Worldmap.cpp +++ b/sfall/HRP/Worldmap.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/HRP/Worldmap.h b/sfall/HRP/Worldmap.h index 9a316bde3..deb62ba8d 100644 --- a/sfall/HRP/Worldmap.h +++ b/sfall/HRP/Worldmap.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * */ diff --git a/sfall/IniReader.cpp b/sfall/IniReader.cpp index d46d22d02..6fc626733 100644 --- a/sfall/IniReader.cpp +++ b/sfall/IniReader.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/IniReader.h b/sfall/IniReader.h index 563240417..29ce12171 100644 --- a/sfall/IniReader.h +++ b/sfall/IniReader.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/InputFuncs.cpp b/sfall/InputFuncs.cpp index 7a0a2f946..b3fc875b0 100644 --- a/sfall/InputFuncs.cpp +++ b/sfall/InputFuncs.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/InputFuncs.h b/sfall/InputFuncs.h index dc5d2da33..ec6dbea25 100644 --- a/sfall/InputFuncs.h +++ b/sfall/InputFuncs.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Logging.cpp b/sfall/Logging.cpp index 6f827d110..a1e2a24f3 100644 --- a/sfall/Logging.cpp +++ b/sfall/Logging.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Logging.h b/sfall/Logging.h index 672257d66..b72781037 100644 --- a/sfall/Logging.h +++ b/sfall/Logging.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/AI.cpp b/sfall/Modules/AI.cpp index cfd65ba94..8b34dcf3e 100644 --- a/sfall/Modules/AI.cpp +++ b/sfall/Modules/AI.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/AI.h b/sfall/Modules/AI.h index 6472ddba6..7fc6b4700 100644 --- a/sfall/Modules/AI.h +++ b/sfall/Modules/AI.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Animations.cpp b/sfall/Modules/Animations.cpp index 447b53315..ffddf2fbd 100644 --- a/sfall/Modules/Animations.cpp +++ b/sfall/Modules/Animations.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009, 2010 Mash (Matt Wells, mashw at bigpond dot net dot au) + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Animations.h b/sfall/Modules/Animations.h index 335588e1a..65f8efb36 100644 --- a/sfall/Modules/Animations.h +++ b/sfall/Modules/Animations.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009 Mash (Matt Wells, mashw at bigpond dot net dot au) + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/BarBoxes.cpp b/sfall/Modules/BarBoxes.cpp index 13fd4c66c..087340864 100644 --- a/sfall/Modules/BarBoxes.cpp +++ b/sfall/Modules/BarBoxes.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/BarBoxes.h b/sfall/Modules/BarBoxes.h index 1a1ab190f..34abbca9f 100644 --- a/sfall/Modules/BarBoxes.h +++ b/sfall/Modules/BarBoxes.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "Module.h" diff --git a/sfall/Modules/Books.cpp b/sfall/Modules/Books.cpp index 4ef6155d2..b768a7d07 100644 --- a/sfall/Modules/Books.cpp +++ b/sfall/Modules/Books.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Books.h b/sfall/Modules/Books.h index 28368558d..59d14019c 100644 --- a/sfall/Modules/Books.h +++ b/sfall/Modules/Books.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index a6a972db9..00d722115 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "..\main.h" #include "..\FalloutEngine\Fallout2.h" #include "..\Translate.h" diff --git a/sfall/Modules/BugFixes.h b/sfall/Modules/BugFixes.h index 88010834c..8954ed516 100644 --- a/sfall/Modules/BugFixes.h +++ b/sfall/Modules/BugFixes.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "Module.h" diff --git a/sfall/Modules/BurstMods.cpp b/sfall/Modules/BurstMods.cpp index efd0e3077..436bba54a 100644 --- a/sfall/Modules/BurstMods.cpp +++ b/sfall/Modules/BurstMods.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2014 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/BurstMods.h b/sfall/Modules/BurstMods.h index fffdc2463..1b2fad7dd 100644 --- a/sfall/Modules/BurstMods.h +++ b/sfall/Modules/BurstMods.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2014 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Combat.cpp b/sfall/Modules/Combat.cpp index 83658e7e2..6a88f2389 100644 --- a/sfall/Modules/Combat.cpp +++ b/sfall/Modules/Combat.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010, 2011, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Combat.h b/sfall/Modules/Combat.h index 2ad8bdc01..2581ecc42 100644 --- a/sfall/Modules/Combat.h +++ b/sfall/Modules/Combat.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2011 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Console.cpp b/sfall/Modules/Console.cpp index 06ea724d5..2eba2961c 100644 --- a/sfall/Modules/Console.cpp +++ b/sfall/Modules/Console.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Console.h b/sfall/Modules/Console.h index 81f1d22f3..c6bef370d 100644 --- a/sfall/Modules/Console.h +++ b/sfall/Modules/Console.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Credits.cpp b/sfall/Modules/Credits.cpp index d771ea244..71430517b 100644 --- a/sfall/Modules/Credits.cpp +++ b/sfall/Modules/Credits.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Credits.h b/sfall/Modules/Credits.h index 5f4e3a798..25bb0713d 100644 --- a/sfall/Modules/Credits.h +++ b/sfall/Modules/Credits.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Criticals.cpp b/sfall/Modules/Criticals.cpp index 8c35abd2b..eb0c982da 100644 --- a/sfall/Modules/Criticals.cpp +++ b/sfall/Modules/Criticals.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Criticals.h b/sfall/Modules/Criticals.h index cb01a46ae..1a600261f 100644 --- a/sfall/Modules/Criticals.h +++ b/sfall/Modules/Criticals.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/CritterPoison.cpp b/sfall/Modules/CritterPoison.cpp index 8487ea8b2..3826e1839 100644 --- a/sfall/Modules/CritterPoison.cpp +++ b/sfall/Modules/CritterPoison.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/CritterPoison.h b/sfall/Modules/CritterPoison.h index c0899055a..21894861f 100644 --- a/sfall/Modules/CritterPoison.h +++ b/sfall/Modules/CritterPoison.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/CritterStats.cpp b/sfall/Modules/CritterStats.cpp index 146a84d14..3964572fe 100644 --- a/sfall/Modules/CritterStats.cpp +++ b/sfall/Modules/CritterStats.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2019 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/CritterStats.h b/sfall/Modules/CritterStats.h index b6f1c45dd..430e7ae10 100644 --- a/sfall/Modules/CritterStats.h +++ b/sfall/Modules/CritterStats.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2019 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/DamageMod.cpp b/sfall/Modules/DamageMod.cpp index 50c8fffc7..b06be6c5e 100644 --- a/sfall/Modules/DamageMod.cpp +++ b/sfall/Modules/DamageMod.cpp @@ -1,6 +1,6 @@ /* * sfall -* Copyright (C) 2008, 2009, 2010, 2013, 2014 The sfall team +* Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/DamageMod.h b/sfall/Modules/DamageMod.h index 40ab95919..ac14bd5a7 100644 --- a/sfall/Modules/DamageMod.h +++ b/sfall/Modules/DamageMod.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/DebugEditor.cpp b/sfall/Modules/DebugEditor.cpp index 2a9a87ddb..8c734808f 100644 --- a/sfall/Modules/DebugEditor.cpp +++ b/sfall/Modules/DebugEditor.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/DebugEditor.h b/sfall/Modules/DebugEditor.h index 89cac9ff0..4390b4eef 100644 --- a/sfall/Modules/DebugEditor.h +++ b/sfall/Modules/DebugEditor.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once namespace sfall diff --git a/sfall/Modules/Drugs.cpp b/sfall/Modules/Drugs.cpp index ea5851770..1005f3d09 100644 --- a/sfall/Modules/Drugs.cpp +++ b/sfall/Modules/Drugs.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2019 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Drugs.h b/sfall/Modules/Drugs.h index d09234ca0..60fd3c0aa 100644 --- a/sfall/Modules/Drugs.h +++ b/sfall/Modules/Drugs.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2019 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Elevators.cpp b/sfall/Modules/Elevators.cpp index 57141675e..689f0da10 100644 --- a/sfall/Modules/Elevators.cpp +++ b/sfall/Modules/Elevators.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Elevators.h b/sfall/Modules/Elevators.h index 01022169b..ff3b0683b 100644 --- a/sfall/Modules/Elevators.h +++ b/sfall/Modules/Elevators.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/EngineTweaks.cpp b/sfall/Modules/EngineTweaks.cpp index bec68675a..993ec7d01 100644 --- a/sfall/Modules/EngineTweaks.cpp +++ b/sfall/Modules/EngineTweaks.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/EngineTweaks.h b/sfall/Modules/EngineTweaks.h index 9803375d9..3099edb81 100644 --- a/sfall/Modules/EngineTweaks.h +++ b/sfall/Modules/EngineTweaks.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Explosions.cpp b/sfall/Modules/Explosions.cpp index 731d2fbf4..6c5b4af56 100644 --- a/sfall/Modules/Explosions.cpp +++ b/sfall/Modules/Explosions.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2014 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Explosions.h b/sfall/Modules/Explosions.h index c97652fe2..b89c95bcd 100644 --- a/sfall/Modules/Explosions.h +++ b/sfall/Modules/Explosions.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2014 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/ExtraSaveSlots.cpp b/sfall/Modules/ExtraSaveSlots.cpp index 982466b47..ff10a6cb8 100644 --- a/sfall/Modules/ExtraSaveSlots.cpp +++ b/sfall/Modules/ExtraSaveSlots.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009, 2010 Mash (Matt Wells, mashw at bigpond dot net dot au) + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/ExtraSaveSlots.h b/sfall/Modules/ExtraSaveSlots.h index f67a3fe27..a5850ae1e 100644 --- a/sfall/Modules/ExtraSaveSlots.h +++ b/sfall/Modules/ExtraSaveSlots.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009 Mash (Matt Wells, mashw at bigpond dot net dot au) + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/FileSystem.cpp b/sfall/Modules/FileSystem.cpp index ace895ab0..842561025 100644 --- a/sfall/Modules/FileSystem.cpp +++ b/sfall/Modules/FileSystem.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/FileSystem.h b/sfall/Modules/FileSystem.h index f335b7d3f..23f12eb3e 100644 --- a/sfall/Modules/FileSystem.h +++ b/sfall/Modules/FileSystem.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Graphics.cpp b/sfall/Modules/Graphics.cpp index a9e000c09..ff9e9b3eb 100644 --- a/sfall/Modules/Graphics.cpp +++ b/sfall/Modules/Graphics.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Graphics.h b/sfall/Modules/Graphics.h index f1bbe04c2..da2cc0dc0 100644 --- a/sfall/Modules/Graphics.h +++ b/sfall/Modules/Graphics.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/HeroAppearance.cpp b/sfall/Modules/HeroAppearance.cpp index bbe3e8025..513b4857c 100644 --- a/sfall/Modules/HeroAppearance.cpp +++ b/sfall/Modules/HeroAppearance.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009, 2010 Mash (Matt Wells, mashw at bigpond dot net dot au) + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/HeroAppearance.h b/sfall/Modules/HeroAppearance.h index d6e19e202..992777b87 100644 --- a/sfall/Modules/HeroAppearance.h +++ b/sfall/Modules/HeroAppearance.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009 Mash (Matt Wells, mashw at bigpond dot net dot au) + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index b1e158e70..a5be4b137 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index b51f7f9c1..a5b6334b0 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Input.cpp b/sfall/Modules/Input.cpp index 387acbc60..f4346d15a 100644 --- a/sfall/Modules/Input.cpp +++ b/sfall/Modules/Input.cpp @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + //#include "..\InputFuncs.h" #include "..\Logging.h" #include "..\SafeWrite.h" diff --git a/sfall/Modules/Input.h b/sfall/Modules/Input.h index b4e9efd64..b1d7accc8 100644 --- a/sfall/Modules/Input.h +++ b/sfall/Modules/Input.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "Module.h" diff --git a/sfall/Modules/Interface.cpp b/sfall/Modules/Interface.cpp index 37cd03612..64e317e7c 100644 --- a/sfall/Modules/Interface.cpp +++ b/sfall/Modules/Interface.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2019 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Interface.h b/sfall/Modules/Interface.h index 7ee1d7f13..c83704b12 100644 --- a/sfall/Modules/Interface.h +++ b/sfall/Modules/Interface.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "Module.h" diff --git a/sfall/Modules/Inventory.cpp b/sfall/Modules/Inventory.cpp index d7ceceaf5..d20b6888a 100644 --- a/sfall/Modules/Inventory.cpp +++ b/sfall/Modules/Inventory.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2011 Timeslip + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Inventory.h b/sfall/Modules/Inventory.h index 03295ad46..cba01927b 100644 --- a/sfall/Modules/Inventory.h +++ b/sfall/Modules/Inventory.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2011 Timeslip + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Karma.cpp b/sfall/Modules/Karma.cpp index 2ca96fa2f..3b27947df 100644 --- a/sfall/Modules/Karma.cpp +++ b/sfall/Modules/Karma.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Karma.h b/sfall/Modules/Karma.h index d13fafcf9..eb376ae6b 100644 --- a/sfall/Modules/Karma.h +++ b/sfall/Modules/Karma.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/KillCounter.cpp b/sfall/Modules/KillCounter.cpp index c365a115f..608cef14d 100644 --- a/sfall/Modules/KillCounter.cpp +++ b/sfall/Modules/KillCounter.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/KillCounter.h b/sfall/Modules/KillCounter.h index 8d48faba4..b0020a433 100644 --- a/sfall/Modules/KillCounter.h +++ b/sfall/Modules/KillCounter.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index 99ef9f522..06ca90145 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010, 2011, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/LoadGameHook.h b/sfall/Modules/LoadGameHook.h index 01496e16f..4834b7ea0 100644 --- a/sfall/Modules/LoadGameHook.h +++ b/sfall/Modules/LoadGameHook.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/LoadOrder.cpp b/sfall/Modules/LoadOrder.cpp index 3730c89d9..cc5c41823 100644 --- a/sfall/Modules/LoadOrder.cpp +++ b/sfall/Modules/LoadOrder.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/LoadOrder.h b/sfall/Modules/LoadOrder.h index 4c9af507c..017d93370 100644 --- a/sfall/Modules/LoadOrder.h +++ b/sfall/Modules/LoadOrder.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/MainLoopHook.cpp b/sfall/Modules/MainLoopHook.cpp index caccb3ffd..3c1559136 100644 --- a/sfall/Modules/MainLoopHook.cpp +++ b/sfall/Modules/MainLoopHook.cpp @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include "..\FalloutEngine\Fallout2.h" #include "..\SafeWrite.h" diff --git a/sfall/Modules/MainLoopHook.h b/sfall/Modules/MainLoopHook.h index 87e395d2e..b3a55f9f5 100644 --- a/sfall/Modules/MainLoopHook.h +++ b/sfall/Modules/MainLoopHook.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "..\Delegate.h" diff --git a/sfall/Modules/MainMenu.cpp b/sfall/Modules/MainMenu.cpp index 9d0732a4c..e9dd28182 100644 --- a/sfall/Modules/MainMenu.cpp +++ b/sfall/Modules/MainMenu.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/MainMenu.h b/sfall/Modules/MainMenu.h index ea1701f14..889249dd4 100644 --- a/sfall/Modules/MainMenu.h +++ b/sfall/Modules/MainMenu.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Message.cpp b/sfall/Modules/Message.cpp index c2d99fe6c..d1c0d753c 100644 --- a/sfall/Modules/Message.cpp +++ b/sfall/Modules/Message.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Message.h b/sfall/Modules/Message.h index da7070195..585714144 100644 --- a/sfall/Modules/Message.h +++ b/sfall/Modules/Message.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/MetaruleExtender.cpp b/sfall/Modules/MetaruleExtender.cpp index f813da68b..133e45cd8 100644 --- a/sfall/Modules/MetaruleExtender.cpp +++ b/sfall/Modules/MetaruleExtender.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/MetaruleExtender.h b/sfall/Modules/MetaruleExtender.h index 3e009c4b9..eae0c64f0 100644 --- a/sfall/Modules/MetaruleExtender.h +++ b/sfall/Modules/MetaruleExtender.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index 617e77f0d..f56f6dd7d 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/MiscPatches.h b/sfall/Modules/MiscPatches.h index 0caa9fc23..3ff9264ae 100644 --- a/sfall/Modules/MiscPatches.h +++ b/sfall/Modules/MiscPatches.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Module.h b/sfall/Modules/Module.h index 868a18baa..463b52097 100644 --- a/sfall/Modules/Module.h +++ b/sfall/Modules/Module.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Movies.cpp b/sfall/Modules/Movies.cpp index cde0c5462..cc0d6cf33 100644 --- a/sfall/Modules/Movies.cpp +++ b/sfall/Modules/Movies.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Movies.h b/sfall/Modules/Movies.h index bb816ce2f..6a76c5f5b 100644 --- a/sfall/Modules/Movies.h +++ b/sfall/Modules/Movies.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Objects.cpp b/sfall/Modules/Objects.cpp index 41b53d9b3..d990f1454 100644 --- a/sfall/Modules/Objects.cpp +++ b/sfall/Modules/Objects.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2018 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Objects.h b/sfall/Modules/Objects.h index 59ab0c431..72b117c7c 100644 --- a/sfall/Modules/Objects.h +++ b/sfall/Modules/Objects.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "Module.h" diff --git a/sfall/Modules/PartyControl.cpp b/sfall/Modules/PartyControl.cpp index 56d678d62..3359a3994 100644 --- a/sfall/Modules/PartyControl.cpp +++ b/sfall/Modules/PartyControl.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/PartyControl.h b/sfall/Modules/PartyControl.h index dd576af26..3d118957d 100644 --- a/sfall/Modules/PartyControl.h +++ b/sfall/Modules/PartyControl.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Perks.cpp b/sfall/Modules/Perks.cpp index fecd6978a..a1b9b8ad0 100644 --- a/sfall/Modules/Perks.cpp +++ b/sfall/Modules/Perks.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Perks.h b/sfall/Modules/Perks.h index 782e86e4d..a283c1cf5 100644 --- a/sfall/Modules/Perks.h +++ b/sfall/Modules/Perks.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/PlayerModel.cpp b/sfall/Modules/PlayerModel.cpp index fdd5973c5..b5fc36f63 100644 --- a/sfall/Modules/PlayerModel.cpp +++ b/sfall/Modules/PlayerModel.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/PlayerModel.h b/sfall/Modules/PlayerModel.h index c90ecdbf7..10ecef27c 100644 --- a/sfall/Modules/PlayerModel.h +++ b/sfall/Modules/PlayerModel.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Premade.cpp b/sfall/Modules/Premade.cpp index d67faa8c8..2847b0606 100644 --- a/sfall/Modules/Premade.cpp +++ b/sfall/Modules/Premade.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Premade.h b/sfall/Modules/Premade.h index 92872436d..9d91fe13c 100644 --- a/sfall/Modules/Premade.h +++ b/sfall/Modules/Premade.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/QuestList.cpp b/sfall/Modules/QuestList.cpp index 5e2ab7bcf..c6336d711 100644 --- a/sfall/Modules/QuestList.cpp +++ b/sfall/Modules/QuestList.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/QuestList.h b/sfall/Modules/QuestList.h index b8d1668c2..ccf948d00 100644 --- a/sfall/Modules/QuestList.h +++ b/sfall/Modules/QuestList.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Reputations.cpp b/sfall/Modules/Reputations.cpp index 5c124741a..e5c62b9bb 100644 --- a/sfall/Modules/Reputations.cpp +++ b/sfall/Modules/Reputations.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Reputations.h b/sfall/Modules/Reputations.h index 03b1c0a24..d3c1a7179 100644 --- a/sfall/Modules/Reputations.h +++ b/sfall/Modules/Reputations.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "Module.h" diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index a9d9a2987..66286dd85 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/ScriptExtender.h b/sfall/Modules/ScriptExtender.h index 5421f6a9d..9e1cf5d12 100644 --- a/sfall/Modules/ScriptExtender.h +++ b/sfall/Modules/ScriptExtender.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/ScriptShaders.cpp b/sfall/Modules/ScriptShaders.cpp index 2d5a0dfc4..59a8ef654 100644 --- a/sfall/Modules/ScriptShaders.cpp +++ b/sfall/Modules/ScriptShaders.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2019 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/ScriptShaders.h b/sfall/Modules/ScriptShaders.h index 3b69141d7..3961ca647 100644 --- a/sfall/Modules/ScriptShaders.h +++ b/sfall/Modules/ScriptShaders.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "Module.h" diff --git a/sfall/Modules/Scripting/Arrays.cpp b/sfall/Modules/Scripting/Arrays.cpp index 4a53486e3..272ebcf11 100644 --- a/sfall/Modules/Scripting/Arrays.cpp +++ b/sfall/Modules/Scripting/Arrays.cpp @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include #include diff --git a/sfall/Modules/Scripting/Arrays.h b/sfall/Modules/Scripting/Arrays.h index 080bdf1fc..147228fa0 100644 --- a/sfall/Modules/Scripting/Arrays.h +++ b/sfall/Modules/Scripting/Arrays.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include diff --git a/sfall/Modules/Scripting/Handlers/Anims.cpp b/sfall/Modules/Scripting/Handlers/Anims.cpp index ec6cc59ee..30abef799 100644 --- a/sfall/Modules/Scripting/Handlers/Anims.cpp +++ b/sfall/Modules/Scripting/Handlers/Anims.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Anims.h b/sfall/Modules/Scripting/Handlers/Anims.h index 88b4f14ab..cbe1abd36 100644 --- a/sfall/Modules/Scripting/Handlers/Anims.h +++ b/sfall/Modules/Scripting/Handlers/Anims.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Arrays.cpp b/sfall/Modules/Scripting/Handlers/Arrays.cpp index a90bed131..e8a362fbb 100644 --- a/sfall/Modules/Scripting/Handlers/Arrays.cpp +++ b/sfall/Modules/Scripting/Handlers/Arrays.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Arrays.h b/sfall/Modules/Scripting/Handlers/Arrays.h index cdb861cb4..f8a403011 100644 --- a/sfall/Modules/Scripting/Handlers/Arrays.h +++ b/sfall/Modules/Scripting/Handlers/Arrays.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Combat.cpp b/sfall/Modules/Scripting/Handlers/Combat.cpp index 680172795..d9e281dc3 100644 --- a/sfall/Modules/Scripting/Handlers/Combat.cpp +++ b/sfall/Modules/Scripting/Handlers/Combat.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Combat.h b/sfall/Modules/Scripting/Handlers/Combat.h index b13405653..e480457cf 100644 --- a/sfall/Modules/Scripting/Handlers/Combat.h +++ b/sfall/Modules/Scripting/Handlers/Combat.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Core.cpp b/sfall/Modules/Scripting/Handlers/Core.cpp index fa586138b..b710649d1 100644 --- a/sfall/Modules/Scripting/Handlers/Core.cpp +++ b/sfall/Modules/Scripting/Handlers/Core.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Core.h b/sfall/Modules/Scripting/Handlers/Core.h index b1da13927..69baeb062 100644 --- a/sfall/Modules/Scripting/Handlers/Core.h +++ b/sfall/Modules/Scripting/Handlers/Core.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/FileSystem.cpp b/sfall/Modules/Scripting/Handlers/FileSystem.cpp index aa49cbe51..689afaebb 100644 --- a/sfall/Modules/Scripting/Handlers/FileSystem.cpp +++ b/sfall/Modules/Scripting/Handlers/FileSystem.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/FileSystem.h b/sfall/Modules/Scripting/Handlers/FileSystem.h index 42a704ac0..325194311 100644 --- a/sfall/Modules/Scripting/Handlers/FileSystem.h +++ b/sfall/Modules/Scripting/Handlers/FileSystem.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Graphics.cpp b/sfall/Modules/Scripting/Handlers/Graphics.cpp index 0cca5b51f..f1f8b6a20 100644 --- a/sfall/Modules/Scripting/Handlers/Graphics.cpp +++ b/sfall/Modules/Scripting/Handlers/Graphics.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Graphics.h b/sfall/Modules/Scripting/Handlers/Graphics.h index 45283073d..a90f3c8c8 100644 --- a/sfall/Modules/Scripting/Handlers/Graphics.h +++ b/sfall/Modules/Scripting/Handlers/Graphics.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Interface.cpp b/sfall/Modules/Scripting/Handlers/Interface.cpp index 2b9025db7..7321dcc5d 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.cpp +++ b/sfall/Modules/Scripting/Handlers/Interface.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Interface.h b/sfall/Modules/Scripting/Handlers/Interface.h index a3851c368..c80af778f 100644 --- a/sfall/Modules/Scripting/Handlers/Interface.h +++ b/sfall/Modules/Scripting/Handlers/Interface.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Inventory.cpp b/sfall/Modules/Scripting/Handlers/Inventory.cpp index a21c00540..b71f475a2 100644 --- a/sfall/Modules/Scripting/Handlers/Inventory.cpp +++ b/sfall/Modules/Scripting/Handlers/Inventory.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Inventory.h b/sfall/Modules/Scripting/Handlers/Inventory.h index 676d74fa3..9e98416f7 100644 --- a/sfall/Modules/Scripting/Handlers/Inventory.h +++ b/sfall/Modules/Scripting/Handlers/Inventory.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Math.cpp b/sfall/Modules/Scripting/Handlers/Math.cpp index a1f3157f8..942e930c4 100644 --- a/sfall/Modules/Scripting/Handlers/Math.cpp +++ b/sfall/Modules/Scripting/Handlers/Math.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Math.h b/sfall/Modules/Scripting/Handlers/Math.h index 00d562705..b2a6a2f2e 100644 --- a/sfall/Modules/Scripting/Handlers/Math.h +++ b/sfall/Modules/Scripting/Handlers/Math.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Memory.cpp b/sfall/Modules/Scripting/Handlers/Memory.cpp index ef27688f1..522f05fab 100644 --- a/sfall/Modules/Scripting/Handlers/Memory.cpp +++ b/sfall/Modules/Scripting/Handlers/Memory.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Memory.h b/sfall/Modules/Scripting/Handlers/Memory.h index 72499efcd..125a74cfc 100644 --- a/sfall/Modules/Scripting/Handlers/Memory.h +++ b/sfall/Modules/Scripting/Handlers/Memory.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index 7aed46a32..8034c37e4 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Metarule.h b/sfall/Modules/Scripting/Handlers/Metarule.h index ded825b7c..b115dd5b4 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.h +++ b/sfall/Modules/Scripting/Handlers/Metarule.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Misc.cpp b/sfall/Modules/Scripting/Handlers/Misc.cpp index f13ab82b4..d40c4f6c6 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.cpp +++ b/sfall/Modules/Scripting/Handlers/Misc.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Misc.h b/sfall/Modules/Scripting/Handlers/Misc.h index 50b241027..f6cbc6d6a 100644 --- a/sfall/Modules/Scripting/Handlers/Misc.h +++ b/sfall/Modules/Scripting/Handlers/Misc.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Objects.cpp b/sfall/Modules/Scripting/Handlers/Objects.cpp index 64f53677d..c7656965d 100644 --- a/sfall/Modules/Scripting/Handlers/Objects.cpp +++ b/sfall/Modules/Scripting/Handlers/Objects.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Objects.h b/sfall/Modules/Scripting/Handlers/Objects.h index 975c17385..ad75853ea 100644 --- a/sfall/Modules/Scripting/Handlers/Objects.h +++ b/sfall/Modules/Scripting/Handlers/Objects.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Perks.cpp b/sfall/Modules/Scripting/Handlers/Perks.cpp index c2c7c7cca..cf06cc403 100644 --- a/sfall/Modules/Scripting/Handlers/Perks.cpp +++ b/sfall/Modules/Scripting/Handlers/Perks.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Perks.h b/sfall/Modules/Scripting/Handlers/Perks.h index 43ba6c16c..b1f242fae 100644 --- a/sfall/Modules/Scripting/Handlers/Perks.h +++ b/sfall/Modules/Scripting/Handlers/Perks.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Stats.cpp b/sfall/Modules/Scripting/Handlers/Stats.cpp index f7ae0d57f..9f7f5c85e 100644 --- a/sfall/Modules/Scripting/Handlers/Stats.cpp +++ b/sfall/Modules/Scripting/Handlers/Stats.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Stats.h b/sfall/Modules/Scripting/Handlers/Stats.h index 7ab031171..218993a8d 100644 --- a/sfall/Modules/Scripting/Handlers/Stats.h +++ b/sfall/Modules/Scripting/Handlers/Stats.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Utils.cpp b/sfall/Modules/Scripting/Handlers/Utils.cpp index 43883374a..97e6dfdb3 100644 --- a/sfall/Modules/Scripting/Handlers/Utils.cpp +++ b/sfall/Modules/Scripting/Handlers/Utils.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Utils.h b/sfall/Modules/Scripting/Handlers/Utils.h index 7230af068..305d93139 100644 --- a/sfall/Modules/Scripting/Handlers/Utils.h +++ b/sfall/Modules/Scripting/Handlers/Utils.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Worldmap.cpp b/sfall/Modules/Scripting/Handlers/Worldmap.cpp index 52b1810dd..477dcc1f1 100644 --- a/sfall/Modules/Scripting/Handlers/Worldmap.cpp +++ b/sfall/Modules/Scripting/Handlers/Worldmap.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Handlers/Worldmap.h b/sfall/Modules/Scripting/Handlers/Worldmap.h index 1ab5115d7..6589ed8ab 100644 --- a/sfall/Modules/Scripting/Handlers/Worldmap.h +++ b/sfall/Modules/Scripting/Handlers/Worldmap.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/OpcodeContext.cpp b/sfall/Modules/Scripting/OpcodeContext.cpp index b87790036..7a45164c9 100644 --- a/sfall/Modules/Scripting/OpcodeContext.cpp +++ b/sfall/Modules/Scripting/OpcodeContext.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/OpcodeContext.h b/sfall/Modules/Scripting/OpcodeContext.h index 4f0561c42..023709038 100644 --- a/sfall/Modules/Scripting/OpcodeContext.h +++ b/sfall/Modules/Scripting/OpcodeContext.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index db9724707..3a4609a97 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/Opcodes.h b/sfall/Modules/Scripting/Opcodes.h index f1677be4f..105478734 100644 --- a/sfall/Modules/Scripting/Opcodes.h +++ b/sfall/Modules/Scripting/Opcodes.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/ScriptValue.cpp b/sfall/Modules/Scripting/ScriptValue.cpp index 37d13cfe7..f360d0f9e 100644 --- a/sfall/Modules/Scripting/ScriptValue.cpp +++ b/sfall/Modules/Scripting/ScriptValue.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Scripting/ScriptValue.h b/sfall/Modules/Scripting/ScriptValue.h index c7b897ba4..5db54245f 100644 --- a/sfall/Modules/Scripting/ScriptValue.h +++ b/sfall/Modules/Scripting/ScriptValue.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Skills.cpp b/sfall/Modules/Skills.cpp index 32c6035c9..4b97582e7 100644 --- a/sfall/Modules/Skills.cpp +++ b/sfall/Modules/Skills.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2011 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Skills.h b/sfall/Modules/Skills.h index 67c72b2a8..6e5667585 100644 --- a/sfall/Modules/Skills.h +++ b/sfall/Modules/Skills.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2011 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Sound.cpp b/sfall/Modules/Sound.cpp index 95f1ad9ef..135b1d9a1 100644 --- a/sfall/Modules/Sound.cpp +++ b/sfall/Modules/Sound.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Sound.h b/sfall/Modules/Sound.h index c2b82024a..b9e02fa93 100644 --- a/sfall/Modules/Sound.h +++ b/sfall/Modules/Sound.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SpeedPatch.cpp b/sfall/Modules/SpeedPatch.cpp index ccac714db..41b0fad7f 100644 --- a/sfall/Modules/SpeedPatch.cpp +++ b/sfall/Modules/SpeedPatch.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SpeedPatch.h b/sfall/Modules/SpeedPatch.h index e6c1f6dbd..d2af589b7 100644 --- a/sfall/Modules/SpeedPatch.h +++ b/sfall/Modules/SpeedPatch.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Stats.cpp b/sfall/Modules/Stats.cpp index 76c47219e..f7918cf66 100644 --- a/sfall/Modules/Stats.cpp +++ b/sfall/Modules/Stats.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Stats.h b/sfall/Modules/Stats.h index 5bac62a1e..923689d9b 100644 --- a/sfall/Modules/Stats.h +++ b/sfall/Modules/Stats.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/CombatBlock.cpp b/sfall/Modules/SubModules/CombatBlock.cpp index 6767809eb..4758b63fa 100644 --- a/sfall/Modules/SubModules/CombatBlock.cpp +++ b/sfall/Modules/SubModules/CombatBlock.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/CombatBlock.h b/sfall/Modules/SubModules/CombatBlock.h index ef10e50b2..e51589041 100644 --- a/sfall/Modules/SubModules/CombatBlock.h +++ b/sfall/Modules/SubModules/CombatBlock.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/DirectDraw.cpp b/sfall/Modules/SubModules/DirectDraw.cpp index a4c391281..b2d5d7f45 100644 --- a/sfall/Modules/SubModules/DirectDraw.cpp +++ b/sfall/Modules/SubModules/DirectDraw.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/DirectDraw.h b/sfall/Modules/SubModules/DirectDraw.h index cf671b7bb..52409c74e 100644 --- a/sfall/Modules/SubModules/DirectDraw.h +++ b/sfall/Modules/SubModules/DirectDraw.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/EnginePerks.cpp b/sfall/Modules/SubModules/EnginePerks.cpp index fbf940e54..e90f29e03 100644 --- a/sfall/Modules/SubModules/EnginePerks.cpp +++ b/sfall/Modules/SubModules/EnginePerks.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/EnginePerks.h b/sfall/Modules/SubModules/EnginePerks.h index 8e67b687e..3465570c7 100644 --- a/sfall/Modules/SubModules/EnginePerks.h +++ b/sfall/Modules/SubModules/EnginePerks.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/ObjectName.cpp b/sfall/Modules/SubModules/ObjectName.cpp index 045aa6241..bc0f017be 100644 --- a/sfall/Modules/SubModules/ObjectName.cpp +++ b/sfall/Modules/SubModules/ObjectName.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/ObjectName.h b/sfall/Modules/SubModules/ObjectName.h index ca7aff596..5fbb5be67 100644 --- a/sfall/Modules/SubModules/ObjectName.h +++ b/sfall/Modules/SubModules/ObjectName.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/WindowRender.cpp b/sfall/Modules/SubModules/WindowRender.cpp index 2318d957f..ba3c55fea 100644 --- a/sfall/Modules/SubModules/WindowRender.cpp +++ b/sfall/Modules/SubModules/WindowRender.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/SubModules/WindowRender.h b/sfall/Modules/SubModules/WindowRender.h index 3905bee26..3267cfb24 100644 --- a/sfall/Modules/SubModules/WindowRender.h +++ b/sfall/Modules/SubModules/WindowRender.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2020 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/TalkingHeads.cpp b/sfall/Modules/TalkingHeads.cpp index de78c16f0..b26e85da0 100644 --- a/sfall/Modules/TalkingHeads.cpp +++ b/sfall/Modules/TalkingHeads.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/TalkingHeads.h b/sfall/Modules/TalkingHeads.h index 54dd57575..535891764 100644 --- a/sfall/Modules/TalkingHeads.h +++ b/sfall/Modules/TalkingHeads.h @@ -1,3 +1,21 @@ +/* + * sfall + * Copyright (C) 2008-2023 The sfall team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #pragma once #include "Module.h" diff --git a/sfall/Modules/Tiles.cpp b/sfall/Modules/Tiles.cpp index 220b1da4f..a40dda1ee 100644 --- a/sfall/Modules/Tiles.cpp +++ b/sfall/Modules/Tiles.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010, 2012 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Tiles.h b/sfall/Modules/Tiles.h index d4fc038f6..dcdd4b629 100644 --- a/sfall/Modules/Tiles.h +++ b/sfall/Modules/Tiles.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Unarmed.cpp b/sfall/Modules/Unarmed.cpp index 0a08e6adc..4c5cb62b2 100644 --- a/sfall/Modules/Unarmed.cpp +++ b/sfall/Modules/Unarmed.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Unarmed.h b/sfall/Modules/Unarmed.h index 9cc01638c..80d8528fd 100644 --- a/sfall/Modules/Unarmed.h +++ b/sfall/Modules/Unarmed.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Worldmap.cpp b/sfall/Modules/Worldmap.cpp index bd0f269dc..3741f7312 100644 --- a/sfall/Modules/Worldmap.cpp +++ b/sfall/Modules/Worldmap.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Modules/Worldmap.h b/sfall/Modules/Worldmap.h index 23e9123f3..f2bab5557 100644 --- a/sfall/Modules/Worldmap.h +++ b/sfall/Modules/Worldmap.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2017 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/ReplacementFuncs.h b/sfall/ReplacementFuncs.h index 6dbf983ee..6f70ebcd4 100644 --- a/sfall/ReplacementFuncs.h +++ b/sfall/ReplacementFuncs.h @@ -1,7 +1,19 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ #pragma once diff --git a/sfall/Translate.cpp b/sfall/Translate.cpp index 0d0150388..d2d3edb01 100644 --- a/sfall/Translate.cpp +++ b/sfall/Translate.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/Translate.h b/sfall/Translate.h index f8f9d25f8..f3591cb99 100644 --- a/sfall/Translate.h +++ b/sfall/Translate.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/WinProc.cpp b/sfall/WinProc.cpp index a2b0ac187..6cd15ab58 100644 --- a/sfall/WinProc.cpp +++ b/sfall/WinProc.cpp @@ -1,7 +1,19 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ #include "main.h" diff --git a/sfall/WinProc.h b/sfall/WinProc.h index e9a7e6e42..332fdca3f 100644 --- a/sfall/WinProc.h +++ b/sfall/WinProc.h @@ -1,7 +1,19 @@ /* * sfall - * Copyright (C) 2008-2021 The sfall team + * Copyright (C) 2008-2023 The sfall team * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ #pragma once diff --git a/sfall/ddraw.cpp b/sfall/ddraw.cpp index 0d88a435a..2d2cb63b3 100644 --- a/sfall/ddraw.cpp +++ b/sfall/ddraw.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008, 2009, 2010 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/main.cpp b/sfall/main.cpp index 9fa8a9dc8..a57d3eb3a 100644 --- a/sfall/main.cpp +++ b/sfall/main.cpp @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/main.h b/sfall/main.h index 363a381a9..8ce73d395 100644 --- a/sfall/main.h +++ b/sfall/main.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2016 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/sfall/version.h b/sfall/version.h index f202f5f89..4d6cfadb3 100644 --- a/sfall/version.h +++ b/sfall/version.h @@ -1,6 +1,6 @@ /* * sfall - * Copyright (C) 2008-2018 The sfall team + * Copyright (C) 2008-2023 The sfall team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ #define TARGETVERSION "Fallout 2 v1.02 US" -#define LEGAL_COPYRIGHT "Copyright (C) 2006-2022, sfall Team" +#define LEGAL_COPYRIGHT "Copyright (C) 2006-2023, sfall Team" #define VERSION_MAJOR 4 #define VERSION_MINOR 3 From ad137896c91050628874b2acc96280e6b97caa91 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 7 Jan 2023 23:06:07 +0800 Subject: [PATCH 17/33] Increased the upper limit of ProcessorIdle --- artifacts/ddraw.ini | 4 ++-- sfall/Modules/MiscPatches.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index a07deb1cf..b54c196a4 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -348,7 +348,7 @@ ExtraKillTypes=0 ;0 - Fallout default ;1 - Glovz's Damage Fix ;2 - Glovz's Damage Fix with Damage Multiplier tweak -;5 - Haenlomal's Yet Another Ammo Mod. +;5 - Haenlomal's Yet Another Ammo Mod DamageFormula=0 ;Prevents you from using 0 to escape from dialogue at any time. @@ -428,7 +428,7 @@ CorpseDeleteTime=6 ;Set a number of milliseconds to idle each input loop ;Set to -1 to disable ;Set to 0 to idle only if other processes are waiting for processor time (WinXP/2000: if processes have equal priority) -;Set to 1 (or some higher number if needed) to prevent 100% CPU use. The maximum is 30 +;Set to 1 (or some higher number if needed) to prevent 100% CPU use. The maximum is 50 ProcessorIdle=-1 ;Set to 1 if using the hero appearance mod diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index f56f6dd7d..3eec786ac 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -914,7 +914,7 @@ static void EngineOptimizationPatches() { } void MiscPatches::SetIdle(int value) { - idle = (value > 30) ? 30 : value; + idle = (value > 50) ? 50 : value; } void MiscPatches::init() { From 5c5df4ef6418afef8f9e57b4cb0f0d179ae25124 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 10 Jan 2023 10:31:35 +0800 Subject: [PATCH 18/33] Added a tweak to allow premade characters to have less than two traits Fixed the player's traits not being displayed in certain unusual cases. (with save editing or hex-edited GCD file) --- sfall/FalloutEngine/VariableOffsets.h | 2 ++ sfall/Modules/Perks.cpp | 12 ++++++++++++ sfall/Modules/Premade.cpp | 17 +++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index 7ad095838..331e06bc0 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -326,6 +326,8 @@ #define FO_VAR_target_str 0x56D518 #define FO_VAR_target_xpos 0x672E20 #define FO_VAR_target_ypos 0x672E24 +#define FO_VAR_temp_trait 0x570A04 +#define FO_VAR_temp_trait2 0x570A08 #define FO_VAR_text_char_width 0x51E3C4 #define FO_VAR_text_height 0x51E3BC #define FO_VAR_text_max 0x51E3D4 diff --git a/sfall/Modules/Perks.cpp b/sfall/Modules/Perks.cpp index a1b9b8ad0..ef2568925 100644 --- a/sfall/Modules/Perks.cpp +++ b/sfall/Modules/Perks.cpp @@ -343,6 +343,17 @@ static FakePerk* __fastcall GetFakeSelectPerk(int id) { return &fakeSelectablePerks[id - startFakeID]; } +static void __declspec(naked) CheckTraitHack() { + __asm { + mov edx, ds:[FO_VAR_temp_trait]; + cmp edx, -1; + jnz end; + mov edx, ds:[FO_VAR_temp_trait2]; +end: + retn; + } +} + // Print a list of fake traits static DWORD HandleFakeTraits(int isSelect) { for (DWORD i = 0; i < fakeTraits.size(); i++) { @@ -829,6 +840,7 @@ static void PerkEngineInit() { perk::EnginePerkBonusInit(); // Character screen (list_perks_) + MakeCall(0x434246, CheckTraitHack, 1); // fix for certain cases HookCall(0x434256, PlayerHasTraitHook); // jz func MakeJump(0x43436B, PlayerHasPerkHack); HookCall(0x4343AC, GetPerkLevelHook); diff --git a/sfall/Modules/Premade.cpp b/sfall/Modules/Premade.cpp index 2847b0606..974e5c502 100644 --- a/sfall/Modules/Premade.cpp +++ b/sfall/Modules/Premade.cpp @@ -85,6 +85,20 @@ static void __declspec(naked) select_update_display_hook() { } } +static void __declspec(naked) select_display_stats_hook() { + __asm { + call fo::funcoffs::trait_name_; + test eax, eax; + jz skip; + retn; +skip: + mov eax, [esp]; + add eax, 94; // offset to next section (0x4A8A60, 0x4A8AC9) + add esp, 4; + jmp eax; + } +} + void Premade::init() { auto premadePaths = IniReader::GetConfigList("misc", "PremadePaths", "", 512); auto premadeFids = IniReader::GetConfigList("misc", "PremadeFIDs", "", 512); @@ -113,6 +127,9 @@ void Premade::init() { // Add language path for premade GCD/BIO files HookCall(0x4A8B44, select_display_bio_hook); HookCall(0x4A7D91, select_update_display_hook); + + // Allow premade characters to have less than two traits + HookCalls(select_display_stats_hook, {0x4A89FD, 0x4A8A66}); } } From dd73cbea9cad1dc79b167782239d95d40e83a9a3 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 2 Feb 2023 12:33:41 +0800 Subject: [PATCH 19/33] Removed StackEmptyWeapons from ddraw.ini (always enabled) --- artifacts/ddraw.ini | 3 --- docs/Gemfile.lock | 6 +++--- sfall/Modules/Credits.cpp | 2 +- sfall/Modules/Inventory.cpp | 7 ++++--- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index b54c196a4..83d7d0f08 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -629,9 +629,6 @@ DialogPanelAnimDelay=33 ;Controls the speed of pipboy alarm clock animations (lower - faster; valid range: 0..127) PipboyTimeAnimDelay=50 -;Set to 1 to stack empty identical weapons, no matter what type of ammo was loaded before -StackEmptyWeapons=0 - ;Changes the way weapon reloading works when you drag ammo onto a weapon in the inventory ;Set to -1 to disable (vanilla behavior with the 'Move Items' window) ;Set to 0 to use all the ammo boxes to reload diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 1fd681afc..eb7bf09bb 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.4.7) + activesupport (6.1.7.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -14,7 +14,7 @@ GEM execjs coffee-script-source (1.11.1) colorator (1.1.0) - commonmarker (0.23.6) + commonmarker (0.23.7) concurrent-ruby (1.1.9) dnsruby (1.61.9) simpleidn (~> 0.1) @@ -102,7 +102,7 @@ GEM octokit (~> 4.0) public_suffix (>= 3.0, < 5.0) typhoeus (~> 1.3) - html-pipeline (2.14.0) + html-pipeline (2.14.3) activesupport (>= 2) nokogiri (>= 1.4) http_parser.rb (0.8.0) diff --git a/sfall/Modules/Credits.cpp b/sfall/Modules/Credits.cpp index 71430517b..a719ee3f9 100644 --- a/sfall/Modules/Credits.cpp +++ b/sfall/Modules/Credits.cpp @@ -70,7 +70,7 @@ static const char* ExtraLines[] = { "Rain man", "Continuum", "Drobovik", - "Burn", + "burn", "Lexx", "Anyone who has used sfall in their own mods", "The bug reporters and feature requesters", diff --git a/sfall/Modules/Inventory.cpp b/sfall/Modules/Inventory.cpp index d20b6888a..c038ead08 100644 --- a/sfall/Modules/Inventory.cpp +++ b/sfall/Modules/Inventory.cpp @@ -359,7 +359,7 @@ static void __declspec(naked) SetDefaultAmmo() { call fo::funcoffs::proto_ptr_; mov edx, [esp]; mov eax, [edx + 0x5C]; // eax = default ammo pid - mov [ecx + ammoPid], eax; // set current ammo proto + mov [ecx + ammoPid], eax; // set current ammo pid add esp, 4; end: pop ecx; @@ -699,10 +699,11 @@ void Inventory::init() { ApplyInvenApCostPatch(); } - if (IniReader::GetConfigInt("Misc", "StackEmptyWeapons", 0)) { + // Set default ammo pid for empty weapons to make them stack regardless of previously loaded ammo + //if (IniReader::GetConfigInt("Misc", "StackEmptyWeapons", 1)) { MakeCall(0x4736C6, inven_action_cursor_hack); HookCall(0x4772AA, item_add_mult_hook); - } + //} // Do not call the 'Move Items' window when using drag and drop to reload weapons in the inventory int ReloadReserve = IniReader::GetConfigInt("Misc", "ReloadReserve", -1); From b6ee7bebf21459c6007a95df63ecf60eabfb73d8 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 9 Feb 2023 15:04:41 +0800 Subject: [PATCH 20/33] Tweaked how disabled unsafe opcodes work * now disabled opcodes will just do nothing instead of causing the script terminated. --- sfall/Modules/Inventory.cpp | 2 +- sfall/Modules/Scripting/Handlers/Memory.cpp | 11 ++++++++++- sfall/Modules/Scripting/Handlers/Memory.h | 1 + sfall/Modules/Scripting/Opcodes.cpp | 17 +++++++++-------- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/sfall/Modules/Inventory.cpp b/sfall/Modules/Inventory.cpp index c038ead08..38d1b4c5e 100644 --- a/sfall/Modules/Inventory.cpp +++ b/sfall/Modules/Inventory.cpp @@ -699,7 +699,7 @@ void Inventory::init() { ApplyInvenApCostPatch(); } - // Set default ammo pid for empty weapons to make them stack regardless of previously loaded ammo + // Set default ammo pid for unloaded weapons to make them stack regardless of previously loaded ammo //if (IniReader::GetConfigInt("Misc", "StackEmptyWeapons", 1)) { MakeCall(0x4736C6, inven_action_cursor_hack); HookCall(0x4772AA, item_add_mult_hook); diff --git a/sfall/Modules/Scripting/Handlers/Memory.cpp b/sfall/Modules/Scripting/Handlers/Memory.cpp index 522f05fab..fb8a9fe85 100644 --- a/sfall/Modules/Scripting/Handlers/Memory.cpp +++ b/sfall/Modules/Scripting/Handlers/Memory.cpp @@ -30,6 +30,7 @@ namespace script #define START_VALID_ADDR 0x410000 #define END_VALID_ADDR 0x6B403F +bool unsafeEnabled = false; bool checkValidMemAddr = true; void __declspec(naked) op_read_byte() { @@ -108,6 +109,8 @@ void __declspec(naked) op_write_byte() { _GET_ARG_INT(end); cmp cx, VAR_TYPE_INT; jnz end; + cmp unsafeEnabled, 0; + jz end; // check valid addr cmp checkValidMemAddr, 0; jz noCheck; @@ -134,6 +137,8 @@ void __declspec(naked) op_write_short() { _GET_ARG_INT(end); cmp cx, VAR_TYPE_INT; jnz end; + cmp unsafeEnabled, 0; + jz end; // check valid addr cmp checkValidMemAddr, 0; jz noCheck; @@ -160,6 +165,8 @@ void __declspec(naked) op_write_int() { _GET_ARG_INT(end); cmp cx, VAR_TYPE_INT; jnz end; + cmp unsafeEnabled, 0; + jz end; // check valid addr cmp checkValidMemAddr, 0; jz noCheck; @@ -197,6 +204,8 @@ void __declspec(naked) op_write_string() { cmp cx, VAR_TYPE_STR; jnz end; next: + cmp unsafeEnabled, 0; + jz end; // ecx - type, esi - value // edx - type, eax - addr // check valid address @@ -228,7 +237,7 @@ static void __fastcall CallOffsetInternal(fo::Program* script, DWORD func) { if ((short)fo::func::interpretPopShort(script) != (short)VAR_TYPE_INT) illegalArg++; args[i] = fo::func::interpretPopLong(script); } - if (illegalArg || (checkValidMemAddr && (args[0] < 0x410010 || args[0] > 0x4FCE34))) { + if (illegalArg || !unsafeEnabled || (checkValidMemAddr && (args[0] < 0x410010 || args[0] > 0x4FCE34))) { args[0] = 0; } else { __asm { diff --git a/sfall/Modules/Scripting/Handlers/Memory.h b/sfall/Modules/Scripting/Handlers/Memory.h index 125a74cfc..0fa31b34d 100644 --- a/sfall/Modules/Scripting/Handlers/Memory.h +++ b/sfall/Modules/Scripting/Handlers/Memory.h @@ -23,6 +23,7 @@ namespace sfall namespace script { +extern bool unsafeEnabled; extern bool checkValidMemAddr; // memory_reading_funcs diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index 3a4609a97..6de80a2fa 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -270,7 +270,7 @@ static void __fastcall defaultOpcodeHandler(fo::Program* program, DWORD opcodeOf } void Opcodes::InitNew() { - dlogr("Adding additional opcodes", DL_SCRIPT); + dlogr("Adding sfall opcodes", DL_SCRIPT); SafeWrite32(0x46E370, opcodeCount); // Maximum number of allowed opcodes SafeWrite32(0x46CE34, (DWORD)opcodes); // cmp check to make sure opcode exists @@ -290,18 +290,19 @@ void Opcodes::InitNew() { }; if (int unsafe = IniReader::GetIntDefaultConfig("Debugging", "AllowUnsafeScripting", 0)) { + unsafeEnabled = true; if (unsafe == 2) checkValidMemAddr = false; dlogr(" Unsafe opcodes enabled.", DL_SCRIPT); - opcodes[0x1cf] = op_write_byte; - opcodes[0x1d0] = op_write_short; - opcodes[0x1d1] = op_write_int; - opcodes[0x21b] = op_write_string; - for (int i = 0x1d2; i < 0x1dc; i++) { - opcodes[i] = op_call_offset; - } } else { dlogr(" Unsafe opcodes disabled.", DL_SCRIPT); } + opcodes[0x1cf] = op_write_byte; + opcodes[0x1d0] = op_write_short; + opcodes[0x1d1] = op_write_int; + opcodes[0x21b] = op_write_string; + for (int i = 0x1d2; i < 0x1dc; i++) { + opcodes[i] = op_call_offset; + } opcodes[0x156] = op_read_byte; opcodes[0x157] = op_read_short; opcodes[0x158] = op_read_int; From 381032a2466837d8fd252eeec0b960435f958dcb Mon Sep 17 00:00:00 2001 From: NovaRain Date: Fri, 10 Feb 2023 08:42:02 +0800 Subject: [PATCH 21/33] Removed redundant "Done" strings from sfall log * only when there are alternative states or for graphics/sound/scripting --- sfall/Modules/AI.cpp | 3 +- sfall/Modules/Animations.cpp | 6 +- sfall/Modules/Books.cpp | 2 +- sfall/Modules/BugFixes.cpp | 174 ++++++++-------------- sfall/Modules/BurstMods.cpp | 3 +- sfall/Modules/Combat.cpp | 3 +- sfall/Modules/Criticals.cpp | 9 +- sfall/Modules/DamageMod.cpp | 6 +- sfall/Modules/DebugEditor.cpp | 6 +- sfall/Modules/Drugs.cpp | 2 +- sfall/Modules/Elevators.cpp | 3 +- sfall/Modules/Explosions.cpp | 3 +- sfall/Modules/ExtraSaveSlots.cpp | 12 +- sfall/Modules/HeroAppearance.cpp | 3 +- sfall/Modules/HeroAppearance.h | 4 +- sfall/Modules/HookScripts/Common.cpp | 8 +- sfall/Modules/Input.cpp | 3 +- sfall/Modules/Interface.cpp | 25 +--- sfall/Modules/Karma.cpp | 7 +- sfall/Modules/KillCounter.cpp | 3 +- sfall/Modules/LoadOrder.cpp | 12 +- sfall/Modules/Message.cpp | 3 +- sfall/Modules/MiscPatches.cpp | 89 ++++------- sfall/Modules/Movies.cpp | 9 +- sfall/Modules/PartyControl.cpp | 6 +- sfall/Modules/Perks.cpp | 15 +- sfall/Modules/PlayerModel.cpp | 12 +- sfall/Modules/Premade.cpp | 3 +- sfall/Modules/QuestList.cpp | 4 +- sfall/Modules/Scripting/Opcodes.cpp | 6 +- sfall/Modules/SpeedPatch.cpp | 3 +- sfall/Modules/SubModules/WindowRender.cpp | 3 +- sfall/Modules/Tiles.cpp | 6 +- sfall/Modules/Worldmap.cpp | 42 ++---- sfall/SimplePatch.h | 3 +- sfall/main.cpp | 3 +- 36 files changed, 174 insertions(+), 330 deletions(-) diff --git a/sfall/Modules/AI.cpp b/sfall/Modules/AI.cpp index 8b34dcf3e..fa1c67f8a 100644 --- a/sfall/Modules/AI.cpp +++ b/sfall/Modules/AI.cpp @@ -587,9 +587,8 @@ void AI::init() { RetryCombatMinAP = IniReader::GetConfigInt("Misc", "NPCsTryToSpendExtraAP", 0); if (RetryCombatMinAP > 0) { - dlog("Applying retry combat patch.", DL_INIT); + dlogr("Applying retry combat patch.", DL_INIT); HookCall(0x422B94, RetryCombatHook); // combat_turn_ - dlogr(" Done", DL_INIT); } /////////////////////// Combat behavior AI fixes /////////////////////// diff --git a/sfall/Modules/Animations.cpp b/sfall/Modules/Animations.cpp index ffddf2fbd..3685d903c 100644 --- a/sfall/Modules/Animations.cpp +++ b/sfall/Modules/Animations.cpp @@ -571,9 +571,8 @@ void Animations::init() { if (animationLimit < 32) animationLimit = 32; if (animationLimit > 32) { if (animationLimit > 127) animationLimit = 127; - dlog("Applying AnimationsAtOnceLimit patch.", DL_INIT); + dlogr("Applying AnimationsAtOnceLimit patch.", DL_INIT); ApplyAnimationsAtOncePatches(animationLimit); - dlogr(" Done", DL_INIT); } // Improved implementation of animation registration @@ -617,10 +616,9 @@ void Animations::init() { // Fix for grave type containers in the open state not executing the use_p_proc procedure if (IniReader::GetConfigInt("Misc", "GraveContainersFix", 0)) { - dlog("Applying grave type containers fix.", DL_INIT); + dlogr("Applying grave type containers fix.", DL_INIT); HookCall(0x49CFAC, obj_use_container_hook); SafeWrite16(0x4122D9, 0x9090); // action_get_an_object_ - dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/Books.cpp b/sfall/Modules/Books.cpp index b768a7d07..ac0e5f634 100644 --- a/sfall/Modules/Books.cpp +++ b/sfall/Modules/Books.cpp @@ -117,7 +117,7 @@ void Books::init() { MakeJump(0x49B9FB, obj_use_book_hook); } - dlog_f(" (%d/%d books) Done\n", DL_INIT, n, count); + dlog_f(" (%d/%d books)\n", DL_INIT, n, count); } } diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index 00d722115..593bbe410 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -3284,19 +3284,17 @@ void BugFixes::init() { // Fix for vanilla division operator treating negative integers as unsigned //if (IniReader::GetConfigInt("Misc", "DivisionOperatorFix", 1)) { - dlog("Applying division operator fix.", DL_FIX); + dlogr("Applying division operator fix.", DL_FIX); SafeWrite32(0x46A51D, 0xFBF79990); // xor edx, edx; div ebx > cdq; idiv ebx - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "SpecialUnarmedAttacksFix", 1)) { - dlog("Applying Special Unarmed Attacks fix.", DL_FIX); + dlogr("Applying Special Unarmed Attacks fix.", DL_FIX); //MakeJump(0x42394D, compute_attack_hack); - implementation moved to Unarmed module - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "SharpshooterFix", 1)) { - dlog("Applying Sharpshooter patch.", DL_FIX); + dlogr("Applying Sharpshooter patch.", DL_FIX); // https://www.nma-fallout.com/threads/fo2-engine-tweaks-sfall.178390/page-119#post-4050162 // by Slider2k HookCall(0x4244AB, SharpShooterFix); // hooks stat_level_() call in detemine_to_hit_func_() @@ -3304,25 +3302,22 @@ void BugFixes::init() { // if ( who == obj_dude ) // dist -= 2 * perk_level_(obj_dude, PERK_sharpshooter); SafeWrite8(0x424527, CodeType::JumpShort); // in detemine_to_hit_func_() - dlogr(" Done", DL_FIX); //} // 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 clickability issues and rest exploit.", DL_FIX); + dlogr("Applying fix for Pip-Boy clickability issues and rest exploit.", DL_FIX); 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_FIX); // Fix for "Too Many Items" bug // http://fforum.kochegarov.com/index.php?showtopic=29288&view=findpost&p=332242 //if (IniReader::GetConfigInt("Misc", "TooManyItemsBugFix", 1)) { - dlog("Applying preventive patch for \"Too Many Items\" bug.", DL_FIX); + dlogr("Applying preventive patch for \"Too Many Items\" bug.", DL_FIX); HookCalls(scr_write_ScriptNode_hook, {0x4A596A, 0x4A59C1}); - dlogr(" Done", DL_FIX); //} // Fix for cells getting consumed even when the car is already fully charged @@ -3330,27 +3325,24 @@ void BugFixes::init() { // Fix for being able to charge the car by using cells on other scenery/critters if (IniReader::GetConfigInt("Misc", "CarChargingFix", 1)) { - dlog("Applying car charging fix.", DL_FIX); + dlogr("Applying car charging fix.", DL_FIX); MakeJump(0x49C36D, protinst_default_use_item_hack); - dlogr(" Done", DL_FIX); } // Fix for gaining stats from more than two doses of a specific chem after save-load - dlog("Applying fix for save-load unlimited drug use exploit.", DL_FIX); + dlogr("Applying fix for save-load unlimited drug use exploit.", DL_FIX); MakeCall(0x47A25B, item_d_save_hack); MakeCall(0x47A243, item_d_load_hack); - dlogr(" Done", DL_FIX); // Fix crash when leaving the map while waiting for someone to die of a super stimpak overdose - dlog("Applying fix for \"leaving the map while waiting for a super stimpak overdose death\" crash.", DL_FIX); + dlogr("Applying fix for \"leaving the map while waiting for a super stimpak overdose death\" crash.", DL_FIX); HookCall(0x4A27E7, queue_clear_type_mem_free_hook); // hooks mem_free_() - dlogr(" Done", DL_FIX); // Evil bug! If party member has the same armor type in inventory as currently equipped, then // on level up he loses Armor Class equal to the one received from this armor. // The same happens if you just order NPC to remove the armor through dialogue. //if (IniReader::GetConfigInt("Misc", "ArmorCorruptsNPCStatsFix", 1)) { - dlog("Applying fix for armor reducing NPC original stats when removed.", DL_FIX); + dlogr("Applying fix for armor reducing NPC original stats when removed.", DL_FIX); HookCall(0x495F3B, partyMemberCopyLevelInfo_hook_stat_level); HookCall(0x45419B, correctFidForRemovedItem_hook_adjust_ac); // Fix for move_obj_inven_to_obj function @@ -3359,47 +3351,40 @@ void BugFixes::init() { SafeWrite8(0x45C4A3, CodeType::JumpNZ); // jmp > jnz // Fix for drop_obj function HookCall(0x49B965, obj_drop_hook); - dlogr(" Done", DL_FIX); //} // Fix of invalid stats when party member gains a level while being on drugs - dlog("Applying fix for addicted party member level up bug.", DL_FIX); + dlogr("Applying fix for addicted party member level up bug.", DL_FIX); HookCall(0x495D5C, partyMemberIncLevels_hook); - dlogr(" Done", DL_FIX); // Allow 9 options (lines of text) to be displayed correctly in a dialog window //if (IniReader::GetConfigInt("Misc", "DialogOptions9Lines", 1)) { - dlog("Applying 9 dialog options patch.", DL_FIX); + dlogr("Applying 9 dialog options patch.", DL_FIX); MakeCall(0x447021, gdProcessUpdate_hack, 1); - dlogr(" Done", DL_FIX); //} // Fix for "Unlimited Ammo" exploit - dlog("Applying fix for Unlimited Ammo exploit.", DL_FIX); + dlogr("Applying fix for Unlimited Ammo exploit.", DL_FIX); HookCall(0x472957, invenWieldFunc_item_get_type_hook); // hooks item_get_type_() - dlogr(" Done", DL_FIX); // Fix for negative values in Skilldex window ("S") - dlog("Applying fix for negative values in Skilldex window.", DL_FIX); + dlogr("Applying fix for negative values in Skilldex window.", DL_FIX); SafeWrite8(0x4AC377, 0x7F); // jg - dlogr(" Done", DL_FIX); // Fix for negative SPECIAL values in character creation - dlog("Applying fix for negative SPECIAL values in character creation.", DL_FIX); + dlogr("Applying fix for negative SPECIAL values in character creation.", DL_FIX); MakeCall(0x43DF6F, is_supper_bonus_hack); MakeCall(0x434BFF, PrintBasicStat_hack); HookCall(0x437AB4, StatButtonUp_hook); HookCall(0x437B26, StatButtonDown_hook); - dlogr(" Done", DL_FIX); // Fix for not counting in the weight/size of equipped items on NPC when stealing or bartering //if (IniReader::GetConfigInt("Misc", "NPCWeightFix", 1)) { - dlog("Applying fix for not counting in weight of equipped items on NPC.", DL_FIX); + dlogr("Applying fix for not counting in weight of equipped items on NPC.", DL_FIX); MakeCall(0x473B4E, loot_container_hack); HookCall(0x4758AB, barter_inventory_hook); MakeCall(0x477EAB, item_total_weight_hack, 1); MakeCall(0x479A2F, item_c_curr_size_hack, 1); - dlogr(" Done", DL_FIX); //} // Corrects the max text width of the item weight in trading interface to be 64 (was 80), which matches the table width @@ -3409,7 +3394,7 @@ void BugFixes::init() { SafeWrite32(0x471E48, 140); //if (IniReader::GetConfigInt("Misc", "InventoryDragIssuesFix", 1)) { - dlog("Applying inventory reverse order issues fix.", DL_FIX); + dlogr("Applying inventory reverse order issues fix.", DL_FIX); // Fix for minor visual glitch when picking up solo item from the top of inventory // and there is multiple item stack at the bottom of inventory MakeCall(0x470EC2, inven_pickup_hack, 2); @@ -3418,83 +3403,73 @@ void BugFixes::init() { MakeJump(0x47114A, inven_pickup_hack2); // Fix for using only one box of ammo when a weapon is above the ammo in the inventory list HookCall(0x476598, drop_ammo_into_weapon_hook); - dlogr(" Done", DL_FIX); //} // Enable party members with level 6 protos to reach level 6 //if (IniReader::GetConfigInt("Misc", "NPCStage6Fix", 1)) { - dlog("Applying NPC Stage 6 Fix.", DL_FIX); + dlogr("Applying NPC Stage 6 Fix.", DL_FIX); 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 - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "NPCLevelFix", 1)) { - dlog("Applying NPC level fix.", DL_FIX); + dlogr("Applying NPC level fix.", DL_FIX); HookCall(0x495BC9, (void*)0x495E51); // jz 0x495E7F > jz 0x495E51 - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "BlackSkilldexFix", 1)) { - dlog("Applying black Skilldex patch.", DL_FIX); + dlogr("Applying black Skilldex patch.", DL_FIX); HookCall(0x497D0F, PipStatus_AddHotLines_hook); - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "FixWithdrawalPerkDescCrash", 1)) { - dlog("Applying withdrawal perk description crash fix.", DL_FIX); + dlogr("Applying withdrawal perk description crash fix.", DL_FIX); HookCall(0x47A501, perform_withdrawal_start_display_print_hook); - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "JetAntidoteFix", 1)) { - dlog("Applying Jet Antidote fix.", DL_FIX); + dlogr("Applying Jet Antidote fix.", DL_FIX); // Fix for Jet antidote not being removed after removing the addiction effect (when using the item) MakeJump(0x47A013, (void*)0x47A168); // item_d_take_drug_ - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "NPCDrugAddictionFix", 1)) { - dlog("Applying NPC's drug addiction fix.", DL_FIX); + dlogr("Applying NPC's drug addiction fix.", DL_FIX); // proper checks for NPC's addiction instead of always using global vars HookCalls(item_d_take_drug_hook, {0x479FBC, 0x47A0AE}); // replace item_d_check_addict_ function calls with sfall implementation MakeCall(0x479FCA, item_d_take_drug_hack, 2); // just add a new "addict" event every 7 days (the previous one is deleted) until the Jet addiction is removed by the antidote // Note: for critters who are not party members, any addiction is removed after leaving the map MakeCall(0x47A3A4, item_wd_process_hack); - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "ShivPatch", 1)) { - dlog("Applying shiv patch.", DL_FIX); + dlogr("Applying shiv patch.", DL_FIX); SafeWrite8(0x477B2B, CodeType::JumpShort); - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "ImportedProcedureFix", 0)) { - dlog("Applying imported procedure patch.", DL_FIX); + dlogr("Applying imported procedure patch.", DL_FIX); // http://teamx.ru/site_arc/smf/index.php-topic=398.0.htm SafeWrite16(0x46B35B, 0x1C60); // Fix problems with the temporary stack SafeWrite32(0x46B35D, 0x90909090); SafeWriteBatch(CodeType::JumpShort, {0x46DBF1, 0x46DDC4}); // Disable warnings SafeWrite8(0x4415CC, 0x00); // Prevent crashes when re-exporting - dlogr(" Done", DL_FIX); //} // 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 (IniReader::GetConfigInt("Misc", "WieldObjCritterFix", 1)) { - dlog("Applying wield_obj_critter fix.", DL_FIX); + dlogr("Applying wield_obj_critter fix.", DL_FIX); SafeWrite8(0x456912, 0x1E); // jnz 0x456931 HookCall(0x45697F, op_wield_obj_critter_adjust_ac_hook); - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "MultiHexPathingFix", 1)) { - dlog("Applying MultiHex Pathing Fix.", DL_FIX); + dlogr("Applying MultiHex Pathing Fix.", DL_FIX); HookCall(0x416144, make_path_func_hook); // Fix for building the path to the central hex of a multihex object //MakeCalls(MultiHexFix, {0x42901F, 0x429170}); // obsolete fix @@ -3504,14 +3479,12 @@ void BugFixes::init() { // Check neighboring tiles to prevent critters from overlapping other object tiles when moving to the retargeted tile SafeWrite16(0x42A3A6, 0xE889); // xor eax, eax > mov eax, ebp (fix retargeting tile for multihex critters) HookCall(0x42A3A8, MultiHexRetargetTileFix); // cai_retargetTileFromFriendlyFire_ - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "DodgyDoorsFix", 1)) { - dlog("Applying Dodgy Door Fix.", DL_FIX); + dlogr("Applying Dodgy Door Fix.", DL_FIX); MakeCall(0x4113D3, action_melee_hack, 2); MakeCall(0x411BC9, action_ranged_hack, 2); - dlogr(" Done", DL_FIX); //} // Fix for multiple knockout events being added to the queue @@ -3529,66 +3502,59 @@ void BugFixes::init() { // Fix for "NPC turns into a container" bug // https://www.nma-fallout.com/threads/fo2-engine-tweaks-sfall.178390/page-123#post-4065716 //if (IniReader::GetConfigInt("Misc", "NPCTurnsIntoContainerFix", 1)) { - dlog("Applying fix for \"NPC turns into a container\" bug.", DL_FIX); + dlogr("Applying fix for \"NPC turns into a container\" bug.", DL_FIX); MakeJump(0x42E46E, critter_wake_clear_hack); MakeCall(0x488EF3, obj_load_func_hack, 1); HookCall(0x4949B2, partyMemberPrepLoadInstance_hook); // Fix for knocked down critters not playing stand up animation when the combat ends (when DAM_LOSE_TURN and DAM_KNOCKED_DOWN flags are set) MakeCall(0x42206F, combat_over_hack, 1); - dlogr(" Done", DL_FIX); //} // Fix to prevent dead NPCs from reloading their weapons when the combat ends HookCall(0x421F30, combat_over_hook); - dlog("Applying fix for explosives bugs.", DL_FIX); + dlogr("Applying fix for explosives bugs.", DL_FIX); // Fix crashes when killing critters with explosives MakeJump(0x422F05, combat_ctd_init_hack); MakeCall(0x48941C, obj_save_hack, 1); // Fix for destroy_p_proc not being called if the critter is killed by explosives when you leave the map MakeCall(0x4130C3, action_explode_hack); MakeCall(0x4130E5, action_explode_hack1); - dlogr(" Done", DL_FIX); // Fix for being unable to sell used geiger counters or stealth boys if (IniReader::GetConfigInt("Misc", "CanSellUsedGeiger", 1)) { - dlog("Applying fix for being unable to sell used geiger counters or stealth boys.", DL_FIX); + dlogr("Applying fix for being unable to sell used geiger counters or stealth boys.", DL_FIX); SafeWriteBatch(0xBA, {0x478115, 0x478138}); // item_queued_ (will return the found item) MakeJump(0x474D22, barter_attempt_transaction_hack, 1); HookCall(0x4798B1, item_m_turn_off_hook); - dlogr(" Done", DL_FIX); } // Fix for incorrect initialization of action points at the beginning of each turn - dlog("Applying Action Points initialization fix.", DL_FIX); + dlogr("Applying Action Points initialization fix.", DL_FIX); BlockCall(0x422E02); MakeCall(0x422E1B, combat_hack); - dlogr(" Done", DL_FIX); // Fix for incorrect death animations being used when killing critters with kill_critter_type function - dlog("Applying kill_critter_type fix.", DL_FIX); + dlogr("Applying kill_critter_type fix.", DL_FIX); SafeWrite16(0x457E22, 0xDB31); // xor ebx, ebx SafeWrite32(0x457C99, 0x30BE0075); // jnz loc_457C9B; mov esi, 48 - dlogr(" Done", DL_FIX); // Fix for checking the horizontal position on the y-axis instead of x when setting coordinates on the world map SafeWrite8(0x4C4743, 0xC6); // cmp esi, eax //if (IniReader::GetConfigInt("Misc", "PrintToFileFix", 1)) { - dlog("Applying print to file fix.", DL_FIX); + dlogr("Applying print to file fix.", DL_FIX); MakeCall(0x4C67D4, db_get_file_list_hack); - dlogr(" Done", DL_FIX); //} // Fix for display issues when calling gdialog_mod_barter with critters with no "Barter" flag set //if (IniReader::GetConfigInt("Misc", "gdBarterDispFix", 1)) { - dlog("Applying gdialog_mod_barter display fix.", DL_FIX); + dlogr("Applying gdialog_mod_barter display fix.", DL_FIX); HookCall(0x448250, gdActivateBarter_hook); - dlogr(" Done", DL_FIX); //} //if (IniReader::GetConfigInt("Misc", "BagBackpackFix", 1)) { - dlog("Applying fix for bag/backpack bugs.", DL_FIX); + dlogr("Applying fix for bag/backpack bugs.", DL_FIX); // Fix for items disappearing from inventory when you try to drag them to bag/backpack in the inventory list // and are overloaded HookCall(0x4764FC, (void*)fo::funcoffs::item_add_force_); @@ -3600,7 +3566,6 @@ void BugFixes::init() { MakeCall(0x471C17, inven_item_wearing, 1); // inven_worn_ // Fix crash when trying to open bag/backpack on the table in the bartering interface MakeCall(0x473191, inven_action_cursor_hack); - dlogr(" Done", DL_FIX); //} // Fix crash when clicking on empty space in the inventory list opened by "Use Inventory Item On" (backpack) action icon @@ -3618,10 +3583,9 @@ void BugFixes::init() { // Fix for Bonus Move APs being replenished when you save and load the game in combat //if (IniReader::GetConfigInt("Misc", "BonusMoveFix", 1)) { - dlog("Applying fix for Bonus Move exploit.", DL_FIX); + dlogr("Applying fix for Bonus Move exploit.", DL_FIX); HookCall(0x420E93, combat_load_hook); MakeCall(0x422A06, combat_turn_hack); - dlogr(" Done", DL_FIX); //} // Fix for the displayed message when the attack randomly hits a target that is not a critter and has a script attached @@ -3633,10 +3597,9 @@ void BugFixes::init() { // Fix for the double damage effect of Silent Death perk not being applied to critical hits //if (IniReader::GetConfigInt("Misc", "SilentDeathFix", 1)) { - dlog("Applying Silent Death patch.", DL_FIX); + dlogr("Applying Silent Death patch.", DL_FIX); SafeWrite8(0x4238DF, 0x8C); // jl loc_423A0D HookCall(0x423A99, compute_attack_hook); - dlogr(" Done", DL_FIX); //} // Fix crash when calling partyMemberGetCurLevel_ on a critter that has no data in party.txt @@ -3661,34 +3624,30 @@ void BugFixes::init() { }); // Fix instant death critical - dlog("Applying instant death fix.", DL_FIX); + dlogr("Applying instant death fix.", DL_FIX); MakeJump(0x424BA2, compute_damage_hack); - dlogr(" Done", DL_FIX); // Fix missing AC/DR mod stats when examining ammo in the barter screen - dlog("Applying fix for displaying ammo stats in barter screen.", DL_FIX); + dlogr("Applying fix for displaying ammo stats in barter screen.", DL_FIX); MakeCall(0x49B4AD, obj_examine_func_hack_ammo0, 2); MakeCall(0x49B504, obj_examine_func_hack_ammo0, 2); MakeCall(0x49B563, obj_examine_func_hack_ammo1, 2); - dlogr(" Done", DL_FIX); // Display full item description for weapon/ammo in the barter screen showItemDescription = (IniReader::GetConfigInt("Misc", "FullItemDescInBarter", 0) != 0); if (showItemDescription) { - dlog("Applying full item description in barter patch.", DL_FIX); + dlogr("Applying full item description in barter patch.", DL_FIX); HookCall(0x49B452, obj_examine_func_hack_weapon); // it's jump - dlogr(" Done", DL_FIX); } // Display experience points with the bonus from Swift Learner perk when gained from non-scripted situations if (IniReader::GetConfigInt("Misc", "DisplaySwiftLearnerExp", 1)) { - dlog("Applying Swift Learner exp display patch.", DL_FIX); + dlogr("Applying Swift Learner exp display patch.", DL_FIX); 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_FIX); } // Fix for obj_can_see_obj not checking if source and target objects are on the same elevation before calling @@ -3698,15 +3657,14 @@ void BugFixes::init() { // Fix broken obj_can_hear_obj function if (IniReader::GetConfigInt("Misc", "ObjCanHearObjFix", 0)) { - dlog("Applying obj_can_hear_obj fix.", DL_FIX); + dlogr("Applying obj_can_hear_obj fix.", DL_FIX); SafeWrite8(0x4583D8, 0x3B); // jz loc_458414 SafeWrite8(0x4583DE, CodeType::JumpZ); // jz loc_458414 MakeCall(0x4583E0, op_obj_can_hear_obj_hack, 1); - dlogr(" Done", DL_FIX); } if (IniReader::GetConfigInt("Misc", "AIBestWeaponFix", 1)) { - dlog("Applying AI best weapon choice fix.", DL_FIX); + dlogr("Applying AI best weapon choice fix.", DL_FIX); // Fix for the incorrect item being checked for the presence of weapon perks HookCall(0x42954B, ai_best_weapon_hook); // Corrects the calculation of the weapon score to: (maxDmg + minDmg) / 4 @@ -3714,7 +3672,6 @@ void BugFixes::init() { MakeCalls(ai_best_weapon_hack, {0x4294E6, 0x429679}); // Corrects the weapon score multiplier for having perks to 2x (was 5x) SafeWriteBatch(0x15, {0x42955E, 0x4296E7}); // lea eax, [edx*4] > lea eax, [edx] - dlogr(" Done", DL_FIX); } // Fix for the encounter description being displayed in two lines instead of one @@ -3729,29 +3686,25 @@ void BugFixes::init() { MakeCall(0x472F5F, inven_obj_examine_func_hack, 1); // Fix for the exploit that allows you to gain excessive skill points from Tag! perk before leaving the character screen - dlog("Applying fix for Tag! exploit.", DL_FIX); + dlogr("Applying fix for Tag! exploit.", DL_FIX); HookCall(0x43B463, SliderBtn_hook_down); HookCall(0x43D7DD, Add4thTagSkill_hook); - dlogr(" Done", DL_FIX); // Fix for ai_retrieve_object_ engine function not returning the requested object when there are different objects // with the same ID - dlog("Applying ai_retrieve_object engine function fix.", DL_FIX); + dlogr("Applying ai_retrieve_object engine function fix.", DL_FIX); HookCall(0x429D7B, ai_retrieve_object_hook); MakeCall(0x472708, inven_find_id_hack); - dlogr(" Done", DL_FIX); // Fix for the "mood" argument of start_gdialog function being ignored for talking heads if (IniReader::GetConfigInt("Misc", "StartGDialogFix", 0)) { - dlog("Applying start_gdialog argument fix.", DL_FIX); + dlogr("Applying start_gdialog argument fix.", DL_FIX); MakeCall(0x456F08, op_start_gdialog_hack); - dlogr(" Done", DL_FIX); } // Fix for Heave Ho! perk increasing Strength stat above 10 when determining the maximum range of thrown weapons - dlog("Applying Heave Ho! perk fix.", DL_FIX); + dlogr("Applying Heave Ho! perk fix.", DL_FIX); HookCall(0x478AD9, item_w_range_hook); - dlogr(" Done", DL_FIX); // Fix for determine_to_hit_func_ engine function taking distance into account when called from determine_to_hit_no_range_ HookCall(0x4244C3, determine_to_hit_func_hook); @@ -3762,16 +3715,15 @@ void BugFixes::init() { radEffectsMsgNum = IniReader::GetConfigInt("Misc", "RadEffectsRemovalMsg", radEffectsMsgNum); // Display messages about radiation for the active geiger counter if (IniReader::GetConfigInt("Misc", "ActiveGeigerMsgs", 1)) { - dlog("Applying active geiger counter messages patch.", DL_FIX); + dlogr("Applying active geiger counter messages patch.", DL_FIX); SafeWriteBatch(CodeType::JumpZ, {0x42D424, 0x42D444}); // jnz > jz - dlogr(" Done", DL_FIX); } // Display a pop-up message box about death from radiation HookCall(0x42D733, process_rads_hook_msg); //int drugUsePerfFix = IniReader::GetConfigInt("Misc", "AIDrugUsePerfFix", 0); //if (drugUsePerfFix > 0) { - // dlog("Applying AI drug use preference fix.", DL_FIX); + // dlogr("Applying AI drug use preference fix.", DL_FIX); // if (drugUsePerfFix == 1) { // // Fix for AI not taking chem_primary_desire in AI.txt as a preference list when using drugs in the inventory // MakeCall(0x42869D, ai_check_drugs_hack_break); @@ -3781,7 +3733,6 @@ void BugFixes::init() { // // Fix to allow using only the drugs listed in chem_primary_desire and healing drugs (stimpaks and healing powder) // SafeWrite8(0x4286B1, CodeType::JumpZ); // jnz > jz (ai_check_drugs_) // SafeWrite8(0x4286C5, CodeType::JumpNZ); // jz > jnz (ai_check_drugs_) - // dlogr(" Done", DL_FIX); //} // Fix for chem_primary_desire values in party member AI packets not being saved correctly @@ -3798,7 +3749,7 @@ void BugFixes::init() { // called_shot - additional damage when hitting the target // num_attacks - the number of free action points on the first turn only if (IniReader::GetConfigInt("Misc", "AttackComplexFix", 0)) { - dlog("Applying attack_complex arguments fix.", DL_FIX); + dlogr("Applying attack_complex arguments fix.", DL_FIX); HookCall(0x456D4A, op_attack_hook); SafeWrite8(0x456D61, 0x74); // mov [gcsd.free_move], esi SafeWrite8(0x456D92, 0x5C); // mov [gcsd.amount], ebx @@ -3809,7 +3760,6 @@ void BugFixes::init() { SafeWrite16(0x456DA7, 0x8489); // mov [gcsd.changeFlags], 1 > mov [gcsd.changeFlags], eax SafeWrite8(0x456DAB, 0); SafeWrite8(0x456DAE, CodeType::Nop); - dlogr(" Done", DL_FIX); } else { // Fix setting result flags argument for the target SafeWrite16(0x456D95, 0xED85); // cmp eax, ebp > test ebp, ebp @@ -3821,9 +3771,8 @@ void BugFixes::init() { MakeJump(0x422FE5, combat_attack_hack, 1); // Fix for critter_mod_skill taking a negative amount value as a positive - dlog("Applying critter_mod_skill fix.", DL_FIX); + dlogr("Applying critter_mod_skill fix.", DL_FIX); SafeWrite8(0x45B910, 0x7E); // jbe > jle - dlogr(" Done", DL_FIX); // Fix crash when calling use_obj/use_obj_on_obj without using set_self in global scripts // also change the behavior of use_obj_on_obj function @@ -3833,14 +3782,13 @@ void BugFixes::init() { // Fix pickup_obj/drop_obj/use_obj functions, change them to get pointer from script.self instead of script.target // script.target contains an incorrect pointer, which may vary depending on the situations in the game - dlog("Applying pickup_obj/drop_obj/use_obj fix.", DL_FIX); + dlogr("Applying pickup_obj/drop_obj/use_obj fix.", DL_FIX); SafeWriteBatch(0x34, { // script.target > script.self 0x456554, // op_pickup_obj_ 0x456600, // op_drop_obj_ 0x456A6D, // op_use_obj_ 0x456AA4 // op_use_obj_ }); - dlogr(" Done", DL_FIX); // Fix for critters not attacking the player in combat when loading a game saved in combat mode BlockCall(0x48D6F0); // obj_fix_combat_cid_for_dude_ @@ -3855,18 +3803,16 @@ void BugFixes::init() { SafeWrite32(0x4AA56B, 0); // Fix for NPC stuck in a loop of reloading melee/unarmed weapons or solar scorcher when out of ammo - dlog("Applying fix for NPC stuck in a loop of reloading empty weapons.", DL_FIX); + dlogr("Applying fix for NPC stuck in a loop of reloading empty weapons.", DL_FIX); HookCall(0x429A2B, ai_search_inven_weap_hook0); // for melee/unarmed weapons HookCall(0x4299EC, ai_search_inven_weap_hook1); // for the solar scorcher - dlogr(" Done", DL_FIX); // Fix for critters not being healed over time when entering the map if 'dead_bodies_age=No' is set in maps.txt // also fix the zero initialization of a local variable to correct time for removing corpses and blood - dlog("Applying fix for the self-healing of critters when entering the map.", DL_FIX); + dlogr("Applying fix for the self-healing of critters when entering the map.", DL_FIX); MakeCall(0x483356, map_age_dead_critters_hack); SafeWrite32(0x4832A0, 0x9090C189); // mov ecx, eax (keep dead_bodies_age flag) SafeWrite32(0x4832A4, 0x0C245489); // mov [esp + var_30], edx - dlogr(" Done", DL_FIX); // Fix for the removal of party member's corpse when loading the map MakeCall(0x495769, partyFixMultipleMembers_hack, 1); @@ -3914,9 +3860,8 @@ void BugFixes::init() { // Partial fix for incorrect positioning after exiting small/medium locations (e.g. Ghost Farm) //if (IniReader::GetConfigInt("Misc", "SmallLocExitFix", 1)) { - dlog("Applying fix for incorrect positioning after exiting small/medium locations.", DL_FIX); + dlogr("Applying fix for incorrect positioning after exiting small/medium locations.", DL_FIX); MakeJump(0x4C5A41, wmTeleportToArea_hack); - dlogr(" Done", DL_FIX); //} // Fix for Scout perk being taken into account when setting the visibility of locations with mark_area_known function @@ -3930,9 +3875,8 @@ void BugFixes::init() { // Fix to prevent using number keys to enter unvisited areas on a town map if (IniReader::GetConfigInt("Misc", "TownMapHotkeysFix", 1)) { - dlog("Applying town map hotkeys patch.", DL_FIX); + dlogr("Applying town map hotkeys patch.", DL_FIX); MakeCall(0x4C495A, wmTownMapFunc_hack, 1); - dlogr(" Done", DL_FIX); } // Fix for combat not ending automatically when there are no hostile critters @@ -3942,9 +3886,8 @@ void BugFixes::init() { // Fix for the car being lost when entering a location via the Town/World button and then leaving on foot // (sets GVAR_CAR_PLACED_TILE (633) to -1 on exit to the world map) if (IniReader::GetConfigInt("Misc", "CarPlacedTileFix", 1)) { - dlog("Applying car placed tile fix.", DL_FIX); + dlogr("Applying car placed tile fix.", DL_FIX); MakeCall(0x4C2367, wmInterfaceInit_hack); - dlogr(" Done", DL_FIX); } // Place the player on a nearby empty tile if the entrance tile is blocked by another object when entering a map @@ -3960,10 +3903,9 @@ void BugFixes::init() { // Fix to prevent corpses from blocking line of fire //if (IniReader::GetConfigInt("Misc", "CorpseLineOfFireFix", 1)) { - dlog("Applying fix for corpses blocking line of fire.", DL_FIX); + dlogr("Applying fix for corpses blocking line of fire.", DL_FIX); MakeJump(0x48B994, obj_shoot_blocking_at_hack0); MakeJump(0x48BA04, obj_shoot_blocking_at_hack1); - dlogr(" Done", DL_FIX); //} // Fix for party member's equipped weapon being placed in the incorrect item slot after leveling up diff --git a/sfall/Modules/BurstMods.cpp b/sfall/Modules/BurstMods.cpp index 436bba54a..0f70466dd 100644 --- a/sfall/Modules/BurstMods.cpp +++ b/sfall/Modules/BurstMods.cpp @@ -67,7 +67,7 @@ static void __declspec(naked) compute_spray_rounds_distribution() { void BurstMods::init() { //if (IniReader::GetConfigInt("Misc", "ComputeSprayMod", 0)) { - dlog("Applying ComputeSpray settings to burst attacks.", DL_INIT); + dlogr("Applying ComputeSpray settings to burst attacks.", DL_INIT); compute_spray_center_mult = IniReader::GetConfigInt("Misc", "ComputeSpray_CenterMult", 1); compute_spray_center_div = IniReader::GetConfigInt("Misc", "ComputeSpray_CenterDiv", 3); if (compute_spray_center_div < 1) { @@ -85,7 +85,6 @@ void BurstMods::init() { compute_spray_target_mult = compute_spray_target_div; } MakeJump(0x4234F1, compute_spray_rounds_distribution); - dlogr(" Done", DL_INIT); //} } diff --git a/sfall/Modules/Combat.cpp b/sfall/Modules/Combat.cpp index 6a88f2389..84035e526 100644 --- a/sfall/Modules/Combat.cpp +++ b/sfall/Modules/Combat.cpp @@ -537,10 +537,9 @@ static void __declspec(naked) apply_damage_hack() { } static void CombatProcPatch() { - dlog("Applying Ray's combat_p_proc patch.", DL_INIT); + dlogr("Applying Ray's combat_p_proc patch.", DL_INIT); MakeCall(0x424DD9, apply_damage_hack); SafeWrite16(0x424DC6, 0x9090); - dlogr(" Done", DL_INIT); } static void ResetOnGameLoad() { diff --git a/sfall/Modules/Criticals.cpp b/sfall/Modules/Criticals.cpp index eb0c982da..447440469 100644 --- a/sfall/Modules/Criticals.cpp +++ b/sfall/Modules/Criticals.cpp @@ -78,7 +78,7 @@ void Criticals::ResetCriticalTable(DWORD critter, DWORD bodypart, DWORD slot, DW static int CritTableLoad() { if (mode == 1) { - dlogr("Setting up critical hit table using CriticalOverrides.ini (old fmt)", DL_CRITICALS); + dlogr("Setting up critical hit table using CriticalOverrides.ini (old fmt).", DL_CRITICALS); if (GetFileAttributes(critTableFile.c_str()) == INVALID_FILE_ATTRIBUTES) return 1; char section[16]; for (DWORD critter = 0; critter < 20; critter++) { @@ -108,7 +108,7 @@ static int CritTableLoad() { memcpy(&baseCritTable[38], fo::var::pc_crit_succ_eff, 6 * 9 * sizeof(fo::CritInfo)); // PC crit table if (mode == 3) { - dlogr(" and CriticalOverrides.ini (new fmt)", DL_CRITICALS); + dlogr(" and CriticalOverrides.ini (new fmt).", DL_CRITICALS); if (GetFileAttributes(critTableFile.c_str()) == INVALID_FILE_ATTRIBUTES) return 1; char buf[32], buf2[32], buf3[32]; for (int critter = 0; critter < Criticals::critTableCount; critter++) { @@ -132,7 +132,7 @@ static int CritTableLoad() { } } } else { - dlog("\n", DL_CRITICALS); + dlogr(".", DL_CRITICALS); } } return 0; @@ -305,10 +305,9 @@ static void CriticalTableOverride() { static void RemoveCriticalTimeLimitsPatch() { if (IniReader::GetConfigInt("Misc", "RemoveCriticalTimelimits", 0)) { - dlog("Removing critical time limits.", DL_INIT); + dlogr("Removing critical time limits.", DL_INIT); SafeWrite8(0x424118, CodeType::JumpShort); // jump to 0x424131 SafeWriteBatch(0x9090, {0x4A3052, 0x4A3093}); - dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/DamageMod.cpp b/sfall/Modules/DamageMod.cpp index b06be6c5e..16cde82ad 100644 --- a/sfall/Modules/DamageMod.cpp +++ b/sfall/Modules/DamageMod.cpp @@ -338,7 +338,7 @@ void DamageMod::init() { displayBonusDamage = IniReader::GetConfigInt("Misc", "DisplayBonusDamage", 0) != 0; if (bonusHtHDamageFix) { - dlog("Applying Bonus HtH Damage Perk fix.", DL_INIT); + dlogr("Applying Bonus HtH Damage Perk fix.", DL_INIT); // Subtract damage from perk bonus (vanilla displaying) if (!displayBonusDamage) { HookCalls(MeleeDmgDisplayPrintFix_hook, { @@ -352,16 +352,14 @@ void DamageMod::init() { } //MakeCall(0x478492, HtHDamageFix1a_hack); // Unarmed (item_w_damage_) HookCall(0x47854C, HtHDamageFix1b_hook); // MeleeWeap (item_w_damage_) - dlogr(" Done", DL_INIT); } if (displayBonusDamage) { - dlog("Applying Display Bonus Damage patch.", DL_INIT); + dlogr("Applying Display Bonus Damage patch.", DL_INIT); HookCall(0x4722DD, DisplayBonusRangedDmg_hook); // display_stats_ if (bonusHtHDamageFix) { HookCall(0x472309, DisplayBonusHtHDmg1_hook); // MeleeWeap (display_stats_) } - dlogr(" Done", DL_INIT); } // Display the actual damage values of unarmed attacks (display_stats_ hacks) diff --git a/sfall/Modules/DebugEditor.cpp b/sfall/Modules/DebugEditor.cpp index 8c734808f..0583e5434 100644 --- a/sfall/Modules/DebugEditor.cpp +++ b/sfall/Modules/DebugEditor.cpp @@ -426,7 +426,7 @@ static const DWORD addrNewLineChar[] = { static void DebugModePatch() { int dbgMode = IniReader::GetIntDefaultConfig("Debugging", "DebugMode", 0); if (dbgMode > 0) { - dlog("Applying debugmode patch.", DL_INIT); + dlogr("Applying debugmode patch.", DL_INIT); // If the player is using an exe with the debug patch already applied, just skip this block without erroring if (*((DWORD*)0x444A64) != 0x082327E8) { SafeWrite32(0x444A64, 0x082327E8); // call debug_register_env_ @@ -481,15 +481,13 @@ static void DebugModePatch() { if (dbgMode != 1) { MoveDebugString((char*)0x500A9B); // "computing attack..." } - dlogr(" Done", DL_INIT); } } static void DontDeleteProtosPatch() { if (IniReader::GetIntDefaultConfig("Debugging", "DontDeleteProtos", 0)) { - dlog("Applying permanent protos patch.", DL_INIT); + dlogr("Applying permanent protos patch.", DL_INIT); SafeWrite8(0x48007E, CodeType::JumpShort); - dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/Drugs.cpp b/sfall/Modules/Drugs.cpp index 1005f3d09..d5beabd76 100644 --- a/sfall/Modules/Drugs.cpp +++ b/sfall/Modules/Drugs.cpp @@ -344,7 +344,7 @@ void Drugs::init() { LoadGameHook::OnGameReset() += ResetDrugs; } } - dlog_f(" (%d/%d drugs) Done\n", DL_INIT, drugsCount, count); + dlog_f(" (%d/%d drugs)\n", DL_INIT, drugsCount, count); } } diff --git a/sfall/Modules/Elevators.cpp b/sfall/Modules/Elevators.cpp index 689f0da10..8c1fbdb52 100644 --- a/sfall/Modules/Elevators.cpp +++ b/sfall/Modules/Elevators.cpp @@ -161,10 +161,9 @@ static void ElevatorsInit() { void Elevators::init() { auto elevPath = IniReader::GetConfigString("Misc", "ElevatorsFile", "", MAX_PATH); if (!elevPath.empty()) { - dlog("Applying elevator patch.", DL_INIT); + dlogr("Applying elevator patch.", DL_INIT); ElevatorsInit(); LoadElevators(elevPath.insert(0, ".\\").c_str()); - dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/Explosions.cpp b/sfall/Modules/Explosions.cpp index 6c5b4af56..95850b4b1 100644 --- a/sfall/Modules/Explosions.cpp +++ b/sfall/Modules/Explosions.cpp @@ -483,11 +483,10 @@ void Explosions::init() { lightingEnabled = IniReader::GetConfigInt("Misc", "ExplosionsEmitLight", 0) != 0; if (lightingEnabled) { - dlog("Applying Explosion changes.", DL_INIT); + dlogr("Applying Explosion changes.", DL_INIT); MakeJump(0x4118E1, ranged_attack_lighting_fix); MakeJump(0x410A4A, fire_dance_lighting_fix1); MakeJump(0x415A3F, anim_set_check_light_fix); // this allows to change light intensity - dlogr(" Done", DL_INIT); } // initialize explosives diff --git a/sfall/Modules/ExtraSaveSlots.cpp b/sfall/Modules/ExtraSaveSlots.cpp index ff10a6cb8..a7f88027f 100644 --- a/sfall/Modules/ExtraSaveSlots.cpp +++ b/sfall/Modules/ExtraSaveSlots.cpp @@ -30,7 +30,7 @@ static long LSPageOffset = 0; static long LSButtDN = 0; static BYTE* SaveLoadSurface = nullptr; -static const char* filename = "%s\\savegame\\slotdat.ini"; +static const char* slotFile = "%s\\savegame\\slotdat.ini"; long ExtraSaveSlots::GetSaveSlot() { return LSPageOffset + fo::var::slot_cursor; @@ -45,7 +45,7 @@ void ExtraSaveSlots::SetSaveSlot(long page, long slot) { static long save_page_offsets() { char SavePath[MAX_PATH], buffer[6]; - sprintf_s(SavePath, MAX_PATH, filename, fo::var::patches); + sprintf_s(SavePath, MAX_PATH, slotFile, fo::var::patches); _itoa_s(fo::var::slot_cursor, buffer, 10); WritePrivateProfileStringA("POSITION", "ListNum", buffer, SavePath); @@ -60,7 +60,7 @@ static long save_page_offsets() { static void LoadPageOffsets() { char LoadPath[MAX_PATH]; - sprintf_s(LoadPath, MAX_PATH, filename, fo::var::patches); + sprintf_s(LoadPath, MAX_PATH, slotFile, fo::var::patches); fo::var::slot_cursor = IniReader::GetInt("POSITION", "ListNum", 0, LoadPath); if (fo::var::slot_cursor > 9) { @@ -534,14 +534,13 @@ void ExtraSaveSlots::SetQuickSaveSlot(long page, long slot, long check) { void ExtraSaveSlots::init() { bool extraSaveSlots = (IniReader::GetConfigInt("Misc", "ExtraSaveSlots", 0) != 0); if (extraSaveSlots) { - dlog("Applying extra save slots patch.", DL_INIT); + dlogr("Applying extra save slots patch.", DL_INIT); EnableSuperSaving(); - dlogr(" Done", DL_INIT); } quickSavePageCount = IniReader::GetConfigInt("Misc", "AutoQuickSave", 0); if (quickSavePageCount > 0) { - dlog("Applying auto quick save patch.", DL_INIT); + dlogr("Applying auto quick save patch.", DL_INIT); if (quickSavePageCount > 10) quickSavePageCount = 10; quickSavePage = IniReader::GetConfigInt("Misc", "AutoQuickSavePage", 1); @@ -553,7 +552,6 @@ void ExtraSaveSlots::init() { } MakeJump(0x47B984, SaveGame_hack0); MakeCall(0x47B923, SaveGame_hack1, 1); - dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/HeroAppearance.cpp b/sfall/Modules/HeroAppearance.cpp index 513b4857c..e2b59fb51 100644 --- a/sfall/Modules/HeroAppearance.cpp +++ b/sfall/Modules/HeroAppearance.cpp @@ -1537,7 +1537,7 @@ static void HeroAppearanceModExit() { void HeroAppearance::init() { int heroAppearanceMod = IniReader::GetConfigInt("Misc", "EnableHeroAppearanceMod", 0); if (heroAppearanceMod > 0) { - dlog("Setting up Appearance Char Screen buttons.", DL_INIT); + dlogr("Setting up Appearance Char Screen buttons.", DL_INIT); EnableHeroAppearanceMod(); // Hero FrmID fix for obj_art_fid/art_change_fid_num script functions @@ -1551,7 +1551,6 @@ void HeroAppearance::init() { LoadHeroAppearance(); }; Inventory::OnAdjustFid() += AdjustHeroArmorArt; - dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/HeroAppearance.h b/sfall/Modules/HeroAppearance.h index 992777b87..103be01f6 100644 --- a/sfall/Modules/HeroAppearance.h +++ b/sfall/Modules/HeroAppearance.h @@ -36,8 +36,8 @@ class HeroAppearance : public Module { void __stdcall HeroSelectWindow(int raceStyleFlag); void __stdcall SetHeroStyle(int newStyleVal); void __stdcall SetHeroRace(int newRaceVal); -void __stdcall LoadHeroAppearance(void); -void __stdcall SetNewCharAppearanceGlobals(void); +void __stdcall LoadHeroAppearance(); +void __stdcall SetNewCharAppearanceGlobals(); void __stdcall RefreshPCArt(); diff --git a/sfall/Modules/HookScripts/Common.cpp b/sfall/Modules/HookScripts/Common.cpp index b504af5d3..404b96f62 100644 --- a/sfall/Modules/HookScripts/Common.cpp +++ b/sfall/Modules/HookScripts/Common.cpp @@ -113,14 +113,14 @@ void __stdcall RunHookScript(DWORD hook) { if (!hooks[hook].empty()) { if (callDepth > 1) { if (CheckRecursiveHooks(hook) || callDepth > 8) { - fo::func::debug_printf("\n[SFALL] The hook ID: %d cannot be executed.", hook); - dlog_f("The hook %d cannot be executed due to exceeding depth limit or disallowed recursive calls\n", DL_MAIN, hook); + fo::func::debug_printf("\n[SFALL] The hook ID %d cannot be executed.", hook); + dlog_f("The hook ID %d cannot be executed due to exceeding depth limit or disallowed recursive calls\n", DL_MAIN, hook); return; } } currentRunHook = hook; size_t hooksCount = hooks[hook].size(); - dlog_f("Running hook %d, which has %0d entries attached, depth: %d\n", DL_HOOK, hook, hooksCount, callDepth); + dlog_f("Running hook ID %d, which has %0d entries attached, depth: %d\n", DL_HOOK, hook, hooksCount, callDepth); for (int i = hooksCount - 1; i >= 0; i--) { RunSpecificHookScript(&hooks[hook][i]); @@ -138,7 +138,7 @@ void __stdcall RunHookScript(DWORD hook) { } void __stdcall EndHook() { - devlog_f("End running hook %d, current depth: %d\n", DL_HOOK, currentRunHook, callDepth); + devlog_f("End running hook ID %d, current depth: %d\n", DL_HOOK, currentRunHook, callDepth); callDepth--; if (callDepth) { diff --git a/sfall/Modules/Input.cpp b/sfall/Modules/Input.cpp index f4346d15a..386088d18 100644 --- a/sfall/Modules/Input.cpp +++ b/sfall/Modules/Input.cpp @@ -29,10 +29,9 @@ namespace sfall void Input::init() { //if (IniReader::GetConfigInt("Input", "Enable", 0)) { - dlog("Applying input patch.", DL_INIT); + dlogr("Applying input patch.", DL_INIT); SafeWriteStr(0x50FB70, "ddraw.dll"); ::sfall::availableGlobalScriptTypes |= 1; - dlogr(" Done", DL_INIT); //} } diff --git a/sfall/Modules/Interface.cpp b/sfall/Modules/Interface.cpp index 64e317e7c..ca23329c5 100644 --- a/sfall/Modules/Interface.cpp +++ b/sfall/Modules/Interface.cpp @@ -419,7 +419,7 @@ static void __declspec(naked) wmTownMapInit_hook() { static void WorldmapViewportPatch() { if (Graphics::GetGameHeightRes() < WMAP_WIN_HEIGHT || Graphics::GetGameWidthRes() < WMAP_WIN_WIDTH) return; if (!fo::func::db_access("art\\intrface\\worldmap.frm")) return; - dlog("Applying expanded world map interface patch.", DL_INIT); + dlogr("Applying expanded world map interface patch.", DL_INIT); wmapWinWidth = WMAP_WIN_WIDTH; wmapWinHeight = WMAP_WIN_HEIGHT; @@ -531,7 +531,6 @@ static void WorldmapViewportPatch() { // Town map frm images (wmTownMapRefresh_) SafeWrite32(0x4C4BE4, (WMAP_WIN_WIDTH * 21) + 22); // start offset for town map image (13462) - dlogr(" Done", DL_INIT); } ///////////////////////// FALLOUT 1 WORLD MAP FEATURES ///////////////////////// @@ -833,9 +832,8 @@ static void __declspec(naked) wmTownMapInit_hack() { static void WorldMapInterfacePatch() { if (IniReader::GetConfigInt("Misc", "WorldMapFontPatch", 0)) { - dlog("Applying world map font patch.", DL_INIT); + dlogr("Applying world map font patch.", DL_INIT); HookCall(0x4C2343, wmInterfaceInit_text_font_hook); - dlogr(" Done", DL_INIT); } // Add missing sounds for the buttons on the world map interface (wmInterfaceInit_) @@ -856,20 +854,18 @@ static void WorldMapInterfacePatch() { SafeWrite8(0x4C2D04, 0x46); // dec esi > inc esi //if (IniReader::GetConfigInt("Misc", "WorldMapCitiesListFix", 0)) { - dlog("Applying world map cities list patch.", DL_INIT); + dlogr("Applying world map cities list patch.", DL_INIT); HookCalls(ScrollCityListFix, {0x4C04B9, 0x4C04C8, 0x4C4A34, 0x4C4A3D}); - dlogr(" Done", DL_INIT); //} DWORD wmSlots = IniReader::GetConfigInt("Misc", "WorldMapSlots", 0); if (wmSlots && wmSlots < 128) { - dlog("Applying world map slots patch.", DL_INIT); + dlogr("Applying world map slots patch.", DL_INIT); if (wmSlots < 7) wmSlots = 7; mapSlotsScrollMax = (wmSlots - 7) * 27; // height value after which scrolling is not possible mapSlotsScrollLimit = wmSlots * 27; SafeWrite32(0x4C21FD, 189); // 27 * 7 SafeWrite32(0x4C21F1, (DWORD)&mapSlotsScrollLimit); - dlogr(" Done", DL_INIT); } if (HRP::Setting::IsEnabled() || HRP::Setting::VersionIsValid) { // was available only for 4.1.8? @@ -880,7 +876,7 @@ static void WorldMapInterfacePatch() { // Fallout 1 features, travel markers and displaying terrain types or town titles if (IniReader::GetConfigInt("Interface", "WorldMapTravelMarkers", 0)) { - dlog("Applying world map travel markers patch.", DL_INIT); + dlogr("Applying world map travel markers patch.", DL_INIT); int color = IniReader::GetConfigInt("Interface", "TravelMarkerColor", 134); // color index in palette: R = 224, G = 0, B = 0 if (color > 228) color = 228; else if (color < 1) color = 1; // no palette animation colors @@ -911,7 +907,6 @@ static void WorldMapInterfacePatch() { LoadGameHook::OnGameReset() += []() { dots.clear(); }; - dlogr(" Done", DL_INIT); } showTerrainType = (IniReader::GetConfigInt("Interface", "WorldMapTerrainInfo", 0) != 0); HookCall(0x4C3C7E, wmInterfaceRefresh_hook); // when calling wmDrawCursorStopped_ @@ -952,14 +947,12 @@ static void __declspec(naked) intface_rotate_numbers_hack() { static void SpeedInterfaceCounterAnimsPatch() { switch (IniReader::GetConfigInt("Misc", "SpeedInterfaceCounterAnims", 0)) { case 1: - dlog("Applying SpeedInterfaceCounterAnims patch.", DL_INIT); + dlogr("Applying SpeedInterfaceCounterAnims patch.", DL_INIT); MakeJump(0x460BA1, intface_rotate_numbers_hack); - dlogr(" Done", DL_INIT); break; case 2: - dlog("Applying SpeedInterfaceCounterAnims patch (Instant).", DL_INIT); + dlogr("Applying SpeedInterfaceCounterAnims patch (Instant).", DL_INIT); SafeWrite32(0x460BB6, 0xDB319090); // xor ebx, ebx - dlogr(" Done", DL_INIT); break; } } @@ -1028,8 +1021,6 @@ static void __declspec(naked) display_body_hook() { } static void InterfaceWindowPatch() { - dlog("Applying flags patch for interface windows.", DL_INIT); - // Remove MoveOnTop flag for interfaces SafeWrite8(0x46ECE9, (*(BYTE*)0x46ECE9) ^ fo::WinFlags::MoveOnTop); // Player Inventory/Loot/UseOn SafeWrite8(0x41B966, (*(BYTE*)0x41B966) ^ fo::WinFlags::MoveOnTop); // Automap @@ -1044,8 +1035,6 @@ static void InterfaceWindowPatch() { // Remove OwnerFlag and Transparent flags SafeWrite8(0x42F869, (*(BYTE*)0x42F869) ^ (fo::WinFlags::Transparent | fo::WinFlags::OwnerFlag)); // addWindow_ - dlogr(" Done", DL_INIT); - // Cosmetic fix for the background image of the character portrait on the player's inventory screen HookCall(0x47093C, display_body_hook); BYTE code[11] = { diff --git a/sfall/Modules/Karma.cpp b/sfall/Modules/Karma.cpp index 3b27947df..8513e10f2 100644 --- a/sfall/Modules/Karma.cpp +++ b/sfall/Modules/Karma.cpp @@ -80,11 +80,10 @@ void Karma::DisplayKarma(int value) { static void ApplyDisplayKarmaChangesPatch() { displayKarmaChanges = IniReader::GetConfigInt("Misc", "DisplayKarmaChanges", 0) != 0; if (displayKarmaChanges) { - dlog("Applying display karma changes patch.", DL_INIT); + dlogr("Applying display karma changes patch.", DL_INIT); karmaGainMsg = Translate::Get("sfall", "KarmaGain", "You gained %d karma."); karmaLossMsg = Translate::Get("sfall", "KarmaLoss", "You lost %d karma."); HookScripts::InjectingHook(HOOK_SETGLOBALVAR); - dlogr(" Done", DL_INIT); } } @@ -92,7 +91,7 @@ static void ApplyKarmaFRMsPatch() { auto karmaFrmList = IniReader::GetConfigList("Misc", "KarmaFRMs", "", 512); size_t countFrm = karmaFrmList.size(); if (countFrm) { - dlog("Applying karma FRM patch.", DL_INIT); + dlogr("Applying karma FRM patch.", DL_INIT); auto karmaPointsList = IniReader::GetConfigList("Misc", "KarmaPoints", "", 512); karmaFrms.resize(countFrm); @@ -104,8 +103,6 @@ static void ApplyKarmaFRMsPatch() { : INT_MAX; } HookCall(0x4367A9, DrawInfoWin_hook); - - dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/KillCounter.cpp b/sfall/Modules/KillCounter.cpp index 608cef14d..d96fcc58a 100644 --- a/sfall/Modules/KillCounter.cpp +++ b/sfall/Modules/KillCounter.cpp @@ -74,9 +74,8 @@ bool KillCounter::UsingExtraKillTypes() { void KillCounter::init() { if (IniReader::GetConfigInt("Misc", "ExtraKillTypes", 0)) { - dlog("Applying extra kill types patch.", DL_INIT); + dlogr("Applying extra kill types patch.", DL_INIT); KillCounterInit(); - dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/LoadOrder.cpp b/sfall/Modules/LoadOrder.cpp index cc5c41823..c2f4bec53 100644 --- a/sfall/Modules/LoadOrder.cpp +++ b/sfall/Modules/LoadOrder.cpp @@ -321,10 +321,9 @@ static void GetExtraPatches() { static void MultiPatchesPatch() { //if (IniReader::GetConfigInt("Misc", "MultiPatches", 0)) { - dlog("Applying load multiple patches patch.", DL_INIT); + dlogr("Applying load multiple patches patch.", DL_INIT); SafeWrite8(0x444354, CodeType::Nop); // Change step from 2 to 1 SafeWrite8(0x44435C, 0xC4); // Disable check - dlogr(" Done", DL_INIT); //} } @@ -564,19 +563,18 @@ void LoadOrder::init() { MultiPatchesPatch(); //if (IniReader::GetConfigInt("Misc", "DataLoadOrderPatch", 1)) { - dlog("Applying data load order patch.", DL_INIT); + dlogr("Applying data load order patch.", DL_INIT); MakeCall(0x444259, game_init_databases_hack1); MakeCall(0x4442F1, game_init_databases_hack2); HookCall(0x44436D, game_init_databases_hook); SafeWrite8(0x4DFAEC, 0x1D); // error correction (ecx > ebx) - dlogr(" Done", DL_INIT); //} else /*if (!patchFiles.empty())*/ { // HookCall(0x44436D, game_init_databases_hook1); //} femaleMsgs = IniReader::GetConfigInt("Misc", "FemaleDialogMsgs", 0); if (femaleMsgs) { - dlog("Applying alternative female dialog files patch.", DL_INIT); + dlogr("Applying alternative female dialog files patch.", DL_INIT); MakeJump(0x4A6BCD, scr_get_dialog_msg_file_hack1); MakeJump(0x4A6BF5, scr_get_dialog_msg_file_hack2); LoadGameHook::OnAfterGameStarted() += CheckPlayerGender; @@ -584,7 +582,6 @@ void LoadOrder::init() { MakeCall(0x480A95, gnw_main_hack); // before new game start from main menu. TODO: need moved to address 0x480A9A (it busy in movies.cpp) LoadGameHook::OnGameExit() += PlayerGenderCutsRestore; } - dlogr(" Done", DL_INIT); } // Redefined behavior for replacing art aliases for critters @@ -595,14 +592,13 @@ void LoadOrder::init() { MakeCall(0x419560, art_get_name_hack); } - dlog("Applying party member protos save/load patch.", DL_INIT); + dlogr("Applying party member protos save/load patch.", DL_INIT); savPrototypes.reserve(25); HookCall(0x4A1CF2, proto_load_pid_hook); HookCall(0x4A1BEE, proto_save_pid_hook); MakeCall(0x47F5A5, GameMap2Slot_hack); // save game MakeCall(0x47FB80, SlotMap2Game_hack); // load game MakeCall(0x47FBBF, SlotMap2Game_hack_attr, 1); - dlogr(" Done", DL_INIT); // Load fonts based on the game language HookCalls(load_font_hook, { diff --git a/sfall/Modules/Message.cpp b/sfall/Modules/Message.cpp index d1c0d753c..a5fd2dfaf 100644 --- a/sfall/Modules/Message.cpp +++ b/sfall/Modules/Message.cpp @@ -238,10 +238,9 @@ void Message::init() { msgFileList = IniReader::GetConfigList("Misc", "ExtraGameMsgFileList", "", 512); if (IniReader::GetConfigInt("Misc", "DialogGenderWords", 0)) { - dlog("Applying dialog gender words patch.", DL_INIT); + dlogr("Applying dialog gender words patch.", DL_INIT); HookCall(0x4A6CEE, scr_get_msg_str_speech_hook); SafeWrite16(0x484C62, 0x9090); // message_search_ - dlogr(" Done", DL_INIT); } LoadGameHook::OnGameInit() += FallbackEnglishLoadMsgFiles; diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index 3eec786ac..34769a4e2 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -478,18 +478,17 @@ static void __declspec(naked) text_object_create_hack() { static void AdditionalWeaponAnimsPatch() { if (IniReader::GetConfigInt("Misc", "AdditionalWeaponAnims", 0)) { - dlog("Applying additional weapon animations patch.", DL_INIT); + dlogr("Applying additional weapon animations patch.", DL_INIT); SafeWrite8(0x419320, 18); // art_get_code_ HookCalls(WeaponAnimHook, { 0x451648, 0x451671, // gsnd_build_character_sfx_name_ 0x4194CC // art_get_name_ }); - dlogr(" Done", DL_INIT); } } static void SkilldexImagesPatch() { - dlog("Checking for changed skilldex images.", DL_INIT); + dlogr("Checking for changed skilldex images.", DL_INIT); long tmp = IniReader::GetConfigInt("Misc", "Lockpick", 293); if (tmp != 293) SafeWrite32(0x518D54, tmp); tmp = IniReader::GetConfigInt("Misc", "Steal", 293); @@ -504,7 +503,6 @@ static void SkilldexImagesPatch() { if (tmp != 293) SafeWrite32(0x518D60, tmp); tmp = IniReader::GetConfigInt("Misc", "Repair", 293); if (tmp != 293) SafeWrite32(0x518D64, tmp); - dlogr(" Done", DL_INIT); } static void ScienceOnCrittersPatch() { @@ -525,19 +523,18 @@ static void BoostScriptDialogLimitPatch() { if (IniReader::GetConfigInt("Misc", "BoostScriptDialogLimit", 0)) { const int scriptDialogCount = 10000; - dlog("Applying script dialog limit patch.", DL_INIT); + dlogr("Applying script dialog limit patch.", DL_INIT); scriptDialog = new int[scriptDialogCount * 2]; // Because the msg structure is 8 bytes, not 4. SafeWrite32(0x4A50E3, scriptDialogCount); // scr_init SafeWrite32(0x4A519F, scriptDialogCount); // scr_game_init SafeWrite32(0x4A534F, scriptDialogCount * 8); // scr_message_free SafeWriteBatch((DWORD)scriptDialog, script_dialog_msgs); // scr_get_dialog_msg_file - dlogr(" Done", DL_INIT); } } static void NumbersInDialoguePatch() { if (IniReader::GetConfigInt("Misc", "NumbersInDialogue", 0)) { - dlog("Applying numbers in dialogue patch.", DL_INIT); + dlogr("Applying numbers in dialogue patch.", DL_INIT); SafeWrite32(0x502C32, 0x2000202E); SafeWrite8(0x446F3B, 0x35); SafeWrite32(0x5029E2, 0x7325202E); @@ -546,7 +543,6 @@ static void NumbersInDialoguePatch() { SafeWrite32(0x446FE0, 0x2824448B); // mov eax, [esp+0x28] SafeWrite8(0x446FE4, 0x50); // push eax MakeJump(0x4458F5, gdAddOptionStr_hack); - dlogr(" Done", DL_INIT); } } @@ -561,35 +557,32 @@ static void InstantWeaponEquipPatch() { if (IniReader::GetConfigInt("Misc", "InstantWeaponEquip", 0)) { //Skip weapon equip/unequip animations - dlog("Applying instant weapon equip patch.", DL_INIT); + dlogr("Applying instant weapon equip patch.", DL_INIT); SafeWriteBatch(CodeType::JumpShort, PutAwayWeapon); // jmps BlockCall(0x472AD5); // BlockCall(0x472AE0); // invenUnwieldFunc_ BlockCall(0x472AF0); // MakeJump(0x415238, register_object_take_out_hack); - dlogr(" Done", DL_INIT); } } static void DontTurnOffSneakIfYouRunPatch() { if (IniReader::GetConfigInt("Misc", "DontTurnOffSneakIfYouRun", 0)) { - dlog("Applying DontTurnOffSneakIfYouRun patch.", DL_INIT); + dlogr("Applying DontTurnOffSneakIfYouRun patch.", DL_INIT); SafeWrite8(0x418135, CodeType::JumpShort); - dlogr(" Done", DL_INIT); } } static void PlayIdleAnimOnReloadPatch() { if (IniReader::GetConfigInt("Misc", "PlayIdleAnimOnReload", 0)) { - dlog("Applying idle anim on reload patch.", DL_INIT); + dlogr("Applying idle anim on reload patch.", DL_INIT); HookCall(0x460B8C, intface_item_reload_hook); - dlogr(" Done", DL_INIT); } } static void MotionScannerFlagsPatch() { if (long flags = IniReader::GetConfigInt("Misc", "MotionScannerFlags", 1)) { - dlog("Applying MotionScannerFlags patch.", DL_INIT); + dlogr("Applying MotionScannerFlags patch.", DL_INIT); if (flags & 1) MakeJump(0x41BBE9, automap_hack); if (flags & 2) { // automap_ @@ -598,7 +591,6 @@ static void MotionScannerFlagsPatch() { // item_m_use_charged_item_ SafeWrite8(0x4794B3, 0x5E); // jbe short 0x479512 } - dlogr(" Done", DL_INIT); } } @@ -618,7 +610,7 @@ static void EncounterTableSizePatch() { int tableSize = IniReader::GetConfigInt("Misc", "EncounterTableSize", 0); if (tableSize > 40) { - dlog("Applying EncounterTableSize patch.", DL_INIT); + dlogr("Applying EncounterTableSize patch.", DL_INIT); if (tableSize > 50) { if (tableSize > 100) tableSize = 100; // Increase the count of message lines from 50 to 100 for the encounter tables in worldmap.msg @@ -627,24 +619,21 @@ static void EncounterTableSizePatch() { SafeWrite8(0x4BDB17, (BYTE)tableSize); DWORD nsize = (tableSize + 1) * 180 + 0x50; SafeWriteBatch(nsize, EncounterTableSize); - dlogr(" Done", DL_INIT); } } static void DisablePipboyAlarmPatch() { if (IniReader::GetConfigInt("Misc", "DisablePipboyAlarm", 0)) { - dlog("Applying Disable Pip-Boy alarm button patch.", DL_INIT); + dlogr("Applying Disable Pip-Boy alarm button patch.", DL_INIT); SafeWrite8(0x499518, CodeType::Ret); SafeWrite8(0x443601, 0); - dlogr(" Done", DL_INIT); } } static void ObjCanSeeShootThroughPatch() { if (IniReader::GetConfigInt("Misc", "ObjCanSeeObj_ShootThru_Fix", 0)) { - dlog("Applying obj_can_see_obj fix for seeing through critters and ShootThru objects.", DL_INIT); + dlogr("Applying obj_can_see_obj fix for seeing through critters and ShootThru objects.", DL_INIT); HookCall(0x456BC6, op_obj_can_see_obj_hook); - dlogr(" Done", DL_INIT); } } @@ -662,26 +651,23 @@ static void OverrideMusicDirPatch() { static void DialogueFix() { if (IniReader::GetConfigInt("Misc", "DialogueFix", 1)) { - dlog("Applying dialogue patch.", DL_INIT); + dlogr("Applying dialogue patch.", DL_INIT); SafeWrite8(0x446848, 0x31); - dlogr(" Done", DL_INIT); } } static void AlwaysReloadMsgs() { if (IniReader::GetConfigInt("Misc", "AlwaysReloadMsgs", 0)) { - dlog("Applying always reload messages patch.", DL_INIT); + dlogr("Applying always reload messages patch.", DL_INIT); SafeWrite8(0x4A6B8D, 0); // jnz $+6 - dlogr(" Done", DL_INIT); } } static void MusicInDialoguePatch() { if (IniReader::GetConfigInt("Misc", "EnableMusicInDialogue", 0)) { - dlog("Applying music in dialogue patch.", DL_INIT); + dlogr("Applying music in dialogue patch.", DL_INIT); SafeWrite16(0x44525A, 0x9090); //BlockCall(0x450627); - dlogr(" Done", DL_INIT); } } @@ -709,20 +695,18 @@ static void DisableHorriganPatch() { static void DisplaySecondWeaponRangePatch() { // Display the range of the secondary attack mode in the inventory when you switch weapon modes in active item slots //if (IniReader::GetConfigInt("Misc", "DisplaySecondWeaponRange", 1)) { - dlog("Applying display second weapon range patch.", DL_INIT); + dlogr("Applying display second weapon range patch.", DL_INIT); HookCall(0x472201, display_stats_hook); - dlogr(" Done", DL_INIT); //} } static void KeepSelectModePatch() { //if (IniReader::GetConfigInt("Misc", "KeepWeaponSelectMode", 1)) { - dlog("Applying keep selected attack mode patch.", DL_INIT); + dlogr("Applying keep selected attack mode patch.", DL_INIT); MakeCall(0x4714EC, switch_hand_hack, 1); // Keep unarmed mode MakeCall(0x45F019, intface_update_items_hack_begin); MakeCall(0x45F380, intface_update_items_hack_end); - dlogr(" Done", DL_INIT); //} } @@ -732,9 +716,8 @@ static void PartyMemberSkillPatch() { // the player is standing next to the party member. Because the related engine function is not fully implemented, enabling // this option without a global script that overrides First Aid/Doctor functions has very limited usefulness if (IniReader::GetConfigInt("Misc", "PartyMemberSkillFix", 0)) { - dlog("Applying First Aid/Doctor skill use patch for party members.", DL_INIT); + dlogr("Applying First Aid/Doctor skill use patch for party members.", DL_INIT); HookCall(0x412836, action_use_skill_on_hook); - dlogr(" Done", DL_INIT); } // Small code patch for HOOK_USESKILLON (change obj_dude to source) SafeWrite32(0x4128F3, 0x90909090); @@ -750,7 +733,7 @@ struct CodeData { static void SkipLoadingGameSettingsPatch() { if (int skipLoading = IniReader::GetConfigInt("Misc", "SkipLoadingGameSettings", 0)) { - dlog("Applying skip loading game settings from a saved game patch.", DL_INIT); + dlogr("Applying skip loading game settings from a saved game patch.", DL_INIT); BlockCall(0x493421); SafeWrite8(0x4935A8, 0x1F); SafeWrite32(0x4935AB, 0x90901B75); @@ -761,26 +744,23 @@ static void SkipLoadingGameSettingsPatch() { 0x4934E3, 0x4934F8, 0x49350D, 0x493522, 0x493547, 0x493558, 0x493569, 0x49357A }); - dlogr(" Done", DL_INIT); } } static void UseWalkDistancePatch() { int distance = IniReader::GetConfigInt("Misc", "UseWalkDistance", 3) + 2; if (distance > 1 && distance < 5) { - dlog("Applying walk distance for using objects patch.", DL_INIT); + dlogr("Applying walk distance for using objects patch.", DL_INIT); SafeWriteBatch(distance, {0x411E41, 0x411FF0, 0x4121C4, 0x412475, 0x412906}); // default is 5 - dlogr(" Done", DL_INIT); } } static void F1EngineBehaviorPatch() { if (IniReader::GetConfigInt("Misc", "Fallout1Behavior", 0)) { - dlog("Applying Fallout 1 engine behavior patch.", DL_INIT); + dlogr("Applying Fallout 1 engine behavior patch.", DL_INIT); BlockCall(0x4A4343); // disable playing the final movie/credits after the endgame slideshow SafeWrite8(0x477C71, CodeType::JumpShort); // disable halving the weight for power armor items HookCall(0x43F872, endgame_movie_hook); // play movie 10 or 11 based on the player's gender before the credits - dlogr(" Done", DL_INIT); } } @@ -921,45 +901,40 @@ void MiscPatches::init() { EngineOptimizationPatches(); if (IniReader::GetConfigString("Misc", "StartingMap", "", mapName, 16)) { - dlog("Applying starting map patch.", DL_INIT); + dlogr("Applying starting map patch.", DL_INIT); SafeWrite32(0x480AAA, (DWORD)&mapName); - dlogr(" Done", DL_INIT); } if (IniReader::GetConfigString("Misc", "VersionString", "", versionString, 65)) { - dlog("Applying version string patch.", DL_INIT); + dlogr("Applying version string patch.", DL_INIT); SafeWrite32(0x4B4588, (DWORD)&versionString); - dlogr(" Done", DL_INIT); } if (IniReader::GetConfigString("Misc", "PatchFile", "", patchName, 65)) { - dlog("Applying patch file patch.", DL_INIT); + dlogr("Applying patch file patch.", DL_INIT); SafeWrite32(0x444323, (DWORD)&patchName); - dlogr(" Done", DL_INIT); } if (IniReader::GetConfigInt("Misc", "SingleCore", 1)) { SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); if (sysInfo.dwNumberOfProcessors > 1) { - dlog("Applying single core patch.", DL_INIT); + dlogr("Applying single core patch.", DL_INIT); HANDLE process = GetCurrentProcess(); SetProcessAffinityMask(process, 2); // use only CPU 1 CloseHandle(process); - dlogr(" Done", DL_INIT); } } if (IniReader::GetConfigInt("Misc", "OverrideArtCacheSize", 0)) { - dlog("Applying override art cache size patch.", DL_INIT); + dlogr("Applying override art cache size patch.", DL_INIT); SafeWrite32(0x418867, 0x90909090); - SafeWrite32(0x418872, 261); // default for 512 MB system memory by installer - dlogr(" Done", DL_INIT); + SafeWrite32(0x418872, 261); // default for 512 MB system memory from offical installer } int time = IniReader::GetConfigInt("Misc", "CorpseDeleteTime", 6); // time in days if (time != 6) { - dlog("Applying corpse deletion time patch.", DL_INIT); + dlogr("Applying corpse deletion time patch.", DL_INIT); if (time <= 0) { time = 12; // hours } else if (time > 13) { @@ -968,7 +943,6 @@ void MiscPatches::init() { time *= 24; } SafeWrite32(0x483348, time); - dlogr(" Done", DL_INIT); } // Set idle function @@ -987,23 +961,20 @@ void MiscPatches::init() { // Remove hardcoding for maps with IDs 19 and 37 if (IniReader::GetConfigInt("Misc", "DisableSpecialMapIDs", 0)) { - dlog("Applying disable special maps handling patch.", DL_INIT); + dlogr("Applying disable special maps handling patch.", DL_INIT); SafeWriteBatch(0, {0x4836D6, 0x4836DB}); - dlogr(" Done", DL_INIT); } // Remove hardcoding for city areas 45 and 46 (AREA_FAKE_VAULT_13) if (IniReader::GetConfigInt("Misc", "DisableSpecialAreas", 0)) { - dlog("Applying disable special areas handling patch.", DL_INIT); + dlogr("Applying disable special areas handling patch.", DL_INIT); SafeWrite8(0x4C0576, CodeType::JumpShort); - dlogr(" Done", DL_INIT); } // Set the normal font for death screen subtitles if (IniReader::GetConfigInt("Misc", "DeathScreenFontPatch", 0)) { - dlog("Applying death screen font patch.", DL_INIT); + dlogr("Applying death screen font patch.", DL_INIT); HookCall(0x4812DF, main_death_scene_hook); - dlogr(" Done", DL_INIT); } // Highlight "Radiated" in red when the player is under the influence of negative effects of radiation diff --git a/sfall/Modules/Movies.cpp b/sfall/Modules/Movies.cpp index cc0d6cf33..a82b1f217 100644 --- a/sfall/Modules/Movies.cpp +++ b/sfall/Modules/Movies.cpp @@ -522,10 +522,9 @@ static void __declspec(naked) op_play_gmovie_hack() { void SkipOpeningMoviesPatch() { int skipOpening = IniReader::GetConfigInt("Misc", "SkipOpeningMovies", 0); if (skipOpening) { - dlog("Skipping opening movies.", DL_INIT); + dlogr("Skipping opening movies.", DL_INIT); SafeWrite16(0x4809C7, 0x1CEB); // jmps 0x4809E5 if (skipOpening == 2) BlockCall(0x4426A1); // game_splash_screen_ - dlogr(" Done", DL_INIT); } } @@ -572,7 +571,7 @@ bool Movies::DirectShowMovies() { } void Movies::init() { - dlog("Applying movie patch.", DL_INIT); + dlogr("Applying movie patch.", DL_INIT); // Pause and resume movie/sound playback when the game loses focus fo::func::set_focus_func(LostFocus); @@ -593,7 +592,6 @@ void Movies::init() { SafeWriteBatch((DWORD)MoviePtrs, {0x44E6AE, 0x44E721, 0x44E75E, 0x44E78A}); // gmovie_play_ MakeCall(0x44E896, gmovie_play_hack_subpal, 2); MakeCall(0x45A1C9, op_play_gmovie_hack); - dlogr(" Done", DL_INIT); DWORD days = SimplePatch(0x4A36EC, "Misc", "MovieTimer_artimer4", 360, 0); days = SimplePatch(0x4A3747, "Misc", "MovieTimer_artimer3", 270, 0, days); @@ -603,9 +601,8 @@ void Movies::init() { Artimer1DaysCheckTimer = max(0, min(days, Artimer1DaysCheckTimer)); char s[255]; sprintf_s(s, "Applying patch: MovieTimer_artimer1 = %d.", Artimer1DaysCheckTimer); - dlog(s, DL_INIT); + dlogr(s, DL_INIT); MakeJump(0x4A378B, Artimer1DaysCheckHack); - dlogr(" Done", DL_INIT); } SkipOpeningMoviesPatch(); diff --git a/sfall/Modules/PartyControl.cpp b/sfall/Modules/PartyControl.cpp index 3359a3994..858da15bd 100644 --- a/sfall/Modules/PartyControl.cpp +++ b/sfall/Modules/PartyControl.cpp @@ -839,9 +839,8 @@ void PartyControl::OrderAttackPatch() { static void NpcAutoLevelPatch() { npcAutoLevelEnabled = IniReader::GetConfigInt("Misc", "NPCAutoLevel", 0) != 0; if (npcAutoLevelEnabled) { - dlog("Applying NPC autolevel patch.", DL_INIT); + dlogr("Applying NPC autolevel patch.", DL_INIT); SafeWrite8(0x495CFB, CodeType::JumpShort); // jmps 0x495D28 (skip random check) - dlogr(" Done", DL_INIT); } } @@ -870,12 +869,11 @@ void PartyControl::init() { // Display party member's current level & AC & addict flag if (IniReader::GetConfigInt("Misc", "PartyMemberExtraInfo", 0)) { - dlog("Applying display NPC extra info patch.", DL_INIT); + dlogr("Applying display NPC extra info patch.", DL_INIT); HookCall(0x44926F, gdControlUpdateInfo_hook); Translate::Get("sfall", "PartyLvlMsg", "Lvl:", levelMsg, 12); Translate::Get("sfall", "PartyACMsg", "AC:", armorClassMsg, 12); Translate::Get("sfall", "PartyAddictMsg", "Addict", addictMsg, 16); - dlogr(" Done", DL_INIT); } partyOrderAttackMsg.push_back(Translate::Get("sfall", "PartyOrderAttackCreature", "::Growl::", 33)); diff --git a/sfall/Modules/Perks.cpp b/sfall/Modules/Perks.cpp index ef2568925..6eb5c4059 100644 --- a/sfall/Modules/Perks.cpp +++ b/sfall/Modules/Perks.cpp @@ -1184,27 +1184,26 @@ static void FastShotTraitFix() { Perks::fastShotTweak = IniReader::GetConfigInt("Misc", "FastShotFix", 0); switch (Perks::fastShotTweak) { case 1: - dlog("Applying Fast Shot trait patch (Haenlomal's tweak).", DL_INIT); + dlogr("Applying Fast Shot trait patch (Haenlomal's tweak).", DL_INIT); MakeJump(0x478E79, item_w_called_shot_hack); goto fix; case 2: - dlog("Applying Fast Shot trait patch (Alternative behavior).", DL_INIT); + dlogr("Applying Fast Shot trait patch (Alternative behavior).", DL_INIT); /* Implemented in sfall item_w_mp_cost function */ //SafeWrite16(0x478C9F, 0x9090); // item_w_mp_cost_ //HookCalls((void*)0x478C7D, {0x478BB8, 0x478BC7, 0x478BD6, 0x478BEA, 0x478BF9, 0x478C08, 0x478C2F}); // jmp 0x478C7D - goto done; + break; case 3: - dlog("Applying Fast Shot trait patch (Fallout 1 behavior).", DL_INIT); + dlogr("Applying Fast Shot trait patch (Fallout 1 behavior).", DL_INIT); /* Implemented in sfall item_w_mp_cost function */ //HookCall(0x478C97, (void*)fo::funcoffs::item_hit_with_); //SafeWrite16(0x478C9E, CodeType::JumpZ << 8); // ignore all unarmed attacks (cmp eax, 0; jz) - goto done; + break; default: - dlog("Applying Fast Shot trait fix.", DL_INIT); + dlogr("Applying Fast Shot trait fix.", DL_INIT); fix: //HookCall(0x478C97, item_w_mp_cost_hook); - Fix implemented in sfall item_w_mp_cost function - done: - dlogr(" Done", DL_INIT); + break; } } diff --git a/sfall/Modules/PlayerModel.cpp b/sfall/Modules/PlayerModel.cpp index b5fc36f63..000d80790 100644 --- a/sfall/Modules/PlayerModel.cpp +++ b/sfall/Modules/PlayerModel.cpp @@ -33,26 +33,22 @@ char defaultFemaleModelName[65] = {}; void PlayerModel::init() { if (IniReader::GetConfigString("Misc", "MaleStartModel", "", startMaleModelName, 33)) { - dlog("Applying male start model patch.", DL_INIT); + dlogr("Applying male start model patch.", DL_INIT); SafeWrite32(0x418B88, (DWORD)&startMaleModelName); - dlogr(" Done", DL_INIT); } if (IniReader::GetConfigString("Misc", "FemaleStartModel", "", startFemaleModelName, 33)) { - dlog("Applying female start model patch.", DL_INIT); + dlogr("Applying female start model patch.", DL_INIT); SafeWrite32(0x418BAB, (DWORD)&startFemaleModelName); - dlogr(" Done", DL_INIT); } IniReader::GetConfigString("Misc", "MaleDefaultModel", "hmjmps", defaultMaleModelName, 65); - dlog("Applying male model patch.", DL_INIT); + dlogr("Applying male model patch.", DL_INIT); SafeWrite32(0x418B50, (DWORD)&defaultMaleModelName); - dlogr(" Done", DL_INIT); IniReader::GetConfigString("Misc", "FemaleDefaultModel", "hfjmps", defaultFemaleModelName, 65); - dlog("Applying female model patch.", DL_INIT); + dlogr("Applying female model patch.", DL_INIT); SafeWrite32(0x418B6D, (DWORD)&defaultFemaleModelName); - dlogr(" Done", DL_INIT); } } diff --git a/sfall/Modules/Premade.cpp b/sfall/Modules/Premade.cpp index 974e5c502..499a9cd61 100644 --- a/sfall/Modules/Premade.cpp +++ b/sfall/Modules/Premade.cpp @@ -103,7 +103,7 @@ void Premade::init() { auto premadePaths = IniReader::GetConfigList("misc", "PremadePaths", "", 512); auto premadeFids = IniReader::GetConfigList("misc", "PremadeFIDs", "", 512); if (!premadePaths.empty() && !premadeFids.empty()) { - dlog("Applying premade characters patch.", DL_INIT); + dlogr("Applying premade characters patch.", DL_INIT); int count = min(premadePaths.size(), premadeFids.size()); premade = new fo::PremadeChar[count]; for (int i = 0; i < count; i++) { @@ -121,7 +121,6 @@ void Premade::init() { SafeWrite32(0x4A8B1E, (DWORD)premade); // select_display_bio_ SafeWrite32(0x4A7E2C, (DWORD)&premade[0].fid); // select_display_portrait_ std::strcpy((char*)0x50AF68, premade[0].path); // for selfrun - dlogr(" Done", DL_INIT); } // Add language path for premade GCD/BIO files diff --git a/sfall/Modules/QuestList.cpp b/sfall/Modules/QuestList.cpp index c6336d711..4ebba91ee 100644 --- a/sfall/Modules/QuestList.cpp +++ b/sfall/Modules/QuestList.cpp @@ -559,7 +559,7 @@ void QuestList::init() { questsButtonsType = IniReader::GetConfigInt("Misc", "UseScrollingQuestsList", 0); if (questsButtonsType > 0) { - dlog("Applying quests list patch.", DL_INIT); + dlogr("Applying quests list patch.", DL_INIT); QuestListPatch(); questsScrollButtonsX = IniReader::GetConfigInt("Misc", "QuestsScrollButtonsX", 140); @@ -569,8 +569,6 @@ void QuestList::init() { pageQuest.reserve(4); // init pageQuest.push_back(1); - - dlogr(" Done", DL_INIT); } else { HookCall(0x498186, PipStatus_hook_printfix); // fix "out of bounds" bug when printing a list of quests } diff --git a/sfall/Modules/Scripting/Opcodes.cpp b/sfall/Modules/Scripting/Opcodes.cpp index 6de80a2fa..8a3cb2951 100644 --- a/sfall/Modules/Scripting/Opcodes.cpp +++ b/sfall/Modules/Scripting/Opcodes.cpp @@ -270,7 +270,7 @@ static void __fastcall defaultOpcodeHandler(fo::Program* program, DWORD opcodeOf } void Opcodes::InitNew() { - dlogr("Adding sfall opcodes", DL_SCRIPT); + dlog("Adding sfall opcodes.", DL_SCRIPT); SafeWrite32(0x46E370, opcodeCount); // Maximum number of allowed opcodes SafeWrite32(0x46CE34, (DWORD)opcodes); // cmp check to make sure opcode exists @@ -292,9 +292,9 @@ void Opcodes::InitNew() { if (int unsafe = IniReader::GetIntDefaultConfig("Debugging", "AllowUnsafeScripting", 0)) { unsafeEnabled = true; if (unsafe == 2) checkValidMemAddr = false; - dlogr(" Unsafe opcodes enabled.", DL_SCRIPT); + dlogr(" Unsafe opcodes enabled.", DL_SCRIPT); } else { - dlogr(" Unsafe opcodes disabled.", DL_SCRIPT); + dlogr(" Unsafe opcodes disabled.", DL_SCRIPT); } opcodes[0x1cf] = op_write_byte; opcodes[0x1d0] = op_write_short; diff --git a/sfall/Modules/SpeedPatch.cpp b/sfall/Modules/SpeedPatch.cpp index 41b0fad7f..b4a5b18ad 100644 --- a/sfall/Modules/SpeedPatch.cpp +++ b/sfall/Modules/SpeedPatch.cpp @@ -199,7 +199,7 @@ void SpeedPatch::init() { } if (init == 100 && !modKey[0]) return; - dlog("Applying speed patch.", DL_INIT); + dlogr("Applying speed patch.", DL_INIT); switch (modKey[0]) { case -1: @@ -230,7 +230,6 @@ void SpeedPatch::init() { HookCall(0x4A433E, scripts_check_state_hook); TimerInit(); - dlogr(" Done", DL_INIT); } void SpeedPatch::exit() { diff --git a/sfall/Modules/SubModules/WindowRender.cpp b/sfall/Modules/SubModules/WindowRender.cpp index ba3c55fea..a5803aae1 100644 --- a/sfall/Modules/SubModules/WindowRender.cpp +++ b/sfall/Modules/SubModules/WindowRender.cpp @@ -180,11 +180,10 @@ void WindowRender::EnableRecalculateFadeSteps() { void WindowRender::init() { int multi = IniReader::GetConfigInt("Graphics", "FadeMultiplier", 100); if (multi != 100 || reCalculate) { - dlog("Applying fade patch.", DL_INIT); + dlogr("Applying fade patch.", DL_INIT); HookCall(0x493B16, palette_fade_to_hook); if (multi <= 0) multi = 1; fadeMulti = multi / 100.0f; - dlogr(" Done", DL_INIT); } // Enable support for transparent interface windows diff --git a/sfall/Modules/Tiles.cpp b/sfall/Modules/Tiles.cpp index a40dda1ee..c6292e303 100644 --- a/sfall/Modules/Tiles.cpp +++ b/sfall/Modules/Tiles.cpp @@ -300,14 +300,13 @@ static void __declspec(naked) art_get_name_hack() { void Tiles::init() { if (tileMode = IniReader::GetConfigInt("Misc", "AllowLargeTiles", 0)) { - dlog("Applying allow large tiles patch.", DL_INIT); + dlogr("Applying allow large tiles patch.", DL_INIT); HookCall(0x481D72, iso_init_hook); HookCall(0x48434C, square_load_hook); - dlogr(" Done", DL_INIT); } //if (IniReader::GetConfigInt("Misc", "MoreTiles", 1)) { - dlog("Applying tile FRM limit patch.", DL_INIT); + dlogr("Applying tile FRM limit patch.", DL_INIT); MakeCall(0x419D46, art_id_hack); MakeCall(0x419479, art_get_name_hack); SafeWriteBatch(0x0E, Tiles_0E); @@ -318,7 +317,6 @@ void Tiles::init() { SafeWrite8(HRP::Setting::GetAddress(0x1000E1C0), 0x40); // 4000 > 16384 SafeWrite8(HRP::Setting::GetAddress(0x1000E1DA), 0x3F); // and esi, 0x3FFF } - dlogr(" Done", DL_INIT); //} } diff --git a/sfall/Modules/Worldmap.cpp b/sfall/Modules/Worldmap.cpp index 3741f7312..c20c16783 100644 --- a/sfall/Modules/Worldmap.cpp +++ b/sfall/Modules/Worldmap.cpp @@ -375,25 +375,22 @@ static void MapLimitsPatches() { // This has priority over the SCROLL_DIST_X/Y options in f2_res.ini long data = IniReader::GetConfigInt("Misc", "LocalMapXLimit", 0); if (data > 0) { - dlog("Applying local map x limit patch.", DL_INIT); + dlogr("Applying local map x limit patch.", DL_INIT); SafeWrite32(0x4B13B9, data); HRP::ViewMap::SCROLL_DIST_X = data; - dlogr(" Done", DL_INIT); } data = IniReader::GetConfigInt("Misc", "LocalMapYLimit", 0); if (data > 0) { - dlog("Applying local map y limit patch.", DL_INIT); + dlogr("Applying local map y limit patch.", DL_INIT); SafeWrite32(0x4B13C7, data); HRP::ViewMap::SCROLL_DIST_Y = data; - dlogr(" Done", DL_INIT); } //if (IniReader::GetConfigInt("Misc", "CitiesLimitFix", 0)) { - dlog("Applying cities limit patch.", DL_INIT); + dlogr("Applying cities limit patch.", DL_INIT); if (*((BYTE*)0x4BF3BB) != CodeType::JumpShort) { SafeWrite8(0x4BF3BB, CodeType::JumpShort); // wmAreaInit_ } - dlogr(" Done", DL_INIT); //} } @@ -405,7 +402,7 @@ static void TimeLimitPatch() { limit = -1; // also reset time } if (limit >= -1 && limit < 13) { - dlog("Applying time limit patch.", DL_INIT); + dlogr("Applying time limit patch.", DL_INIT); if (limit == -1) { MakeCall(0x4A3DF5, script_chk_timed_events_hack, 1); MakeCall(0x4A3488, set_game_time_hack); @@ -419,7 +416,6 @@ static void TimeLimitPatch() { SafeWrite8(0x4A34EC, limit); SafeWrite8(0x4A3544, limit); } - dlogr(" Done", DL_INIT); } } @@ -450,38 +446,34 @@ static void WorldmapFpsPatch() { } if (IniReader::GetConfigInt("Misc", "WorldMapEncounterFix", 0)) { - dlog("Applying world map encounter patch.", DL_INIT); + dlogr("Applying world map encounter patch.", DL_INIT); WorldMapEncounterRate = IniReader::GetConfigInt("Misc", "WorldMapEncounterRate", 5); SafeWrite32(0x4C232D, 0xB8); // mov eax, 0; (wmInterfaceInit_) HookCall(0x4BFEE0, wmWorldMapFunc_hook); MakeCall(0x4C0667, wmRndEncounterOccurred_hack); - dlogr(" Done", DL_INIT); } } static void PathfinderFixInit() { //if (IniReader::GetConfigInt("Misc", "PathfinderFix", 0)) { - dlog("Applying Pathfinder patch.", DL_INIT); + dlogr("Applying Pathfinder patch.", DL_INIT); SafeWrite16(0x4C1FF6, 0x9090); // wmPartyWalkingStep_ HookCall(0x4C1C78, PathfinderFix); // wmGameTimeIncrement_ mapMultiMod = (double)IniReader::GetConfigInt("Misc", "WorldMapTimeMod", 100) / 100.0; - dlogr(" Done", DL_INIT); //} } static void StartingStatePatches() { int date = IniReader::GetConfigInt("Misc", "StartYear", -1); if (date >= 0) { - dlog("Applying starting year patch.", DL_INIT); + dlogr("Applying starting year patch.", DL_INIT); SafeWrite32(0x4A336C, date); - dlogr(" Done", DL_INIT); } int month = IniReader::GetConfigInt("Misc", "StartMonth", -1); if (month >= 0) { if (month > 11) month = 11; - dlog("Applying starting month patch.", DL_INIT); + dlogr("Applying starting month patch.", DL_INIT); SafeWrite32(0x4A3382, month); - dlogr(" Done", DL_INIT); } date = IniReader::GetConfigInt("Misc", "StartDay", -1); if (date >= 0) { @@ -490,27 +482,24 @@ static void StartingStatePatches() { } else if (date > 30) { date = 30; // set 31st day } - dlog("Applying starting day patch.", DL_INIT); + dlogr("Applying starting day patch.", DL_INIT); SafeWrite8(0x4A3356, static_cast(date)); - dlogr(" Done", DL_INIT); } long xPos = IniReader::GetConfigInt("Misc", "StartXPos", -1); if (xPos != -1) { if (xPos < 0) xPos = 0; - dlog("Applying starting x position patch.", DL_INIT); + dlogr("Applying starting x position patch.", DL_INIT); SafeWrite32(0x4BC990, xPos); SafeWrite32(0x4BCC08, xPos); - dlogr(" Done", DL_INIT); customPosition = true; } long yPos = IniReader::GetConfigInt("Misc", "StartYPos", -1); if (yPos != -1) { if (yPos < 0) yPos = 0; - dlog("Applying starting y position patch.", DL_INIT); + dlogr("Applying starting y position patch.", DL_INIT); SafeWrite32(0x4BC995, yPos); SafeWrite32(0x4BCC0D, yPos); - dlogr(" Done", DL_INIT); customPosition = true; } @@ -522,27 +511,24 @@ static void StartingStatePatches() { if (xPos != -1) { if (xPos < 0) xPos = 0; ViewportX = xPos; - dlog("Applying starting x view patch.", DL_INIT); + dlogr("Applying starting x view patch.", DL_INIT); SafeWrite32(FO_VAR_wmWorldOffsetX, ViewportX); - dlogr(" Done", DL_INIT); } yPos = IniReader::GetConfigInt("Misc", "ViewYPos", -1); if (yPos != -1) { if (yPos < 0) yPos = 0; ViewportY = yPos; - dlog("Applying starting y view patch.", DL_INIT); + dlogr("Applying starting y view patch.", DL_INIT); SafeWrite32(FO_VAR_wmWorldOffsetY, ViewportY); - dlogr(" Done", DL_INIT); } if (xPos != -1 || yPos != -1) HookCall(0x4BCF07, ViewportHook); // game_reset_ } static void PipBoyAutomapsPatch() { - dlog("Applying Pip-Boy automaps patch.", DL_INIT); + dlogr("Applying Pip-Boy automaps patch.", DL_INIT); MakeCall(0x4BF931, wmMapInit_hack, 2); SafeWrite32(0x41B8B7, (DWORD)AutomapPipboyList); memcpy(AutomapPipboyList, (void*)FO_VAR_displayMapList, sizeof(AutomapPipboyList)); // copy vanilla data - dlogr(" Done", DL_INIT); } void Worldmap::SaveData(HANDLE file) { diff --git a/sfall/SimplePatch.h b/sfall/SimplePatch.h index a01057cef..6df58f94d 100644 --- a/sfall/SimplePatch.h +++ b/sfall/SimplePatch.h @@ -22,11 +22,10 @@ T SimplePatch(DWORD *addrs, int numAddrs, const char* iniSection, const char* in value = maxValue; } _snprintf_s(msg, sizeof(msg), _TRUNCATE, "Applying patch: %s = %d.", iniKey, value); - dlog((const char*)msg, DL_INIT); + dlogr((const char*)msg, DL_INIT); for (int i = 0; i < numAddrs; i++) { SafeWrite(addrs[i], (T)value); } - dlogr(" Done", DL_INIT); } return value; } diff --git a/sfall/main.cpp b/sfall/main.cpp index a57d3eb3a..471ba4e20 100644 --- a/sfall/main.cpp +++ b/sfall/main.cpp @@ -272,9 +272,8 @@ static HMODULE SfallInit() { IniReader::init(); if (IniReader::GetConfigString("Misc", "ConfigFile", "", falloutConfigName, 65)) { - dlog("Applying config file patch.", DL_INIT); + dlogr("Applying config file patch.", DL_INIT); SafeWriteBatch((DWORD)&falloutConfigName, {0x444BA5, 0x444BCA}); - dlogr(" Done", DL_INIT); } else { // if the ConfigFile is not assigned a value std::strcpy(falloutConfigName, (const char*)FO_VAR_fallout_config); From a6a2285ffeb15b00f7915858e3dc9b428a7195a3 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 15 Feb 2023 21:05:25 +0800 Subject: [PATCH 22/33] Fixed incorrect death endings being shown * can happen in vanilla FO2 when the player is lv10 or higher, with a low chance. --- sfall/Modules/BugFixes.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index 593bbe410..f99438211 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -3537,7 +3537,7 @@ void BugFixes::init() { // Fix for incorrect death animations being used when killing critters with kill_critter_type function dlogr("Applying kill_critter_type fix.", DL_FIX); SafeWrite16(0x457E22, 0xDB31); // xor ebx, ebx - SafeWrite32(0x457C99, 0x30BE0075); // jnz loc_457C9B; mov esi, 48 + SafeWrite32(0x457C99, 0x30BE0075); // jnz 0x457C9B; mov esi, 48 // Fix for checking the horizontal position on the y-axis instead of x when setting coordinates on the world map SafeWrite8(0x4C4743, 0xC6); // cmp esi, eax @@ -3598,7 +3598,7 @@ void BugFixes::init() { // Fix for the double damage effect of Silent Death perk not being applied to critical hits //if (IniReader::GetConfigInt("Misc", "SilentDeathFix", 1)) { dlogr("Applying Silent Death patch.", DL_FIX); - SafeWrite8(0x4238DF, 0x8C); // jl loc_423A0D + SafeWrite8(0x4238DF, 0x8C); // jl 0x423A0D HookCall(0x423A99, compute_attack_hook); //} @@ -3653,13 +3653,13 @@ void BugFixes::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); - SafeWrite16(0x456B76, 0x23EB); // jmp loc_456B9B (skip unused engine code) + SafeWrite16(0x456B76, 0x23EB); // jmp 0x456B9B (skip unused engine code) // Fix broken obj_can_hear_obj function if (IniReader::GetConfigInt("Misc", "ObjCanHearObjFix", 0)) { dlogr("Applying obj_can_hear_obj fix.", DL_FIX); - SafeWrite8(0x4583D8, 0x3B); // jz loc_458414 - SafeWrite8(0x4583DE, CodeType::JumpZ); // jz loc_458414 + SafeWrite8(0x4583D8, 0x3B); // jz 0x458414 + SafeWrite8(0x4583DE, CodeType::JumpZ); // jz 0x458414 MakeCall(0x4583E0, op_obj_can_hear_obj_hack, 1); } @@ -4027,6 +4027,9 @@ void BugFixes::init() { // Corrects the language path for loading art files SafeWriteBatch((DWORD)&"art\\%s%s", {0x419B00, 0x419C06}); // art_data_size_, art_data_load_ + + // Fix for incorrect death endings being shown when some endings in the list are not available + SafeWrite8(0x440C8E, 7); // jnz 0x440C96 } } From 64dc30d92249815d5c33d4747e9d230f134b2bec Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sun, 26 Feb 2023 23:29:17 +0800 Subject: [PATCH 23/33] Removed CreditsAtBottom from ddraw.ini * sfall built-in credits will be shown at the beginning when from the main menu and at the end during the ending. --- artifacts/ddraw.ini | 3 -- artifacts/scripting/sfall function notes.md | 4 +- sfall/Modules/Credits.cpp | 45 ++++++++++++++------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 83d7d0f08..c03c86d27 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -696,9 +696,6 @@ SkipLoadingGameSettings=0 ;The formula for the duration in ticks is: 10 * (value - 3 * EN) KnockoutTime=35 -;Set to 1 to display sfall built-in credits at the bottom of credits.txt contents instead of at the top -CreditsAtBottom=0 - ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ; Critical modding options - the following options should be changed with caution ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/artifacts/scripting/sfall function notes.md b/artifacts/scripting/sfall function notes.md index cbb2ecec6..9f73d1408 100644 --- a/artifacts/scripting/sfall function notes.md +++ b/artifacts/scripting/sfall function notes.md @@ -983,7 +983,7 @@ sfall_funcX metarule functions `int sfall_func2("get_stat_min", int stat, bool who)`\ `int sfall_func2("get_stat_max", int stat, bool who)` - Returns the maximum or minimum set value of the specified stat (see `set_stat_min` and `set_stat_max` functions) -- `who`: 0 (false) or omitting the argument - returns the value of the player, 1 (true) - returns the value set for other critters +- `who`: 0 (False) or omitting the argument - returns the value of the player, 1 (True) - returns the value set for other critters ---- #### interface_art_draw @@ -1061,7 +1061,7 @@ sfall_funcX metarule functions ---- #### obj_is_openable `bool sfall_func1("obj_is_openable", object obj)` -- Returns True if the object is openable (i.e. has an opening/closing animation) +- Returns True if the object is openable (i.e. has an opening/closing animation), False otherwise **** diff --git a/sfall/Modules/Credits.cpp b/sfall/Modules/Credits.cpp index a719ee3f9..03210fbdb 100644 --- a/sfall/Modules/Credits.cpp +++ b/sfall/Modules/Credits.cpp @@ -27,7 +27,7 @@ namespace sfall { -static DWORD InCredits = 0; +static bool InCredits = false; static DWORD CreditsLine = 0; static const char* ExtraLines[] = { @@ -84,15 +84,6 @@ static const char* ExtraLines[] = { static DWORD ExtraLineCount = sizeof(ExtraLines) / 4; //static const char* creditsFile = "credits.txt"; -static void __declspec(naked) ShowCreditsHook() { - InCredits = 1; - CreditsLine = 0; - //__asm mov eax, creditsFile; - __asm call fo::funcoffs::credits_; - InCredits = 0; - __asm retn; -} - static DWORD __fastcall CreditsNextLine(char* buf, DWORD* font, DWORD* colour) { if (!InCredits || CreditsLine >= ExtraLineCount) return 0; const char* line = ExtraLines[CreditsLine++]; @@ -159,13 +150,37 @@ static void __declspec(naked) CreditsNextLineHook_Bottom() { } } -void Credits::init() { - HookCalls(ShowCreditsHook, {0x480C49, 0x43F881}); - if (IniReader::GetConfigInt("Misc", "CreditsAtBottom", 0)) { - HookCall(0x42CB49, CreditsNextLineHook_Bottom); +static void __stdcall SetCreditsPosition(DWORD addr) { + void* func; + if (addr == (0x43F881 + 5)) { // called from endgame_movie_ + func = CreditsNextLineHook_Bottom; } else { - HookCall(0x42CB49, CreditsNextLineHook_Top); + func = CreditsNextLineHook_Top; } + HookCall(0x42CB49, func); +} + +static void __declspec(naked) ShowCreditsHook() { + __asm { + push eax; + push edx; + push ebx; + push [esp + 12]; // return address + call SetCreditsPosition; + pop ebx; + pop edx; + pop eax; + mov InCredits, 1; + mov CreditsLine, 0; + //mov eax, creditsFile; + call fo::funcoffs::credits_; + mov InCredits, 0; + retn; + } +} + +void Credits::init() { + HookCalls(ShowCreditsHook, {0x480C49, 0x43F881}); } } From a75886a0209c8fa244ffc6396fe23e6958206047 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 1 Mar 2023 09:13:48 +0800 Subject: [PATCH 24/33] Added a tweak to the ammo info for Glovz's/YAAM * to display correct ammo stats based on the formulas w/o editing proto.msg manually. Updated translation ini files. Set the maximum number of screenshots to 10k (was 100k) * 100k is impractical because the max files per directory on FAT32 is 65535 (only if all files are in 8.3 format) when the game came out. --- artifacts/config_files/Translations.ini | 2 ++ .../translations/brazilian_portuguese.ini | 2 ++ artifacts/translations/chs.ini | 2 ++ artifacts/translations/cht.ini | 2 ++ artifacts/translations/french.ini | 2 ++ artifacts/translations/german.ini | 2 ++ artifacts/translations/polish.ini | 2 ++ artifacts/translations/russian.ini | 2 ++ sfall/Modules/Credits.cpp | 2 -- sfall/Modules/DamageMod.cpp | 23 +++++++++++++++++++ sfall/Modules/Graphics.cpp | 3 +++ 11 files changed, 42 insertions(+), 2 deletions(-) diff --git a/artifacts/config_files/Translations.ini b/artifacts/config_files/Translations.ini index f93611d03..2c95cfa09 100644 --- a/artifacts/config_files/Translations.ini +++ b/artifacts/config_files/Translations.ini @@ -11,6 +11,8 @@ PartyLvlMsg=Lvl: PartyACMsg=AC: PartyAddictMsg=Addict NPCPickupFail=%s cannot pick up the item. +AmmoInfoGlovz=Div: DR/%d, DT/%d +AmmoInfoYAAM=DT Mod: %d PartyOrderAttackHuman=I'll take care of it.|Okay, I got it.|Sounds like a plan. PartyOrderAttackCreature=::Growl:: diff --git a/artifacts/translations/brazilian_portuguese.ini b/artifacts/translations/brazilian_portuguese.ini index 377f68519..a4ab998d7 100644 --- a/artifacts/translations/brazilian_portuguese.ini +++ b/artifacts/translations/brazilian_portuguese.ini @@ -11,6 +11,8 @@ PartyLvlMsg=Nvl: PartyACMsg=CA: PartyAddictMsg=Viciado NPCPickupFail=%s não pôde pegar o item. +AmmoInfoGlovz=Div: DR/%d, DT/%d +AmmoInfoYAAM=DT Mod: %d PartyOrderAttackHuman=Eu tomarei conta disso.|Ok, eu entendi.|Soa como um plano. PartyOrderAttackCreature=::Rosnado:: diff --git a/artifacts/translations/chs.ini b/artifacts/translations/chs.ini index 2bca2dcd7..d374a4292 100644 --- a/artifacts/translations/chs.ini +++ b/artifacts/translations/chs.ini @@ -11,6 +11,8 @@ PartyLvlMsg= PartyACMsg=AC: PartyAddictMsg=ÉÏñ« NPCPickupFail=%sÎÞ·¨½«¶«Î÷¼ñÆðÀ´¡£ +AmmoInfoGlovz=Div: DR/%d, DT/%d +AmmoInfoYAAM=DT Mod: %d PartyOrderAttackHuman=ÎÒ»á¶Ô¸¶ËûµÄ¡£|ºÃ£¬ÎÒÖªµÀÁË¡£|ºÃÖ÷Òâ¡£ PartyOrderAttackCreature=::ºðºð:: diff --git a/artifacts/translations/cht.ini b/artifacts/translations/cht.ini index bf1a0809f..67d284670 100644 --- a/artifacts/translations/cht.ini +++ b/artifacts/translations/cht.ini @@ -11,6 +11,8 @@ PartyLvlMsg= PartyACMsg=AC: PartyAddictMsg=¤WÅ} NPCPickupFail=%sµLªk±NªF¦è¾ß°_¨Ó¡C +AmmoInfoGlovz=Div: DR/%d, DT/%d +AmmoInfoYAAM=DT Mod: %d PartyOrderAttackHuman=§Ú·|¹ï¥I¥Lªº¡C|¦n¡A§Úª¾¹D¤F¡C|¦n¥D·N¡C PartyOrderAttackCreature=::§q§q:: diff --git a/artifacts/translations/french.ini b/artifacts/translations/french.ini index 52314b82c..402c4209b 100644 --- a/artifacts/translations/french.ini +++ b/artifacts/translations/french.ini @@ -11,6 +11,8 @@ PartyLvlMsg=Niveau: PartyACMsg=CA: PartyAddictMsg=Accroc NPCPickupFail=%s ne peux pas prendre cet objet. +AmmoInfoGlovz=Div. : RD/%d, SD/%d +AmmoInfoYAAM=Mod. SD : %d PartyOrderAttackHuman=Je m'en occupe|Okay, je fais ça|Bonne idée PartyOrderAttackCreature=::Grogne:: diff --git a/artifacts/translations/german.ini b/artifacts/translations/german.ini index b158536d8..ea82c4898 100644 --- a/artifacts/translations/german.ini +++ b/artifacts/translations/german.ini @@ -11,6 +11,8 @@ PartyLvlMsg=Lvl: PartyACMsg=RÜ: PartyAddictMsg=Abhäng NPCPickupFail=%s kann das Objekt nicht nehmen. +AmmoInfoGlovz=Div: RV/%d, SV/%d +AmmoInfoYAAM=SV-Mod: %d PartyOrderAttackHuman=Ich kümmere mich darum.|Wird gemacht.|Geht klar. PartyOrderAttackCreature=::Grrrr:: diff --git a/artifacts/translations/polish.ini b/artifacts/translations/polish.ini index 5d5398d8b..bf806be44 100644 --- a/artifacts/translations/polish.ini +++ b/artifacts/translations/polish.ini @@ -11,6 +11,8 @@ PartyLvlMsg=Lvl: PartyACMsg=AC: PartyAddictMsg=Uzale¿niony NPCPickupFail=%s nie mo¿e podnieœæ przedmiotu. +AmmoInfoGlovz=Dz.: OO/%d, PO/%d +AmmoInfoYAAM=Mod. PO: %d PartyOrderAttackHuman=Zajmê siê tym.|Okej, zrozumia³em.|No to mamy plan. PartyOrderAttackCreature=::Warkniêcie:: diff --git a/artifacts/translations/russian.ini b/artifacts/translations/russian.ini index 794f9a6d5..f4c8c1de2 100644 --- a/artifacts/translations/russian.ini +++ b/artifacts/translations/russian.ini @@ -11,6 +11,8 @@ PartyLvlMsg= PartyACMsg=ÊÁ: PartyAddictMsg=Çàâèñèìîñòü NPCPickupFail=%s íå ìîæåò ïîäîáðàòü ïðåäìåò. +AmmoInfoGlovz=Äåë.: ÑÓ/%d, ÏÓ/%d +AmmoInfoYAAM=Èçì. ÏÓ: %d PartyOrderAttackHuman=Õîðîøî, ÿ èì çàéìóñü.|Öåëü ÿñíà.|Äåéñòâóþ ïî ïëàíó. PartyOrderAttackCreature=::Ãððð:: diff --git a/sfall/Modules/Credits.cpp b/sfall/Modules/Credits.cpp index 03210fbdb..2cab8283a 100644 --- a/sfall/Modules/Credits.cpp +++ b/sfall/Modules/Credits.cpp @@ -82,7 +82,6 @@ static const char* ExtraLines[] = { }; static DWORD ExtraLineCount = sizeof(ExtraLines) / 4; -//static const char* creditsFile = "credits.txt"; static DWORD __fastcall CreditsNextLine(char* buf, DWORD* font, DWORD* colour) { if (!InCredits || CreditsLine >= ExtraLineCount) return 0; @@ -172,7 +171,6 @@ static void __declspec(naked) ShowCreditsHook() { pop eax; mov InCredits, 1; mov CreditsLine, 0; - //mov eax, creditsFile; call fo::funcoffs::credits_; mov InCredits, 0; retn; diff --git a/sfall/Modules/DamageMod.cpp b/sfall/Modules/DamageMod.cpp index 16cde82ad..2c4a10c08 100644 --- a/sfall/Modules/DamageMod.cpp +++ b/sfall/Modules/DamageMod.cpp @@ -20,6 +20,7 @@ #include "..\FalloutEngine\Fallout2.h" #include "..\Logging.h" +#include "..\Translate.h" #include "HookScripts.h" #include "Unarmed.h" @@ -32,6 +33,8 @@ namespace sfall int DamageMod::formula; +static char ammoInfoFmt[32]; + // Integer division w/ round half to even for Glovz's damage formula // Prerequisite: both dividend and divisor must be positive integers (should already be handled in the main function) static long DivRound(long dividend, long divisor) { @@ -117,6 +120,13 @@ void DamageMod::DamageGlovz(fo::ComputeAttackResult &ctd, DWORD &accumulatedDama } } +static __declspec(naked) void AmmoInfoPrintGlovz() { + __asm { + lea edi, ammoInfoFmt; + retn; + } +} + // YAAM v1.1a by Haenlomal 2010.05.13 void DamageMod::DamageYAAM(fo::ComputeAttackResult &ctd, DWORD &accumulatedDamage, long rounds, long armorDT, long armorDR, long bonusRangedDamage, long multiplyDamage, long difficulty) { if (rounds <= 0) return; // Check number of hits @@ -169,6 +179,13 @@ void DamageMod::DamageYAAM(fo::ComputeAttackResult &ctd, DWORD &accumulatedDamag } } +static __declspec(naked) void AmmoInfoPrintYAAM() { + __asm { + lea ecx, ammoInfoFmt; + retn; + } +} + //////////////////////////////////////////////////////////////////////////////// // Display melee damage w/o PERK_bonus_hth_damage bonus @@ -326,8 +343,14 @@ void DamageMod::init() { switch (formula) { case 1: case 2: + HookScripts::InjectingHook(HOOK_SUBCOMBATDAMAGE); + MakeCall(0x49B54A, AmmoInfoPrintGlovz, 2); // Dmg Mod (obj_examine_func_) + Translate::Get("sfall", "AmmoInfoGlovz", "Div: DR/%d, DT/%d", ammoInfoFmt, 32); + break; case 5: HookScripts::InjectingHook(HOOK_SUBCOMBATDAMAGE); + MakeCall(0x49B4EB, AmmoInfoPrintYAAM, 2); // DR Mod (obj_examine_func_) + Translate::Get("sfall", "AmmoInfoYAAM", "DT Mod: %d", ammoInfoFmt, 32); break; default: formula = 0; diff --git a/sfall/Modules/Graphics.cpp b/sfall/Modules/Graphics.cpp index ff9e9b3eb..07f8d3238 100644 --- a/sfall/Modules/Graphics.cpp +++ b/sfall/Modules/Graphics.cpp @@ -1307,6 +1307,9 @@ void Graphics::init() { LoadGameHook::OnBeforeGameInit() += []() { WinProc::SetWindowProc(); }; } + // Set the maximum number of BMP screenshots to 10k (was 100k) + SafeWriteBatch(10000, {0x4C908B, 0x4C9093}); // default_screendump_ + WindowRender::init(); } From 56150d572a98bba8fb4b9fc3be8027e16c889536 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sun, 5 Mar 2023 10:18:59 +0800 Subject: [PATCH 25/33] Renamed some object flags --- artifacts/mods/gl_partycontrol.ssl | 8 ++------ artifacts/scripting/functions.yml | 8 ++++---- artifacts/scripting/headers/define_extra.h | 15 +++++++++++---- sfall/FalloutEngine/Enums.h | 6 +++--- sfall/Game/tilemap.cpp | 4 ++-- sfall/Modules/BugFixes.cpp | 2 +- sfall/Modules/Scripting/Handlers/Objects.cpp | 2 +- 7 files changed, 24 insertions(+), 21 deletions(-) diff --git a/artifacts/mods/gl_partycontrol.ssl b/artifacts/mods/gl_partycontrol.ssl index b0d6bde71..8420d6923 100644 --- a/artifacts/mods/gl_partycontrol.ssl +++ b/artifacts/mods/gl_partycontrol.ssl @@ -11,14 +11,10 @@ */ -#include "..\headers\define.h" -//#include "..\headers\command.h" +#include "..\headers\global.h" +#include "..\headers\critrpid.h" #include "main.h" -#define OBJ_DATA_LIGHT_DISTANCE (0x6C) -#define OBJ_DATA_LIGHT_INTENSITY (0x70) -#define PID_PLAYER (16777216) - procedure start; procedure AllowControl(variable pid); procedure SetLight(variable critter, variable int, variable dist); diff --git a/artifacts/scripting/functions.yml b/artifacts/scripting/functions.yml index 8ff9c91f1..dd5e127f9 100644 --- a/artifacts/scripting/functions.yml +++ b/artifacts/scripting/functions.yml @@ -130,12 +130,12 @@ detail: get_stat_min(int stat, bool who = False) doc: | - Returns the minimum set value of the specified stat (see `set_stat_min` functions) - - who: 0 (`false`) or omitting the argument - returns the value of the player, 1 (true) - returns the value set for other critters + - who: 0 (`False`) or omitting the argument - returns the value of the player, 1 (`True`) - returns the value set for other critters - name: get_stat_max detail: get_stat_max(int stat, bool who = False) doc: | - Returns the maximum set value of the specified stat (see `set_stat_max` functions) - - who: 0 (`false`) or omitting the argument - returns the value of the player, 1 (true) - returns the value set for other critters + - who: 0 (`False`) or omitting the argument - returns the value of the player, 1 (`True`) - returns the value set for other critters - name: Alter min/max doc: The `set_stat_max/min` functions can be used to set the valid ranges on stats. Values returned by `get_current_stat` will be clamped to this range. The `set_pc_` function only affects the player, the `set_npc_` functions only affects other critters, and the `set_` functions affects both. @@ -1680,7 +1680,7 @@ - winName: the window name, assigned to the window by the `CreateWin/create_win` function - winID: the ID number of the interface or script window obtained with the `get_window_under_mouse` function, or 0 for the current game interface - flag: the flag to change (see `WIN_FLAG_*` constants in `define_extra.h`) - - value: `true` - set the flag, `false` - unset the flag + - value: `True` - set the flag, `False` - unset the flag macro: sfall.h - name: win_fill_color @@ -1925,5 +1925,5 @@ - name: obj_is_openable detail: bool obj_is_openable(object obj) - doc: Returns True if the object is openable (i.e. has an opening/closing animation) + doc: Returns True if the object is openable (i.e. has an opening/closing animation), False otherwise macro: sfall.h diff --git a/artifacts/scripting/headers/define_extra.h b/artifacts/scripting/headers/define_extra.h index d9375b322..0e916e325 100644 --- a/artifacts/scripting/headers/define_extra.h +++ b/artifacts/scripting/headers/define_extra.h @@ -2,8 +2,10 @@ #ifndef DEFINE_EXTRA_H #define DEFINE_EXTRA_H +#define PID_PLAYER (16777216) + /* Combat Flags */ -#define DAM_PRESERVE_FLAGS 0x80000000 // keep the existing result flags when setting new flags in attack_complex (for sfall) +#define DAM_PRESERVE_FLAGS (0x80000000) // keep the existing result flags when setting new flags in attack_complex (for sfall) #define BODY_HIT_HEAD (0) #define BODY_HIT_LEFT_ARM (1) @@ -67,12 +69,12 @@ #define ATKMODE_SEC_FLAME 128 // 0x00000080 /* Object flags for get/set_flags */ -#define FLAG_MOUSE_3D (0x1) -#define FLAG_WALKTHRU (0x4) +#define FLAG_HIDDEN (0x1) +#define FLAG_NOSAVE (0x4) #define FLAG_FLAT (0x8) #define FLAG_NOBLOCK (0x10) #define FLAG_LIGHTING (0x20) -#define FLAG_TEMP (0x400) +#define FLAG_NOREMOVE (0x400) #define FLAG_MULTIHEX (0x800) #define FLAG_NOHIGHLIGHT (0x1000) #define FLAG_USED (0x2000) @@ -105,6 +107,9 @@ #define CFLG_NOKNOCKBACK 16384 // 0x00004000 - Knock (cannot be knocked back) #define CFLG_NOKNOCKDOWN CFLG_NOKNOCKBACK // obsolete +/* Door flags */ +#define FLAG_WALKTHRU (0x4) + /* Window flags */ #define WIN_FLAG_DONTMOVE (0x2) // does not move the window to the foreground when clicking on the window #define WIN_FLAG_MOVEONTOP (0x4) // places the window on top of other windows @@ -424,6 +429,8 @@ #define OBJ_DATA_MISC_FLAGS (0x38) #define OBJ_DATA_PID (0x64) #define OBJ_DATA_CID (0x68) // combat ID, used by critters in savegame (don't change while in combat) +#define OBJ_DATA_LIGHT_DISTANCE (0x6C) +#define OBJ_DATA_LIGHT_INTENSITY (0x70) #define OBJ_DATA_SID (0x78) // script ID #define OBJ_DATA_SCRIPT_INDEX (0x80) // script index number in scripts.lst // items diff --git a/sfall/FalloutEngine/Enums.h b/sfall/FalloutEngine/Enums.h index 04949120a..aea53f4c9 100644 --- a/sfall/FalloutEngine/Enums.h +++ b/sfall/FalloutEngine/Enums.h @@ -243,12 +243,12 @@ enum class Material : long namespace ObjectFlag { enum ObjectFlag : unsigned long { - Mouse_3d = 0x00000001, - WalkThru = 0x00000004, + Hidden = 0x00000001, + NoSave = 0x00000004, // WalkThru flag for doors Flat = 0x00000008, NoBlock = 0x00000010, Lighting = 0x00000020, - Temp = 0x00000400, // ??? + NoRemove = 0x00000400, MultiHex = 0x00000800, NoHighlight = 0x00001000, Used = 0x00002000, // set if there was/is any event for the object diff --git a/sfall/Game/tilemap.cpp b/sfall/Game/tilemap.cpp index b186bbe9d..4066581ce 100644 --- a/sfall/Game/tilemap.cpp +++ b/sfall/Game/tilemap.cpp @@ -25,7 +25,7 @@ static fo::GameObject* __fastcall obj_path_blocking_at(fo::GameObject* source, l if (elev == obj->object->elevation) { fo::GameObject* object = obj->object; long flags = object->flags; - if (!(flags & (fo::ObjectFlag::Mouse_3d | fo::ObjectFlag::NoBlock)) && source != object) { + if (!(flags & (fo::ObjectFlag::Hidden | fo::ObjectFlag::NoBlock)) && source != object) { char type = object->TypeFid(); if (type == fo::ObjType::OBJ_TYPE_SCENERY || type == fo::ObjType::OBJ_TYPE_WALL) { return object; @@ -44,7 +44,7 @@ static fo::GameObject* __fastcall obj_path_blocking_at(fo::GameObject* source, l if (elev == obj->object->elevation) { fo::GameObject* object = obj->object; long flags = object->flags; - if (flags & fo::ObjectFlag::MultiHex && !(flags & (fo::ObjectFlag::Mouse_3d | fo::ObjectFlag::NoBlock)) && source != object) { + if (flags & fo::ObjectFlag::MultiHex && !(flags & (fo::ObjectFlag::Hidden | fo::ObjectFlag::NoBlock)) && source != object) { char type = object->TypeFid(); if (type == fo::ObjType::OBJ_TYPE_SCENERY || type == fo::ObjType::OBJ_TYPE_WALL) { return object; diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index f99438211..6603c7c41 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -1160,7 +1160,7 @@ static void __declspec(naked) obj_load_func_hack() { static const DWORD obj_load_func_Ret = 0x488F14; using fo::InCombat; __asm { - test word ptr [eax + flags], Temp; // engine code + test word ptr [eax + flags], NoRemove; // engine code jz fix; retn; fix: diff --git a/sfall/Modules/Scripting/Handlers/Objects.cpp b/sfall/Modules/Scripting/Handlers/Objects.cpp index c7656965d..40a61a67d 100644 --- a/sfall/Modules/Scripting/Handlers/Objects.cpp +++ b/sfall/Modules/Scripting/Handlers/Objects.cpp @@ -340,7 +340,7 @@ void op_get_party_members(OpcodeContext& ctx) { DWORD arrayId = CreateTempArray(0, 4); for (int i = 0; i < actualCount; i++) { fo::GameObject* obj = fo::var::partyMemberList[i].object; - if (includeHidden || (obj->IsCritter() && !fo::func::critter_is_dead(obj) && !(obj->flags & fo::ObjectFlag::Mouse_3d))) { + if (includeHidden || (obj->IsCritter() && !fo::func::critter_is_dead(obj) && !(obj->flags & fo::ObjectFlag::Hidden))) { arrays[arrayId].push_back((long)obj); } } From 30802e8e218d2fe1db69b14292279716aa411d46 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 6 Mar 2023 22:41:37 +0800 Subject: [PATCH 26/33] Changed the copyright text format in the credits --- sfall/Modules/Credits.cpp | 4 ++-- sfall/Modules/Graphics.cpp | 2 +- sfall/Modules/Graphics.h | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/sfall/Modules/Credits.cpp b/sfall/Modules/Credits.cpp index 2cab8283a..ad5a1509b 100644 --- a/sfall/Modules/Credits.cpp +++ b/sfall/Modules/Credits.cpp @@ -33,8 +33,8 @@ static DWORD CreditsLine = 0; static const char* ExtraLines[] = { "#SFALL " VERSION_STRING, "", - "sfall is free software, licensed under the GPL", - LEGAL_COPYRIGHT, + "@sfall is free software, licensed under the GPL", + "@" LEGAL_COPYRIGHT, "", "@Author", "Timeslip", diff --git a/sfall/Modules/Graphics.cpp b/sfall/Modules/Graphics.cpp index 07f8d3238..dc8a7595a 100644 --- a/sfall/Modules/Graphics.cpp +++ b/sfall/Modules/Graphics.cpp @@ -76,7 +76,7 @@ bool Graphics::PlayAviMovie = false; bool Graphics::AviMovieWidthFit = false; static bool dShowMovies; -bool DeviceLost = false; +static bool DeviceLost = false; static char textureFilter; // 1 - auto, 2 - force static DDSURFACEDESC surfaceDesc; diff --git a/sfall/Modules/Graphics.h b/sfall/Modules/Graphics.h index da2cc0dc0..723169969 100644 --- a/sfall/Modules/Graphics.h +++ b/sfall/Modules/Graphics.h @@ -30,7 +30,6 @@ namespace sfall extern IDirect3D9* d3d9; extern IDirect3DDevice9* d3d9Device; extern IDirectDrawSurface* primarySurface; -extern bool DeviceLost; /* static void DDSurfaceToDXTexture(BYTE* src, long width, long height, long src_width, DWORD* dst, long dst_width) { From 656b122f3ea70e3a8f59d53c1f3ed71bbea419db Mon Sep 17 00:00:00 2001 From: NovaRain Date: Fri, 10 Mar 2023 21:01:21 +0800 Subject: [PATCH 27/33] Removed deprecated "register" keyword Minor edits to documents. --- artifacts/scripting/functions.yml | 2 +- artifacts/scripting/sfall function notes.md | 4 ++-- sfall/Modules/Explosions.cpp | 16 ++++++++-------- sfall/Modules/HookScripts/MiscHs.cpp | 6 +++--- sfall/Modules/Interface.cpp | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/artifacts/scripting/functions.yml b/artifacts/scripting/functions.yml index dd5e127f9..8dc233bad 100644 --- a/artifacts/scripting/functions.yml +++ b/artifacts/scripting/functions.yml @@ -757,7 +757,7 @@ - makes the specified item (pid) an explosive item like Dynamite or Plastic Explosives - `maxDamage` is optional - `activePid` is for an item with an active timer, can be the same as the `pid` argument - - the item proto must be "Misc Item" type and have "Use" action flag + - the item proto must be the **Misc Item** type and have the **Use** action flag - minDamage/maxDamage are the minimum and maximum explosion damage - using the function on an item that is already set as an explosive will override its previous settings - NOTE: this function does not work for pids of Dynamite and Plastic Explosives diff --git a/artifacts/scripting/sfall function notes.md b/artifacts/scripting/sfall function notes.md index 9f73d1408..2aabf4798 100644 --- a/artifacts/scripting/sfall function notes.md +++ b/artifacts/scripting/sfall function notes.md @@ -693,8 +693,8 @@ sfall_funcX metarule functions `void sfall_func3("item_make_explosive", int pid, int activePid, int damage)`\ `void sfall_func4("item_make_explosive", int pid, int activePid, int min, int max)` - Makes the specified item (pid) an explosive item like Dynamite or Plastic Explosives -- `activePid` is for an item with an active timer, can be the same as the pid argument -- The item proto must be **Misc Item** type and have **Use** action flag +- `activePid` is for an item with an active timer, can be the same as the `pid` argument +- The item proto must be the **Misc Item** type and have the **Use** action flag - `min` and `max` are the minimum and maximum explosion damage - Using the function on an item that is already set as an explosive will override its previous settings - __NOTE:__ this function does not work for pid's of Dynamite and Plastic Explosives diff --git a/sfall/Modules/Explosions.cpp b/sfall/Modules/Explosions.cpp index 95850b4b1..1aa944d1d 100644 --- a/sfall/Modules/Explosions.cpp +++ b/sfall/Modules/Explosions.cpp @@ -165,23 +165,23 @@ static void __declspec(naked) fire_dance_lighting_fix1() { } } -//----------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// -static DWORD __fastcall CheckExplosives(DWORD register pid) { +static DWORD __fastcall CheckExplosives(DWORD pid) { for (const auto &item: explosives) { if (item.pid == pid) return item.pidActive; } return 0; } -static DWORD __fastcall CheckActiveExplosives(DWORD register pid) { +static DWORD __fastcall CheckActiveExplosives(DWORD pid) { for (const auto &item: explosives) { if (item.pidActive == pid) return 0; } return 1; } -static DWORD __fastcall GetDamage(DWORD register pid, DWORD &min, DWORD &max) { +static DWORD __fastcall GetDamage(DWORD pid, DWORD &min, DWORD &max) { DWORD result = 0; for (const auto &item: explosives) { if (item.pidActive == pid) { @@ -194,7 +194,7 @@ static DWORD __fastcall GetDamage(DWORD register pid, DWORD &min, DWORD &max) { return result; } -static DWORD __fastcall SetQueueExplosionDamage(DWORD register pid) { +static DWORD __fastcall SetQueueExplosionDamage(DWORD pid) { DWORD min, max; DWORD result = GetDamage(pid, min, max); @@ -288,7 +288,7 @@ static void __declspec(naked) protinstTestDroppedExplosive_hack() { call CheckActiveExplosives; test eax, eax; jz end; - mov dword ptr [esp], 0x49C112; // exit, no active item explosive + mov dword ptr [esp], 0x49C112; // exit, no active explosive item end: retn; } @@ -318,7 +318,7 @@ void Explosions::AddToExplosives(DWORD pid, DWORD activePid, DWORD minDmg, DWORD } } -//----------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// static const DWORD explosion_dmg_check_adr[] = {0x411709, 0x4119FC, 0x411C08, 0x4517C1, 0x423BC8, 0x42381A}; static const DWORD explosion_art_adr[] = {0x411A19, 0x411A29, 0x411A35, 0x411A3C}; @@ -468,7 +468,7 @@ void ResetExplosionRadius() { } static void ResetExplosionDamage() { - if (!explosives.empty()) explosives.clear(); + explosives.clear(); if (!explosionsDamageReset) return; SafeWrite32(dynamite_min_dmg_addr, dynamite_minDmg); diff --git a/sfall/Modules/HookScripts/MiscHs.cpp b/sfall/Modules/HookScripts/MiscHs.cpp index 2c6221b62..1805558fe 100644 --- a/sfall/Modules/HookScripts/MiscHs.cpp +++ b/sfall/Modules/HookScripts/MiscHs.cpp @@ -11,7 +11,7 @@ namespace sfall { // The hook is executed twice when entering the barter screen and after transaction: the first time is for the player; the second time is for NPC -static DWORD __fastcall BarterPriceHook_Script(register fo::GameObject* source, register fo::GameObject* target, DWORD callAddr) { +static DWORD __fastcall BarterPriceHook_Script(fo::GameObject* source, fo::GameObject* target, DWORD callAddr) { bool barterIsParty = (fo::var::dialog_target_is_party != 0); long computeCost = fo::func::barter_compute_value(source, target); @@ -100,7 +100,7 @@ void SourceUseSkillOnInit() { sourceSkillOn = fo::var::obj_dude; } static char resultSkillOn; // -1 - cancel handler, 1 - replace user static long bakupCombatState; -static void __fastcall UseSkillOnHook_Script(DWORD source, DWORD target, register DWORD skillId) { +static void __fastcall UseSkillOnHook_Script(DWORD source, DWORD target, DWORD skillId) { BeginHook(); argCount = 3; @@ -389,7 +389,7 @@ static void __declspec(naked) CarTravelHack() { } } -static long __fastcall GlobalVarHook_Script(register DWORD number, register int value) { +static long __fastcall GlobalVarHook_Script(DWORD number, int value) { int old = fo::var::game_global_vars[number]; if (IsGameLoaded() && HookScripts::HookHasScript(HOOK_SETGLOBALVAR)) { // IsGameLoaded - don't execute hook until loading sfall scripts diff --git a/sfall/Modules/Interface.cpp b/sfall/Modules/Interface.cpp index ca23329c5..19084d425 100644 --- a/sfall/Modules/Interface.cpp +++ b/sfall/Modules/Interface.cpp @@ -1049,7 +1049,7 @@ static void InterfaceWindowPatch() { SafeWriteBatch(127, {0x435160, 0x435189}); // 100 (PrintBigname_) // Increase the max text width of the information card on the character screen - SafeWriteBatch(145, {0x43ACD5, 0x43DD37}); // 136, 133 (DrawCard_, DrawCard2_) + SafeWriteBatch(146, {0x43ACD5, 0x43DD37}); // 136, 133 (DrawCard_, DrawCard2_) // Increase the width of the mouse drop area from 64px to 80px for the PC's and NPC's inventory on the barter screen // barter_move_from_table_inventory_ From c4efe786615987cf6ed870364cb06ac62894cf62 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 13 Mar 2023 14:13:14 +0800 Subject: [PATCH 28/33] Updated readme and added changelog (#451) --- CHANGELOG.md | 919 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 38 ++- 2 files changed, 951 insertions(+), 6 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..c972cfb63 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,919 @@ +# Changelog + +## 4.3.7 +* Dropped support for older **pre-SSE** processors in favor of more optimized code. Now sfall requires a processor with **SSE** support +* Fixed a bug that could prevent loading files from the `art\\` directory +* Fixed `REMOVEINVENOBJ` hook to match the values of `RMOBJ_*` constants correctly +* Fixed **NPC combat control mod** not setting the lighting of controlled critters correctly in some cases +* Expanded `set_pipboy_available` script function to match **PipBoyAvailableAtGameStart** option +* Expanded `message_str_game` script function to support `editor.msg` file +* Increased the default number of sound buffers available for sound effects from 4 to 8 +* Changed the way **AllowDShowSound** works. Now mode 2 is combined with mode 1 +* Removed **MoreTiles** from `ddraw.ini`. Now the maximum number of tile FRMs is always 16383 + +## 4.3.6 +* Minor code fixes and improvements to sfall and engine functions +* Fixed **UseWalkDistance** having no effect when trying to use a ladder +* Fixed `float_msg` script function not setting the purple or black text color correctly +* Changed mode 1 of **NPC combat control mod** to require sfall debugging mode to control all critters in combat +* Added a fix for NPC stuck in a loop of reloading the solar scorcher when out of ammo +* Added an option to **NPC combat control mod** to allow the player to gain a positive reputation while controlling other critters +* Added a boundary check to `set_terrain_name` script function +* New script function: `get_terrain_name` + +## 4.3.5 +* HRP: Fixed movie subtitles not showing up when setting **MOVIE_SIZE=1** with certain combinations of screen and movie aspect ratios +* HRP: Disabled **IFACE_BAR_WIDTH** and **SCALE_BUTTONS_AND_TEXT_MENU** for a modified `fallout2.exe` with Chinese/Japanese support to prevent garbled text +* HRP: Added support for **SPLASH_SCRN_TIME** option in `f2_res.ini` +* Fixed the handling of obsolete script functions that are still recognized by script compiler and decompiler +* Fixed **NPC combat control mod** not redrawing the interface bar properly when it's the player's turn again +* Improved the fix for updating the HP stats of critters on the map when loaded for the first time +* Removed **DivisionOperatorFix** from `ddraw.ini` because there is little reason to turn it off +* Removed **ComputeSprayMod** from `ddraw.ini`. Now **ComputeSpray_\*** options no longer require a master switch +* Added a fix for a crash when the player equips a weapon overloaded with ammo +* Added a fix for being able to use the **'Push'** action on members of the player's team in combat when they are knocked down +* Added missing sounds for the markers on the world map interface (similar to Fallout 1, from Ghosthack) + +## 4.3.4 +* HRP: Fixed a few issues with the main menu +* HRP: Added support for **LocalMapXLimit/LocalMapYLimit** options in `ddraw.ini` +* Removed **FadeBackgroundMusic** option because the fix in 4.3.3 doesn't work reliably in all cases +* Added a fix for being unable to plant items on non-biped critters with the `Barter` flag set (e.g. Skynet and Goris) +* Updated the ammo ini loader mod in the **modders pack** + +## 4.3.3.1 +* HRP: Fixed a possible crash in combat when enabling **EXTRA_WIN_MSG_CHECKS** +* HRP: Fixed broke console messages when enabling **ConsoleOutputPath** +* HRP: Fixed the main menu still being stretched when setting **MAIN_MENU_SIZE=0** +* Fixed a bug introduced in 4.3.1 that caused the game to print an incorrect item name in some cases +* Fixed screenshots for **DX9** graphics modes. Now the screenshots are saved in **PNG** format when in **DX9** mode +* Improved the functionality of **AllowDShowMovies**. Now you can take screenshots and press any key to skip **AVI** movies +* Added a tweak to prevent **'Failure initializing input devices'** error for **built-in HRP/DX9** windowed mode + +## 4.3.3 +* Implemented an **_integrated High Resolution Patch mode_**, which has almost the same functionality as the original hi-res patch and has better integration with sfall's graphics features/improvements +* Fixed a bug introduced in 4.3.1 that broke the fix for party members with drug addictions +* Fixed a bug introduced in 4.3.1 that caused AI to be unable to use some weapons +* Fixed a bug introduced in 4.3.1 that caused the music not to be played after loading a saved game on the same map +* Fixed critical bugs in **FadeBackgroundMusic** that caused crashes in various situations +* Fixed incorrect display of name and damage values for unarmed attacks in the inventory in some cases +* Fixed the black screen issue in **DX9** mode when returning to the game after using `Alt+Tab` +* Fixed the mouse cursor lag in the save/load game screens +* Fixed broken object descriptions for a modified version of `fallout2.exe` that supports Chinese characters +* Fixed and expanded the mouse drop area for the PC's and NPC's inventory on the barter screen +* Changed the **'Radiated'** on the character screen to be highlighted in gray when the player still has an impending radiation effect +* Changed **SkipCompatModeCheck** to not require sfall debugging mode +* Removed **UseCommandLine** from `ddraw.ini`. Now sfall will always check command line arguments for another ini file +* Removed **ArraysBehavior** and **RemoveWindowRounding** from `ddraw.ini` because there is little reason to turn them off +* Removed **SkipSizeCheck** from `ddraw.ini` and the executable file size check from sfall +* Removed the dependency on `d3dcompiler_43.dll` for **DX9** graphics modes +* Added a fix for incorrect value of the limit number of floating text messages +* Added a tweak to allow printing new floating text messages when their limit is exceeded +* Added a debug option to set up a key to toggle the display of the hex grid on the map on or off (like in the mapper) + +## 4.3.2 +* Changed the fix for grave type containers in 4.3.1 to an option, to fix compatibility with existing grave scripts +* Changed **OverrideArtCacheSize** to set the art cache size to 261 instead of 256 +* Changed **Enable** option in the `[Speed]` section to no longer affect **SpeedMultiInitial** +* Tweaked the window title bar for **DX9** windowed mode +* Optimized the calculation process in Glovz's damage formula and Haenlomal's YAAM for burst attacks + +## 4.3.1 +* Fixed the Jet addiction not being removed when using the antidote in some cases +* Fixed the key repeat delay and rate when enabling the game speed tweak +* Fixed a possible crash at the end of the playback of alternative sound files +* Fixed a rounding error in Glovz's damage formula +* Fixed and improved **NPC combat control mod** and the behavior of **SpeedInterfaceCounterAnims=3** +* Improved the rendering performance of **DX9** graphics modes +* Improved and tweaked the page control in **ExtraSaveSlots** +* Changed the way **AutoQuickSave** works. Now it sets the number of pages used for quick saving +* Changed **SingleCore** to set processor affinity to the second processor core if available +* Changed `HOOK_CANUSEWEAPON` hook script to run for both the player and NPCs +* Excluded the walking animation from the debug message about a missing critter art file for stationary critters +* Excluded the animated colors from **TravelMarkerColor** (same as in 3.8.x) +* Removed unnecessary check on action points when AI reloads a weapon (added in 4.3) +* Removed **AffectPlayback** option because it's not practical +* Added a fix for a crash when opening a file with name containing a `%` character +* Added a fix to prevent the main menu music from stopping when entering the load game screen +* Added a fix to display the palette color with index 255 correctly in **DX9** mode when using the hi-res patch +* Added a fix for grave type containers in the open state not executing the `use_p_proc` procedure +* Added a tweak to update unarmed attacks after leveling up +* Added a tweak to keep the selected attack mode for unarmed attacks when closing the inventory or when the combat ends +* Added a tweak to display the actual damage values of unarmed attacks in the inventory +* Added an option to enable fade effects for background music when stopping and starting the playback +* Added an option to automatically search for new **SFX** sound files at game startup +* Added a config file to change the requirements and effects of unarmed attacks +* Added a config file to change some engine parameters for the game mechanics +* Added the ability to continuously play the music when moving to another map that uses the same music +* Added the ability to set custom names for unarmed attacks in the inventory to **TranslationsINI** +* Added support for using the newline control character `'\n'` in the object description in `pro_*.msg` files +* Added support for the new **'Healing Item'** flag to item protos. Now AI will also use items with this flag for healing in combat +* Added support for the new **'Cannot Use'** flag to the misc flags of item objects. This flags makes a weapon object unusable in combat +* Added missing sounds for the buttons on the world map interface (similar to Fallout 1 behavior) +* Added 5 `metarule3` macros for controlling the save slot with scripts to `sfall.h` in the **modders pack** +* New script functions: `set_scr_name`, `obj_is_openable` +* Updated **NPC armor appearance mod** to prevent NPCs from equipping **unusable** weapons +* Included Brazilian Portuguese and Polish translation (from Felipefpl and Jaiden) + +## 4.3.0.2 +* Fixed a bug introduced in 4.3 that caused a hang when opening the pipboy if the value of a quest location in `quests.txt` is less than 1500 +* Fixed a bug introduced in 4.3 that caused a black screen after starting a new game without the hi-res patch +* Fixed a bug in `INVENTORYMOVE` hook that caused duplicate items when canceling moving an item into bag/backpack +* Updated French translation (from HawK-EyE) + +## 4.3.0.1 +* Fixed a crash bug introduced in 4.3 with the fix for animation registration +* Fixed a bug in **AIDrugUsePerfFix** that could cause a hang in combat +* Fixed the extra check for friendly fire not working if the `area_attack_mode` parameter in the AI packet is not set or set to `no_pref` +* Added a fix for `chem_primary_desire` values in party member AI packets not being saved and reset correctly + +## 4.3 +* Fixed the original engine issues with being unable to register animations in certain situations in the game +* Fixed a crash bug introduced in 4.2.9 with the fix for the **'Leave'** event procedure in `AddRegionProc` function +* Fixed a bug in **ObjCanSeeObj_ShootThru_Fix** that could cause a hang in some cases +* Fixed the check of the ammo cost for a shot in **CheckWeaponAmmoCost** +* Fixed `set_critter_burst_disable` script function, which now applies only to weapons with the burst attack as the secondary mode +* Fixed the error handling in `create_object_sid` script function to prevent a crash when the proto is missing +* Fixed `METARULE_CURRENT_TOWN` metarule function not returning the correct index of the current town at the start of a new game +* Fixed the auto-close containers mod for gravesites and not closing containers in some cases (in the **modders pack**) +* Fixed and improved the functionality of **AllowLargeTiles** +* Restored the functionality of `obj_under_cursor` script function for the movement cursor (changed in 4.2.9) +* Improved the **hero appearance mod** to be able to load the interface text from `text\\game\AppIface.msg` +* Improved the functionality of **TranslationsINI** to also search for the ini file relative to the `text\\` directory +* Improved the **'order to attack'** mode in **NPC combat control mod**. Now the target can only be assigned if the party member sees it +* Improved the fix for a duplicate `obj_dude` script being created when loading a saved game +* Rewrote the priority score calculation in **AIBestWeaponFix**, and changed the option to be enabled by default +* Changed **FastShotFix** to be disabled by default +* Removed **DataLoadOrderPatch** from `ddraw.ini` because there is little reason to turn it off +* Added a fix for the script attached to an object not being initialized properly upon object creation +* Added a fix to prevent the player name from being displayed at the bottom of the dialog review window when the text is longer than one screen +* Added a fix for the in-game quest list not being in the same order as in `quests.txt` +* Added a fix for multihex critters hitting themselves when they miss an attack with ranged weapons +* Added a fix to the placement of multihex critters in the player's party when entering a map or elevation +* Added a fix to the starting position of the player's marker on the world map when starting a new game +* Added a fix for AI not checking the safety of weapons based on the selected attack mode +* Added a fix for the incorrect check and AP cost when AI reloads a weapon +* Added a fix to AI behavior to prevent the use of healing drugs when not necessary +* Added a fix for the incorrect object type search when loading a game saved in combat mode +* Added a few fixes for issues with knocked out/down critters. Now the combat doesn't automatically end if the target is only knocked out +* Added a tweak to prevent NPC aggression when non-hostile NPCs accidentally hit the player or members of the player's team +* Added a tweak to play the **'magic hands'** animation when using an item on an object. This also prevents a few issues with scripted animations not playing +* Added a tweak to remove the unspent skill points limit +* Added an option to disable the special handling of city areas 45 and 46 in the engine when visiting Area 45 +* Added a new value to **AIDrugUsePerfFix** to allow NPCs to use only the drugs listed in `chem_primary_desire` and healing drugs +* Added support for loading premade character **GCD/BIO** files from the `premade\\` directory for non-English languages +* Added support for loading fonts from the `fonts\\` directory for non-English languages +* Added a debug option to control messages relating to engine fixes in the debug log +* Added a debug message about a missing combat object +* Added a new argument to `HOOK_CALCAPCOST` hook script +* New script function: `set_quest_failure_value` +* New hook scripts: `hs_bestweapon`, `hs_canuseweapon` +* Updated **NPC armor appearance mod** to prevent NPCs from picking up and trying to equip disallowed weapons in combat +* sfall can now load a localized `sfall_xx.dat` resource file instead of the default `sfall.dat` + +## 4.2.9 +* Fixed the critical hits from unaimed shots not matching the ones from aimed torso shots for some critter types +* Fixed the display issue in **DX9** mode when returning to the game after using `Alt+Tab` in dialogue +* Fixed `obj_under_cursor` script function, which now returns 0 if the cursor is in movement mode +* Improved compatibility with some older **DX9** graphics cards +* Changed `intface_redraw` script function with one argument to be able to redraw the specified interface window +* Changed `HOOK_DESCRIPTIONOBJ` hook script to run for all types of objects, not just the items +* Changed the filename of the debug editor to `FalloutDebug.exe` (in the **modders pack**) +* Excluded **SFX** sounds from the search for alternative formats +* Removed the tweak that adds the city name in the description for empty save slots (added in 4.2.7) +* Added a fix to update the maximum HP stat of critters on the map when loaded for the first time +* Added a fix to the poison/radiation-related engine functions when taking control of an NPC +* Added a fix to AI weapon switching when not having enough action points. Now AI will try to change attack mode before deciding to switch weapon +* Added a fix for the carry weight penalty of the **Small Frame** trait not being applied to bonus Strength points +* Added a fix for the flags of non-door objects being set/unset when using `obj_close/open` script functions +* Added a fix for the **'Leave'** event procedure in `AddRegionProc` function not being triggered when the cursor moves to a non-scripted window +* Added support for **ACM** files at 44.1 kHz sample rate +* Added stereo support for **SFX** and speech **ACM** files at 44.1 kHz sample rate +* Added support for panning **SFX** sounds and reduced the volume for objects located on a different elevation of the map +* Added more options for tweaking some engine perks to the **perks ini file** +* Added options for tweaking tag skills to the **skills ini file** +* Added an option about the behavior of maximum HP calculation to the **stats ini file** +* Added 3 new attribute type values to `get_window_attribute` script functions +* Added additional universal opcodes `sfall_func7` and `sfall_func8` (`compile.exe` and `int2ssl.exe` in the **modders pack** are also updated) +* Added a new mode to **NPC combat control mod** to let you order party members to attack specified targets instead of controlling them directly +* Added an auto-close containers mod to the example mods in the **modders pack** +* Added `snd2acm_fix.exe` (snd2acm with a fix wrapper) to the **modders pack** for writing the correct sample rate and channel info from **WAV** files to **ACM** format +* New script functions: `interface_overlay` +* New hook scripts: `hs_adjustpoison`, `hs_adjustrads`, `hs_rollcheck` + +## 4.2.8.1 +* Fixed a few minor bugs introduced in 4.2.8 +* Added support for drawing **PCX** images to `draw_image`, `draw_image_scaled`, and `interface_art_draw` script functions +* New script function: `win_fill_color` +* Cleaned up `define_lite.h` and `command_lite.h` in the **modders pack** + +## 4.2.8 +* Fixed a bug in **ObjCanSeeObj_ShootThru_Fix** that caused the source to be unable to see the target if it has the `ShootTrhu` flag set +* Fixed the encounter messages still being limited to 50 entries per table when **EncounterTableSize** is set to greater than 50 +* Fixed temporary arrays in scripts being cleared when flushing the keyboard buffer +* Improved the field of view check in **ObjCanSeeObj_ShootThru_Fix** +* Improved the functionality of **GlobalShaderFile** to be able to load multiple shader files +* Improved the performance of **DX9** graphics modes +* Extended the upper limit of `set_pickpocket_max` and `set_hit_chance_max` script functions to 999 +* Expanded `get_window_attribute` script function to support the automap interface window +* Removed the check for valid objects from `get/set_object_data` script functions to make them work with other structured data +* Removed **KeepWeaponSelectMode** and **InterfaceDontMoveOnTop** from `ddraw.ini` because there is little reason to turn them off +* Added a fix for the engine building the path to the central hex of a multihex object +* Added a fix for the flags of critters in the line of fire not being taken into account when calculating the hit chance penalty of ranged attacks +* Added a fix to the check for ranged weapons in the **Fast Shot** trait and **FastShotFix** +* Added a fix for the background image of the character portrait on the player inventory screen +* Added a fix for the broken `Print()` script function +* Added the original Fallout 1 behavior of the **Fast Shot** trait to **FastShotFix** +* Added an option to enable linear texture filtering for **DX9** graphics modes +* Added support for **ACM** audio file playback and volume control to `soundplay` script function +* Added support for transparent interface/script windows +* Added the ability to change the poison level for NPCs to `poison` and `set_critter_stat` script functions +* Added the ability for controlled critters to use Sneak skill in combat +* Added a volume control to reduce the volume for `play_sfall_sound` script function +* Added an argument to `intface_redraw` script function to redraw all interface windows +* Added a new argument to `HOOK_TOHIT` hook script +* Added a new argument to `HOOK_COMBATDAMAGE` hook script +* Added a new hook type to `HOOK_WITHINPERCEPTION` hook script (when AI determines whether it sees a potential target) +* Added two sharpen filter files as global shader examples to the **modders pack** +* New script functions: `interface_art_draw`, `interface_print`, `combat_data` +* Updated the ammo ini loader mod in the **modders pack** + +## 4.2.7 +* Fixed the default values for **Movie1 - Movie17** options +* Fixed the playback of additional movies defined in **Movie18 - Movie32** options +* Fixed **OverrideMusicDir=2** not overriding the music path properly +* Fixed incorrect Melee Damage stat value being displayed in some cases when setting **BonusHtHDamageFix=1** and **DisplayBonusDamage=0** +* Fixed `attack_complex script` function not setting result flags correctly for the attacker and the target +* Fixed and improved **SFX** and speech playback for alternative sound files +* Fixed and improved the behavior of nested timer events in global scripts +* Improved the functionality of **AllowDShowMovies**: added volume control support and a new value to force **AVI** videos to fit the screen width, and fixed movie subtitles not showing up +* Changed **AttackComplexFix** to make `attacker_results` and `target_results` arguments work independently of each other +* Changed **ObjCanSeeObj_ShootThru_Fix** to allow critters to see through other critters and added a check for the direction the source is facing +* Changed the behavior of replacing FRM aliases for critters. Now FRM files from their aliases are taken only if the critter doesn't have its own files +* Added a fix for `ANIM_charred_body`/`ANIM_charred_body_sf` animations not being available to most appearances +* Added a fix to remove floating text messages on the map when moving to another map elevation +* Added a fix for a visual glitch on the black edges of the map when the map borders for the hi-res patch are set smaller than the screen size +* Added a fix to prevent the execution of `critter_p_proc` and game events when playing movies +* Added a fix to prevent crashes and loading maps when the death animation causes the player to cross an exit grid +* Added a fix to limit the maximum distance for the knockback animation to 20 hexes +* Added a tweak to allow setting custom colors from the game palette for object outlines +* Added a tweak to add the city name in the description for empty save slots +* Added an option to use Fallout's normal text font for death screen subtitles +* Added a debug message about a corrupted proto file +* Added a function extension for vanilla `metarule3` function and added `set_horrigan_days` and `clear_keyboard_buffer` macros to sfall.h in the **modders pack** +* Added `DAM_PRESERVE_FLAGS` flag to `attack_complex` script function to keep the existing result flags when setting new flags +* Updated the example global shader file in the **modders pack** +* Updated German and Russian translations + +## 4.2.6 +* Fixed a **hero appearance mod** issue that caused the player's gender not to be reset properly when creating a new character +* Fixed a **hero appearance mod** issue that caused the player to lose some fire/electrical death animations +* Fixed a bug introduced in 4.2.3 that broke the **PlayIdleAnimOnReload** option +* Improved the pathfinding in the engine function when a multihex object is in the line of fire +* Improved the functionality of `display_stats` script function to also update player's stats on the character screen +* Improved the fix for incorrect positioning after exiting small/medium locations +* Removed **AutoSearchPath** from `ddraw.ini`. Now the folder path for autoloading custom files is the fixed **\\mods\\** +* Added a fix to prevent critters from overlapping other object tiles when moving to the retargeted tile +* Added a fix to prevent showing an empty perk selection window (crash when clicking on the empty perk list) +* Added a fix for NPC stuck in an animation loop in combat when trying to move close to a multihex critter +* Increased the maximum text width of the player name on the character screen +* New script functions: `get_stat_max/min` + +## 4.2.5.1 +* Fixed the extra check for friendly fire treating non-critter objects as friendly critters +* Changed the debug message about missing art file for critters to be displayed in game only when in sfall debugging mode + +## 4.2.5 +* Fixed a bug introduced in 4.1.9 that could cause the combat to end automatically in some cases +* Fixed a bug introduced in 4.2 that caused AI to miscalculate the hit chance in determining whether to use secondary attacks if **BodyHit_Torso** and **BodyHit_Torso_Uncalled** modifiers were not equal +* Fixed a bug introduced in 4.2.3 that caused **CorpseDeleteTime** not to set the timer correctly +* Fixed a bug introduced in 4.2.4 that caused **AllowDShowSound=2** not to work +* Fixed `loot_obj` script function not returning the correct object when switching to another corpse in the loot screen +* Fixed and improved the functionality of **ReloadWeaponKey** for using any non-weapon item +* Fixed and changed the behavior of **GvarID** option in the **drugs ini file** +* Improved the fix for items on the ground being obscured by a pool of blood after the corpse is removed +* Changed the priority of files in the **AutoSearchPath** folder to be higher than the **PatchFileXX** options +* Added a fix for AI skipping a target simply because its weapon is currently empty +* Added a fix for AI not always considering the safe distance when using grenades or rockets +* Added a fix to AI behavior for **'Snipe'** distance preference (`distance=snipe` in `AI.txt`). Now the attacker will try to shoot the target instead of always running away from it at the beginning of the turn +* Added a fix to reduce friendly fire in burst attacks. Now there is an extra roll for AI to not use burst attacks if a friendly critter is in the line of fire +* Added a check for the weapon range and the AP cost when AI is choosing weapon attack modes +* Added a tweak to allow party members to keep their current target as one of the potential targets when choosing new targets at the beginning of their turn +* Added a tweak to the displayed message if the main target of a missed attack has the **'Flat'** flag set + +## 4.2.4 +* Fixed stuttering when playing **AVI** movies +* Fixed a crash when playing **MVE** movies in **DX9** mode with the CPU doing the palette conversion and without the hi-res patch +* Fixed a crash when using older versions of the hi-res patch +* Fixed a possible crash or player's turn being skipped when returning to the game after using `Alt+Tab` in combat +* Fixed a bug introduced in 4.1.9 that could cause a hang when loading a saved game +* Fixed `COMBATTURN` hook not being triggered when loading a saved game in combat +* Fixed and improved the playback of alternative sound files +* Re-added **TownMapHotkeysFix** option to `ddraw.ini` for mod testing +* Changed `play/stop_sfall_sound` script functions to return/accept the **ID** number of the played sound instead of a raw pointer +* Changed the **'Radiated'** on the character screen to be highlighted in red color when player's stats are affected by radiation exposure +* Added a new **'fullscreen windowed'** mode to **DX9** graphics modes +* Added saving the position of the game window to `ddraw.ini` +* Added a fix for the player's money not being displayed in the dialog window after leaving the barter/combat control interface +* Added a fix for a crash or animation glitch of the critter in combat when an explosion from explosives and the AI attack animation are performed simultaneously +* Added a fix for the **'Fill_W'** flag in `worldmap.txt` not uncovering all tiles to the left edge of the world map +* Added a fix for leaving the map after reloading a saved game if the player died on the world map from radiation +* Added a fix to prevent the player from dying if a stat is less than 1 when removing radiation effects +* Added a fix for the same effect message being displayed when removing radiation effects +* Added a fix for NPCs not fully reloading a weapon if it has an ammo capacity larger than one box of ammo +* Added an option to display messages about radiation for the active geiger counter +* Added an option to change the displayed message when you recover from the negative effects of radiation exposure +* Added a new value to **AllowUnsafeScripting** to disable the memory address check in unsafe script functions +* Added a new value of 3 to the **'mark_state'** argument of `mark_area_known` script function to uncover locations without radius (Fallout 1 behavior) +* Added a new mode to `play_sfall_sound` script function + +## 4.2.3 +* Fixed the timing of setting `WORLDMAP`, `DIALOG`, `PIPBOY`, `INVENTORY`, `INTFACEUSE`, and `INTFACELOOT` game mode flags +* Fixed the execution of the timer event in global scripts +* Fixed the palette and the movie playback in **DX9** mode +* Improved the functionality of `create_message_window` script function to support the newline control character `'\n'` +* Removed **TownMapHotkeysFix** and **DisplaySecondWeaponRange** from `ddraw.ini` because there is little reason to turn them off +* Added a fix for duplicate critters being added to the list of potential targets for AI +* Added a fix for the playback of the speech sound file for the death screen being ended abruptly in some cases +* Added a fix for the barter button on the dialog window not animating until after leaving the barter screen +* Added a fix for the division operator treating negative integers as unsigned +* Added a fix for trying to loot corpses with the **'NoSteal'** flag +* Added an option to allow using the special `'^'` character in dialog msg files to specify the alternative text that will be displayed in the dialogue based on the player's gender +* Added options to draw a dotted line while traveling on the world map (similar to Fallout 1, from Ghosthack) +* Added an option to display terrain types when hovering the cursor over the player's marker on the world map (from Ghosthack) +* Added a flashing icon to the horrigan encounter and scripted force encounters by default +* Added new flags to `force_encounter_with_flags` script function +* Added a procedure and macros for comparing unsigned integers to `lib.math.h` in the **modders pack** +* Increased the maximum text width of the total weight display in the inventory +* New script functions: `string_to_case`, `set_terrain_name`, `get_window_attribute`, `set_town_title`, `message_box`, `div` operator (unsigned integer division) +* New hook script: `hs_encounter` + +## 4.2.2 +* Fixed `GAMEMODECHANGE` hook being triggered in dialog even when the game mode is not changed +* Fixed the return value of `charcode` script function for characters in the extended ASCII character set +* Fixed the return value of `get_script` script function +* Fixed and improved the functionality of `substr` script function +* Restored and fixed **RemoveWindowRounding** option that was removed in 4.1.2 +* Improved the functionality of `inventory_redraw` script function +* Changed the way **IniConfigFolder** works. Now the game will search for the ini files relative to the specified directory +* Changed the debug message about missing art file for critters to also be displayed in game +* Code refactoring for various script functions +* Added a fix to prevent the player from moving when clicking on a script-created window and prevent the mouse cursor from being toggled when hovering over a **'hidden'** window +* Added a fix to prevent crashes when **DebugMode** is enabled and there is a **'%'** character in the printed message +* Added an option to load a global shader file at game startup and added an example global shader file to the **modders pack** +* Added support for executing the `timed_event_p_proc` procedure in global scripts +* Added `SPECIAL` flag to the game mode functions (when switching from dialog mode to barter mode, or a party member joins/leaves in the dialog screen) +* Added a new argument to `HOOK_GAMEMODECHANGE` hook script +* New game hook: `HOOK_STDPROCEDURE_END`, as an extension to `HOOK_STDPROCEDURE` hook script +* New script functions: `add_g_timer_event`, `remove_timer_event`, `reg_anim_callback`, `get_sfall_arg_at`, `hide/show_window`, `set_window_flag`, `get_text_width`, `string_compare`, `string_format`, `objects_in_radius`, `tile_by_position` +* New hook script: `hs_targetobject` + +## 4.2.1.1 +* Fixed a crash bug introduced in 4.2.1 with the fix for corpses blocking line of fire + +## 4.2.1 +* Fixed a bug in `save_array` script function that could corrupt `sfallgv.sav` when saving a new array under the same key +* Fixed a crash bug in **PremadePaths** when a name exceeds 11 characters +* Fixed `move_obj_inven_to_obj/drop_obj` script functions not removing the equipped armor properly for the player and party members +* Fixed `inven_unwield` script function not updating the active item button on the interface bar for the player +* Fixed `art_change_fid_num` script function not setting player's FID correctly when the **hero appearance mod** is enabled +* Fixed `critter_add/rm_trait` script functions ignoring the value of the **'amount'** argument. Note: pass negative amount values to `critter_rm_trait` to remove all ranks of the perk (vanilla behavior) +* Fixed the xp bonus set by `set_swiftlearner_mod` script function not being reset on game load +* Fixed the player name while controlling other critters +* Fixed **NPC combat control mod** not removing the inherited perks from controlled critters properly +* Improved the display of the car fuel gauge on the world map interface +* Improved the **hero appearance mod** to search for files in **.dat** files and folders simultaneously +* Improved `HOOK_INVENWIELD` hook script to run for the player and NPCs when removing equipped items, and added a new argument to it +* Expanded `set_critter_stat` script function to allow changing the base stats of `STAT_unused` and `STAT_dmg_*` for the player, and `STAT_unused` for other critters +* Changed **AllowUnsafeScripting** to not require sfall debugging mode +* Removed **NPCStage6Fix** and **CorpseLineOfFireFix** from `ddraw.ini` because there is little reason to turn them off +* Added a fix to prevent the player from equipping a weapon when the current appearance has no animation for it +* Added a fix to use **'English'** as the fallback language directory for loading msg files +* Added a fix for party member's equipped weapon being placed in the incorrect item slot after leveling up +* Added a new value to **AIBestWeaponFix** to change the priority multiplier for having weapon perk to 3x (the original is 5x) +* Added a new flag to **MainMenuFontColour** to only change the font color of the Fallout/sfall version text +* Added optional options to enable modification sections for perks and traits to the **perks ini file** +* Added support for displaying AP cost up to 19 on the active item button on the interface bar +* Added a check for valid objects to `get/set_object_data` script functions +* Added a debug message about a missing critter art file to **DebugMode** +* New script functions: `unwield_slot`, `add_trait`, `get_inven_ap_cost` +* Updated **NPC armor appearance mod** and added an alternative `npcarmor.ini` for vanilla Fallout 2 (in the **modders pack**) + +## 4.2 +* Fixed a bug in **XPTable** that prevented the player from reaching the highest specified level +* Fixed `create_message_window` script function to prevent it from creating multiple message windows +* Fixed `obj_art_fid` script function returning incorrect player's FID when the **hero appearance mod** mod is enabled +* Fixed a crash bug in `message_str_game` script function when passing a negative fileId value +* Fixed **MainMenuFontColour** not changing the font color of the copyright text on the main menu +* Fixed a **hero appearance mod** mod issue that caused the incorrect FRM to be displayed when opening bag/backpack in the inventory +* Fixed some arguments in `BARTERPRICE` hook when trading with a party member +* Fixed a crash bug introduced in 4.1.8 when calling `game_time_advance` in the `map_exit_p_proc` procedure with active explosives on the map +* Fixed some of sfall features that depend on the hi-res patch not working properly in some cases +* Fixed a bug introduced in 4.1.8 that broke the **AllowLargeTiles** option +* Fixed the AP cost display issue in **NPC combat control mod** +* Improved the functionality of `add_extra_msg_file` script function to use **'English'** as the fallback language directory for loading msg files +* Changed the `DAM_BACKWASH` flag to be set for the attacker before calculating combat damage when taking self-damage from explosions +* Changed **CorpseLineOfFireFix** to be enabled by default +* Removed the dependency of **Body_Torso** from **Body_Uncalled** hit modifier, and re-added **BodyHit_Torso** to `ddraw.ini`. Now you can use `set_bodypart_hit_modifier` script function to set them individually +* Replaced the **'Take All'** hotkey mod with an extended UI hotkeys mod in the **modders pack** +* Added a fix to prevent the car from being lost when entering a location via the Town/World button and then leaving on foot +* Added a fix for items on the ground being obscured by a pool of blood after the corpse is removed +* Added a fix for player's position if the entrance tile is blocked when entering a map +* Added a fix for the player stuck at **'climbing'** frame after ladder climbing animation +* Added an option to change the path and filename of the critical table file +* Added an option to change the font color of the button text on the main menu +* Added an option to override the path location of all ini files used by scripts +* Added an option to change some of Fallout 2 engine functions to Fallout 1 behavior +* Added support for the new **'Energy Weapon'** flag to weapon protos. This flag forces the weapon to use Energy Weapons skill regardless of its damage type +* Added options for tweaking some engine perks to the **perks ini file** +* Added a new flag to `force_encounter_with_flags` script function +* Added `COUNTERWIN` flag to the game mode functions (when moving multiple items or setting a timer) +* Added a new argument to `HOOK_ADJUSTFID` hook script +* Added a new argument to `HOOK_BARTERPRICE` hook script +* Added a compute damage example script to the **modders pack** +* Slightly increased the width of the car fuel gauge on the world map interface +* New script function: `register_hook_proc_spec` +* New hook script: `hs_stdprocedure` +* +## 4.1.9.1 +* Fixed the error handling for loading `sfallgv.sav` to improve backward compatibility with older saved games +* Fixed `key_pressed` script function not working in `HOOK_KEYPRESS` hook script +* Fixed a bug in **NPC combat control** that caused perks picked in combat to disappear after switching control to other critters +* Fixed a bug in **NPC combat control** that caused player's selected weapon mode not to be saved +* Fixed the map elevation check in `get/set_can_rest_on_map` script functions +* Improved the functionality of `add_extra_msg_file` script function to allow automatically assigning numbers to msg files +* Changed **DebugMode** and **HideObjIsNullMsg** to not require sfall debugging mode +* Added an option to **NPC combat control mod** to let you set a list of perks to be inherited from the player + +## 4.1.9 +* Fixed some scrolling bugs in **WorldMapSlots** option +* Fixed fade in/out of the screen in **DX9** mode (partially) +* Fixed `get/set_critter_base/extra_stat` script functions not accepting a pointer to the player +* Fixed `set_dude_obj` script function not accepting a null argument +* Fixed a crash bug in `COMBATTURN` hook when loading a game saved in combat mode while controlling other critters +* Fixed a bug in **NPC combat control mod** that caused the last controlled critter to get player's combat xp +* Fixed the last procedure in a script being unable to be called through a variable containing its name as a string +* Fixed a bug introduced in 4.1.8 that caused the `DAM_KNOCKED_DOWN` flag not to be reset for knocked out party members when leaving a map +* Improved **NPC combat control** to keep the selected weapon mode of the controlled critter +* Improved the functionality of the debug editor (in the **modders pack**) +* Improved the fix for **'NPC turns into a container'** bug +* Changed **DataLoadOrderPatch** to be enabled by default +* Changed **ItemCounterDefaultMax** to not set the counter to maximum when in the barter screen +* Added a fix for the broken **'reserve movement'** function +* Added a fix for the up/down button images on the world map interface +* Added a fix for the position of the destination marker for small/medium location circles when using the location list +* Added a fix for player's movement in combat being interrupted when trying to use objects with **Bonus Move** APs available +* Added a fix for the incorrect coordinates for small/medium location circles that the engine uses to highlight their sub-tiles +* Added a fix for visited tiles on the world map being darkened again when a location is added next to them +* Added a fix for **Scout** perk being taken into account when setting the visibility of locations with `mark_area_known` script function +* Added a fix for combat not ending automatically when there are no hostile critters +* Added a fix for critters/items on a map having duplicate object IDs +* Added a fix for knocked down critters not playing stand up animation when the combat ends +* Added a fix for dead NPCs reloading their weapons when the combat ends +* Added an option to use the expanded world map interface (requires hi-res patch v4.1.8) +* Added an option to allow to set a folder path for the game to automatically search and load custom **.dat** files +* Added an option to expand the number of action points displayed on the interface bar +* Added an option to change the base value of the duration of the knockout effect +* Added a check for the `DAM_KNOCKED_OUT` flag to `wield_obj_critter/inven_unwield` script functions +* Added a new value to **SkipOpeningMovies** to also skip the splash screen +* Added a new **'combat ends normally'** event to `HOOK_COMBATTURN` hook script +* Added a `sfall.dat` resource file, which contains the required files for various features +* New script functions: `metarule_exist`, `add_extra_msg_file` + +## 4.1.8.1 +* Fixed a bug introduced in 4.1.4 that could crash the game when calling knockback modifier functions +* Improved compatibility with older processors (**pre-SSE2**) + +## 4.1.8 +* Fixed broken `get/mod_kill_counter` script functions when **ExtraKillTypes** is enabled +* Fixed the argument value of `dialogue_reaction` script function +* Fixed getting perks and traits from the real **dude_obj** while controlling other critters +* Fixed the position of the items in active item slots after ending control of the critter +* Improved the fix for the removal of party member's corpse to prevent save file corruption. Now party member's corpse is removed in the same way as all other critter corpses +* Changed the engine functions for saving party member protos and removing the drug effects for NPC to be called after executing the `map_exit_p_proc` procedure +* Changed `create_message_window` script function to be available when other game interfaces are opened +* Removed **DialogOptions9Lines** from `ddraw.ini` because there is little reason to turn it off +* Removed **LoadProtoMaxLimit** from `ddraw.ini`. Now the proto limit is automatically increased when needed +* Added a fix for party member's stats being reset to the base level when their base protos with the read-only attribute set are placed in the **proto\critters\\** directory +* Added a fix for NPC stuck in a loop of picking up items in combat and the incorrect message being displayed when the NPC cannot pick up an item due to not enough space in the inventory +* Added a fix to allow fleeing NPC to use drugs +* Added a fix for AI not checking minimum HP properly for using stimpaks +* Added a fix for NPC stuck in fleeing mode when the hit chance of a target was too low +* Added a fix to prevent fake perks from being added to all controlled critters +* Added a missing option for testing **AllowSoundForFloats** to the **[Debugging]** section of `ddraw.ini` +* Added a new **'dropping item on the character portrait'** event to `HOOK_INVENTORYMOVE` hook script +* Added an ammo ini loader mod to the example mods in the **modders pack** +* Slightly increased the maximum text width of the information card on the character screen +* New script functions: `draw_image`, `draw_image_scaled`, `set_fake_perk/trait_npc`, `set_selectable_perk_npc`, `has_fake_perk/trait_npc` + +## 4.1.7 +* Implemented a **critter individualization** system. Each critter has its own independent base/bonus stats, separated from other critters sharing the same PID. Now `set_critter_base/extra_stat` script functions only set stats for a specific critter +* Fixed the argument numbering in error messages when validating arguments +* Fixed the weapon duplication bug in **NPC combat control mod** +* Fixed a bug in **CheckWeaponAmmoCost** that caused NPCs not to switch to other weapons when there is not enough ammo to shoot +* Fixed fake perks not stacking properly +* Fixed the position of the 32-bit talking heads when the game resolution is higher than 640x480 +* Fixed a bug in **item highlighting** that caused items to be kept highlighted when picking them up while holding the highlight key +* Changed `hero_select_win` function to require an `AppHeroWin.frm` file (included in the **modders pack**) in the **art\intrface\\** directory +* Added a fix for unexplored areas being revealed on the automap when entering a map +* Added a fix for the overflow of the automap tables when the number of maps in `maps.txt` is more than 160 +* Added a fix for a duplicate `obj_dude` script being created when loading a saved game +* Added a fix to prevent the reserved object IDs of the player and party members from being generated for other objects +* Added a fix for the display issue in the pipboy when the automap list is too long +* Added a fix for the `start` procedure not being called correctly if the required standard script procedure is missing (from Crafty) +* Added an option to disable the special handling of map IDs 19 and 37 in the engine when entering the maps +* Added support for the new **'automap=yes/no'** parameter to `maps.txt`. This parameter overrides the hardcoded values for displaying the map in the pipboy automaps for the first 160 maps +* Added a new **'picking up item'** event to `HOOK_INVENTORYMOVE` hook script +* Added files for using 32-bit images for talking heads to the **modders pack** +* Improved the functionality of the debug editor (in the **modders pack**) +* Improved the functionality of **Use32BitHeadGraphics** to allow using 32-bit images without having to patch talking head FRM files +* The number of simultaneously displayed notification boxes now depends on the game resolution +* New script function: `set_unique_id` +* New hook script: `hs_sneak` + +## 4.1.6 +* Fixed a crash bug introduced in 4.1.5 when using various inventory items while a **books ini file** is loaded +* Fixed the return value of `has_skill` script function for incorrect skill numbers +* Fixed the negative skill points of a skill not being taken into account when calculating the skill level +* Fixed incorrect skill point cost for negative skill levels when using a **skills ini file** +* Fixed the screen not returning to the player when moving a controlled critter to another elevation of the map +* Fixed some functionality issues of fake perks +* Fixed the broken `get_perk_available` script function +* Fixed the lighting of controlled critters in **NPC combat control mod** +* Fixed the return FID in **NPC armor appearance mod** (in the **modders pack**) +* Expanded `get/inc_npc_level` script functions to accept party member PIDs +* Removed **MultiPatches** from `ddraw.ini`. Now Fallout always loads multiple patch files at once +* Added a fix for the reserved item FRM being displayed in the top-left corner when in the loot/barter screens +* Added a fix for the active effects of drugs not being saved properly +* Added a fix for NPC stuck in a loop of reloading melee/unarmed weapons when out of ammo +* Added a fix for critters not being healed over time when entering the map if **'dead_bodies_age=No'** is set in `maps.txt` +* Added a fix for corpses being removed early after returning to the map +* Added a fix for the removal of party member's corpse. Now items in party member's inventory are not removed along with the corpse +* Added an option to change the timer for deleting corpses on a map after you leave +* Added an option to override the global variable number used to show the special death message of the Modoc toilet explosion +* Added a new **[ExtraPatches]** section to allow to set multiple custom paths for loading game data +* Added a config file to change some parameters for drugs and their addictions +* Added displaying the NPC's addictions on the character screen when controlled by the player +* Added the ability to add extra non-scripted perks to the **perks ini file** +* Added support for extra perks to `has_fake_perk/get_perk_available` script functions +* Added a new argument to `HOOK_REMOVEINVENOBJ` hook script +* New script functions: `add_iface_tag`, `npc_engine_level_up`, `set_drugs_data` +* Updated **NPC combat control mod** to be able to automatically set the number for the notification box + +## 4.1.5 +Various bug fixes and features based on the work by Mr.Stalin: +* Fixed a hang on startup if there is an invalid character for SPECIAL stats in the `skills ini` file +* Fixed `set_self` function for `use_obj_on_obj`, `attack`, and `attack_complex` vanilla functions +* Fixed `attack_complex` script function still causing minimum damage to the target when the attacker misses +* Fixed `critter_mod_skill` script function taking a negative amount value as a positive +* Fixed a crash when calling `use_obj/use_obj_on_obj` without using `set_self` in global scripts +* Fixed `pickup_obj`, `drop_obj`, and `use_obj` script functions not working properly in some cases +* Fixed **TimeLimit=-3** not returning the correct year, and removed the setting value of -2 (Now it works the same as -3) +* Fixed the mouse cursor lag on the world map when **WorldMapFPSPatch** is enabled +* Fixed issues with the game speed tweak. Now the game speed will be temporarily set to normal speed when in the inventory or dialogue, and it doesn't affect the endgame slideshow +* Fixed and improved the functionality of **UseFileSystemOverride** and `fs_*` script functions +* Improved the functionality of `get/set_sfall_global` script functions to print error messages to debug output if the name of sfall global variable is not 8 characters long +* Improved the error handling for saving/loading sfall data files in savegames +* Expanded `abs` math script function to support returning integers +* Added a fix for critters not attacking the player in combat when loading a game saved in combat mode +* Added a fix for player's turn being skipped when loading a game saved in combat mode +* Added an option to fix and repurpose the unused **called_shot/num_attacks** arguments of `attack_complex` script function +* Added an option to make the game speed tweak also affect the playback speed of **MVE** video files without an audio track +* Added a debugging option to hide error messages in debug output when a null value is passed to the function as an object +* Increased the maximum number of books in **BooksFile** to 50 +* New script function: `art_cache_clear` + +## 4.1.4.1 +* Fixed a bug introduced in 4.1.4 that broke the calculation of the skill point cost for increasing skill levels (from Mr.Stalin) + +## 4.1.4 +* Fixed a bug in **NPC armor appearance mod** (in the **modders pack**) that caused other critters to be unable to attack with weapons + +Various bug fixes and features based on the work by Mr.Stalin: +* Fixed a crash bug when using sorting functions on an associative array +* Improved the functionality of **ElevatorsFile** to allow changing the FRM images of the elevator panel and creating new elevator types +* Expanded `resize_array` function to support sorting associative arrays by keys or values +* Expanded `create/temp_array` functions to allow creating a new **'lookup'** type of associative array +* Changed `INVENTORYMOVE` hook to be called before displaying the **'Move Items'** window for dragging and dropping ammo on weapons +* Added a fix to prevent sfall from trying to load global scripts with an extension that exceeds three characters (e.g. gl_test.int123) +* Added a fix to the following script functions to ensure they set the correct object: `set_critter_burst_disable`, `set_critter_pickpocket_mod`, `set_critter_skill_mod`, `set_critter_hit_chance_mod`, `set_*_knockback` +* Added a debug option to force sfall to search for global scripts every time the game loads rather than only once on the first game start +* Added an option to change the distance at which the player will switch to walking when trying to use objects or pick up items +* New hook script: `hs_setlighting` + +## 4.1.3 +* Changed **PartyMemberExtraInfo** to not show **'Addict'** text (in dark green) on the combat control panel if the party member is not addicted to drugs +* Changed `read_byte`, `read_short`, `read_int`, and `read_string` script functions to not require **AllowUnsafeScripting** +* Changed **AutoQuickSave** to use the current selected page if **AutoQuickSavePage** is disabled + +Various bug fixes and features based on the work by Mr.Stalin: +* Fixed a bug introduced in 4.1 that broke the return values of `HOOK_FINDTARGET` hook script +* Fixed the missing return value of -1 for `HOOK_USEOBJON` hook script +* Fixed the order of loading global scripts from multiple paths +* Fixed the return values of a hook getting corrupted if another hook was called during the execution of the current hook +* Fixed a bug in the **hero appearance mod** mod that caused the player to disappear after saving the game when player's base FID is greater than 255 +* Changed how `HOOK_FINDTARGET` hook script handles its return values. Now you don't have to specify all 4 targets to override normal sorting +* Added a fix for being unable to sell/give items in the barter screen when the player/party member is overloaded +* Added a fix for AI still taking distance into account when calculating hit chance using the **'no_range'** flag +* Added a fix for AI not taking `chem_primary_desire` in `AI.txt` as drug use preference when using drugs in their inventory +* Added a fix to display a pop-up message box about **death from radiation** +* Added a fix to prevent hook scripts from being executed when the depth limit is exceeded, or the hook is called recursively +* Added a new value to **SpeedInterfaceCounterAnims** to update the AC counter instantly when switching to other controlled critters in combat +* New script functions: `obj_under_cursor`, `loot_obj`, `get/set_object_data`, `get_object_ai_data` +* New hook script: `hs_subcombatdmg` + +## 4.1.2 +* Updated **NPC combat control mod** to work with **BoxBarCount** and prevent Marcus and non-biped critters from equipping armor when controlled by the player +* Updated **item highlighting mod** to be disabled while in the loot screen +* Changed the debug editor to require sfall debugging mode +* Removed **RemoveWindowRounding** from `ddraw.ini` because it doesn't affect anything + +Original engine bug fixes and various features based on the work by Crafty: +* Added a fix for **Heave Ho!** perk increasing Strength stat above 10 when determining the maximum range of thrown weapons +* Added an option to display party member's current level/AC/addict flag on the combat control panel +* Added a new value to **DebugMode** to send debug output to both the screen and `debug.log` +* Added a new return value to `HOOK_KEYPRESS` hook script to override the pressed key + +Various bug fixes and features based on the work by Mr.Stalin: +* Fixed **DX9** mode not showing movie subtitles properly when not using the hi-res patch +* Fixed **DisplayBonusDamage** not being applied to Melee Damage stat on the character screen when **BonusHtHDamageFix** is enabled +* Improved the functionality of **ExtraSaveSlots**: added sound effect when clicking on the navigation buttons +* Improved the fix for `start_gdialog` script function to fix a crash if calling `start_gdialog` outside of the `talk_p_proc` procedure for talking heads +* Added a fix for the exploit that allows you to gain excessive skill points from **Tag!** perk before leaving the character screen +* Added an option to change the limit of how many protos per type can be loaded into memory at once, and improved the functionality of `set_proto_data` script function to be able to automatically increase the limit when needed +* Added an option to skip the **'Move Items'** window when taking items from containers or corpses and not holding down **ItemFastMoveKey** +* Added an option to skip loading game settings from saved games +* Added an option to fix the bug of using First Aid/Doctor skills when using them on the player +* Added 4 new modes to `metarule2_explosions` function +* New script functions: `item_make_explosive`, `dialog_obj` +* New hook scripts: `hs_useskillon`, `hs_onexplosion` + +## 4.1.1 +Original engine bug fixes based on the work by Crafty: +* Added a fix for the encounter description being displayed in two lines instead of one +* Added a fix for the maximum text width of the player name in the inventory +* Added a fix for the **'mood'** argument of `start_gdialog` script function being ignored for talking heads + +Various bug fixes and features based on the work by Mr.Stalin: +* Fixed broken `get/reset_critical_table` script functions +* Improved the functionality of **CritterInvSizeLimitMode** and added party member's current/max inventory size info to the combat control panel +* Improved the functionality of **AllowDShowSound**: added volume control support and the ability to play alternative music files even if original **ACM** files are not present in the music folder, and fixed initialization crash bug when **DX9** mode is disabled +* Added a fix for the underline position in the inventory display window when the item name is longer than one line +* Added a fix for AI being unable to use the picked up object immediately when there is a different object with the same ID +* Added an option to prevent the inventory/loot/automap interfaces from being placed on top of other script-created windows +* New script functions: `get_current_inven_size`, `create_win`, `get/set_can_rest_on_map` + +## 4.1 +* Added an option to display experience points with the bonus from **Swift Learner** perk when gained from non-scripted situations (from Crafty) + +Original engine bug fixes and various features based on the work by Mr.Stalin: +* Implemented a **code injection system for game hooks**. In previous versions, the code of game hooks was always executed even if there is no corresponding hook script. Now the code of a game hook only gets injected into the game when the corresponding hook script exists +* Code refactoring for some hook scripts +* Fixed an issue with file IDs of additional game msg files being shifted when a file in **ExtraGameMsgFileList** is missing +* Fixed `obj_can_see_obj` script function not checking if source and target objects are on the same elevation before calling `HOOK_WITHINPERCEPTION` hook script +* Improved the functionality of **ExtraGameMsgFileList** to allow manually assigning numbers to specific msg files +* Improved the functionality of `HOOK_AMMOCOST` hook script when **CheckWeaponAmmoCost** is enabled +* Improved and expanded the functionality of **UseScrollingQuestsList** to display page numbers and add another set of scroll buttons +* Expanded `is_iface_tag_active` script function to check tag value of 0/1/2 (sneak/poisoned/radiated) +* Added a fix for missing AC/DR mod stats when examining ammo in the barter screen +* Added a fix for the display issue in the pipboy when a quest list is too long with **UseScrollingQuestsList** diabled +* Added a fix for the clickability issue of holodisk list in the pipboy +* Added a fix for the broken `obj_can_hear_obj` script function +* Added a fix for multihex critters moving too close and overlapping their targets in combat +* Added a fix for AI not checking weapon perks properly when choosing the best weapon in combat +* Added an option to keep the selected attack mode when moving the weapon between active item slots +* Added an option to set the number of additional notification boxes to the interface +* Added an option to load alternative dialog msg and subtitle files for female PC (translation friendly) +* Added an option to display full item description for weapon/ammo in the barter screen +* Added options to change the location of quest list scroll buttons +* Added options to use more than one save slot for quick saving +* Added `DIALOGVIEW` flag to the game mode functions (when reviewing the current conversation) +* Added a new argument to `hs_withinperception` hook script +* Added a new return value to `hs_barterprice` hook script to modify the value of player's goods +* New script functions: `get_string_pointer`, `dialog_message` +* New hook scripts: `hs_useanimobj`, `hs_explosivetimer`, `hs_descriptionobj` + +## 4.0.7 +* Fixed the game thinking you dropped an active explosive when the dropping is prevented with `hs_inventorymove` (from Mr.Stalin) +* New script function: `inventory_redraw` (from Mr.Stalin) +* **NPC combat control mod** now centers the screen on the controlled critter and has new options to display critter's name + +## 4.0.6 +* Fixed a crash bug introduced in 4.0.5 when calling various hooks + +## 4.0.5 +* Added an option to use Fallout's normal text font instead of DOS-like font on the world map +* Added an option to increase the maximum number of tile FRMs (from Crafty) +* Added the ability to define allowed weapon animations for NPCs to **NPC armor appearance mod** (in the **modders pack**) + +Original engine bug fixes and various features based on the work by Mr.Stalin: +* Added a fix for a crash when the critter goes through a door with animation triggers +* Added a 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 +* Added support for adding custom background FRM to the character screen of the **hero appearance mod** +* Added an option to display the range of the second attack mode in the inventory when you switch weapon modes in active item slots +* Added an option to set up a key to let you move/drop a whole stack of items at once without the **'Move Items'** window +* Added an option to change the counter in the **'Move Items'** window to start with maximum number +* Added a new mode to `metarule2_explosions` function +* New script function: `set_iface_tag_text` +* New hook script: `hs_gamemodechange` +* Expanded `get_mouse_buttons` function to return a value for the middle mouse button +* Improved the functionality of `hs_inventorymove` and `hs_invenwield` + +## 4.0.4 +* Fixed a broken functionality of **ExtraSaveSlots option**. Now sfall will remember the last selected save game slot. The position data is saved to/loaded from an auto-generated `slotdat.ini` in your savegame folder +* Fixed the last additional notification boxes to the interface being missing +* Fixed a bug in **NPC combat control mod** that caused **Gecko Skinning** to appear in the perk selection window +* Fixed a bug in **item highlighting mod** that caused items to be kept highlighted when entering combat while holding the highlight key +* Fixed the broken `get_attack_type` script function (from Mr.Stalin and Crafty) +* Added a fix for being at incorrect hex after map change when the exit hex in source map is at the same position as some exit hex in destination map (from Crafty) +* Added a math script function: `floor2` +* New script functions: `set_ini_setting`, `lock_is_jammed`, `unjam_lock`, `set_unjam_locks_time`, `get/set_map_enter_position`, `set_rest_heal_time`, `set_rest_mode`, `attack_is_aimed` (from Mr.Stalin) +* New hook scripts: `hs_setglobalvar`, `hs_resttimer` (from Mr.Stalin) + +## 4.0.3 +* Fixed the broken **ExtraGameMsgFileList** option +* Fixed a bug in **NPC combat control mod** that increases the rank of **Gecko Skinning** perk when a combat ends +* Fixed `add_mult_objs_to_inven` script function only adding 500 of an object when the value of the **'count'** argument is over 99999 +* Improved the fix for player's base EMP DR to make sure the value is set correctly +* **Item highlighting mod** now only highlights lootable corpses + +## 4.0.2 +* Fixed `sneak_success` script function not checking if the player is currently sneaking +* Added a fix for player's base EMP DR not being properly initialized when creating a new character and then starting the game +* New script function: `display_stats` +* Improved the functionality of **UseScrollWheel**. Now you can scroll through items in the loot/barter screens, and text in the message window (from Crafty) + +## 4.0.1 +* Fixed a crash bug in **NPC combat control** when trying to control a temporary party member that has no data in `party.txt` + +## 4.0 +* The build environment is now **Visual Studio 2015**, and Win XP SP2 and Win 2000 are no longer supported +* Extensive code reorganizing/rewrite was made in the effort to tidy up sfall code base accumulated over the years and make it easier to read, understand, and extend. Main code was split into separate **'modules'**. Code for interacting with Fallout 2 engine was moved and expanded to allow for engine manipulations without using too much Assembly code +* Fixed an issue with the game being rendered before the **hero appearance mod** is loaded +* **Item highlighting mod** was moved from sfall into a separate script (`gl_highlighting.int`) and extended with new options +* **NPC combat control mod** was moved from sfall into a separate script (`gl_partycontrol.int`) +* Related options of **item highlighting** and **NPC combat control** mods were moved from `ddraw.ini` into a separate `sfall-mods.ini` +* A new version of **NPC armor appearance mod** was implemented as a separate script (`gl_npcarmor.int` in the **modders pack**). It can be configured and made compatible with any Fallout 2 mod +* Improved compatibility between **hero appearance mod**, **NPC combat control**, and **NPC armor appearance** mods +* A bunch of hooks and script functions were added to allow implementing multiple vehicles in the game +* New script functions: `item_weight`, `get/set_outline`, `get/set_flags`, `tile_refresh_display`, `outlined_object`, `set_dude_obj`, `real_dude_obj`, `get_ini_sections`, `get_ini_section`, `car_gas_amount`, `set_car_intface_art`, `get/set_cursor_mode` +* New hook scripts: `hs_adjustfid`, `hs_combatturn`, `hs_cartravel` +* Added the ability to load global scripts from different paths +* Included Chinese and Russian translations + +Original engine bug fixes and various features based on the work by Crafty: +* Added a fix for the exploit that **Bonus Move** APs are replenished when you save and load the game in combat +* Added a fix for the displayed message when the attack randomly hits a target that is not a critter and has a script attached +* Added a fix for `damage_p_proc` being called for misses if the target is not a critter +* Added a fix for the double damage effect of **Silent Death** perk not being applied to critical hits +* Implemented standard script procedures: `combat_is_starting_p_proc` (called when a combat starts, but doesn't mean that the critter is in combat) and `combat_is_over_p_proc` (called when a combat ends) +* Added `INTFACEUSE`, `INTFACELOOT`, `BARTER`, and `HEROWIN` flags to the game mode functions +* Added a new argument to `HOOK_COMBATDAMAGE` hook script +* Added an option to prevent the player from running while sneaking without **Silent Running** perk + +## 3.8.4 +* Fixed a crash introduced in 3.8.3 when calling `destroy_object` or `destroy_mult_objs` +* Fixed a **hero appearance mod** issue that caused the race and style not to be loaded properly from savegames +* Added an option to set the color of outlines for highlighted items and containers + +## 3.8.3 +* Fixed a crash when pressing **reload weapon key** while in the main menu +* Fixed `metarule2_explosions` not being reset properly +* Fixed global scripts not running on the world map when disabling the world map speed patch +* Fixed inconsistent behavior of motion sensor flag 2 +* Added 3 new arguments to `HOOK_TOHIT` hook script +* Added a fix for the bag/backpack exploit that lets you keep items that are supposed to be removed from the inventory +* Added a fix for the original engine issue that caused Sequence stat value not to be printed correctly when using **'print to file'** option +* Improved the functionality of **ScrollMod** +* Improved the functionality of **ExplosionsEmitLight**. Now it will check if an item was lit prior to being thrown/shot +* Changed **SkipSizeCheck** and **ExtraCRC** to not require sfall debugging mode +* Removed the obsolete **WorldMapFPS**, **ForceLowResolutionTimer**, and **WorldMapDelay** options + +Original engine bug fixes and various features based on the work by Crafty: +* Added a fix for a crash when clicking on empty space in the inventory list opened by **'Use Inventory Item On'** (backpack) action icon +* Added a fix for negative SPECIAL values in character creation +* Added a fix for the game hanging in an endless loop in combat mode when calling `anim` script functions inside `damage_p_proc` +* Added 3 new arguments to `HOOK_BARTERPRICE` hook script + +## 3.8.2 +* Fixed broken `call_offset_*` script functions +* Fixed **OverrideMusicDir** not using the correct path string +* Fixed a bug in `metarule2_explosions` function that caused damage type change not to work +* Fixed a crash if calling `reg_anim_obj_run_to_tile` after `reg_anim_combat_check` +* Changed `sfallgv.sav` to be loaded before other save game files to make saved arrays available in the start procedure +* Changed **BodyHit_Torso** to **BodyHit_Torso_Uncalled** because it sets both *body_torso* and *body_uncalled* hit modifiers + +Original engine bug fixes and various features based on the work by Crafty: +* Added a fix for display issues when calling `gdialog_mod_barter` with critters with no **'Barter'** flag set +* Added a fix for the original engine issue that caused items to disappear from the inventory when you try to drag them to bag/backpack in the inventory list and are overloaded +* Added a fix for the original engine issue that caused the game not to check player's inventory properly when putting items into the bag/backpack in the hands +* Added a fix for the original engine issue that caused the current carry weight and the range of equipped weapons being lowered temporarily when opening bag/backpack +* Added a fix for a crash when trying to open bag/backpack on the table in the bartering interface +* Added the ability to move items from bag/backpack to the main inventory list by dragging them on the character portrait (similar to Fallout 1 behavior) +* Changed **WorldMapEncounterFix/Rate** to work independently of **WorldMapFPSPatch** + +## 3.8.1 +* Fixed pressing `F6` not displaying the **Quick Save** screen + +## 3.8 +* Improved **NPC combat control** and fixed various issues with it +* Fixed bugs in `set*_stat_min` script functions that set max values instead of min +* Unified the style of global/hook script log entries +* Added new universal opcodes **sfall_funcX** that allow adding new script functions without changing script compiler and decompiler +* Added new script functions: `spatial_radius`, `critter_inven_obj2`, `intface_redraw`, `intface_hide`, `intface_show`, `intface_is_hidden`, `exec_map_update_scripts` + +Original engine bug fixes and various features based on the work by Crafty: +* sfall can now load global/hook scripts from **.dat** files +* Improved the **'print to file'** fix and added the ability to use long filenames in **.dat** files +* Improved the functionality of **ProcessorIdle** + +## 3.7.4 +* Improved the functionality of **DisableHorrigan** +* Replaced **NumberPatchLoop** with a simpler **MultiPatches** toggle +* Added a new value to **PipBoyAvailableAtGameStart** to make the pipboy available by only skipping the vault suit movie check +* Changed **BodypartHitModX** to **BodyHit_(body parts)** in `ddraw.ini` to make them easier to understand +* Removed **BodyHit_Uncalled** from `ddraw.ini`. Now *body_torso* and *body_uncalled* hit modifiers share the same value, and `set_bodypart_hit_modifier` script function is also tweaked to match the change +* Removed **CarryWeightLimit** from `ddraw.ini` because it can be scripted with `set_stat_max` script function +* Removed **GainStatPerkFix** from `ddraw.ini` + +Original engine bug fixes and various features based on the work by Crafty: +* sfall now loads global/hook scripts, shaders, 32-bit talking head images, and **AVI** movies from **master_patches** path in `fallout2.cfg` instead of the fixed **'data\\'** directory +* Added a fix for the original engine issue that caused incorrect positioning after exiting small locations (e.g. Ghost Farm) +* Added an option to use a modified data load order for the engine to find game data + +## 3.7.3 +* Changed the displayed version number to the same as the internal version number +* Added the ability to read additional game msg files, as opposed to dialog msg files (from Vennor) +* Added an option to display sfall built-in credits at the bottom of `credits.txt` contents instead of at the top + +Original engine bug fixes and various features based on the work by Crafty: +* Fixed `get_screen_width/height` script functions not returning correct values when using the hi-res patch +* Fixed incorrect savegame path detection when reading/writing `sfallgv.sav` and `sfallfs.sav` in certain circumstances +* Improved the unlimited ammo exploit fix to prevent crashes with some faulty scripting +* Added a fix for the original engine issue that caused action points to be initialized incorrectly at the beginning of each turn, thus giving a hidden bonus to your opponent's armor class and reducing your hit chance +* Added a fix for `destroy_p_proc` not being called if the critter is killed by explosives when you leave the map +* Added a fix for incorrect death animations being used when killing critters with `kill_critter_type` script function +* Added a fix for the original engine issue that caused Fallout to check the horizontal position on the y-axis instead of x when setting coordinates on the world map +* Changed the way **SpeedInterfaceCounterAnims=2** works. Now it updates the HP/AC counters instantly in all cases +* Added an option to display numbered dialogue options + +## 3.7b +* Fixed broken `sfall_ver_*` script functions +* Fixed potential undefined behavior and crashes in sfall arrays (from Vennor) +* Optimized some code to make the compiled DLLs about 10 KB smaller in size +* Switched to using the precomputed CRC table instead of creating the CRC table at runtime. This could potentially improve startup time in emulated or partially emulated environments (from Oppen) +* Added rounding calculation to **ComputeSprayMod** for more balanced bullet distribution in burst attacks +* Re-added **CarChargingFix** option to `ddraw.ini` for mods that have custom vehicles +* Removed **MultiHexPathingFix** from `ddraw.ini` because there is little reason to turn it off + +Original engine bug fixes and various features based on the work by Crafty: +* Fixed a crash bug introduced with the inventory drag and drop fix +* Added a new value to **SpeedInterfaceCounterAnims** to update the HP/AC counters instantly when the number is not negative +* Added an option to skip weapon equip/unequip animations when performing various actions +* Added an option to control the speed of pipboy alarm clock animations +* Added an option to change the carry weight limit + +## 3.7a +* Partially refactored all the source code to use proper engine function/variable names +* Removed a few options from `ddraw.ini` that should never be turned off + +Original engine bug fixes and various features based on the work by Crafty: +* Added a fix for being unable to sell used geiger counters or stealth boys +* Added a fix for not counting in the weight of equipped items on NPC when stealing or bartering +* Added a fix for only using one box of ammo when reloading a weapon above the ammo in the inventory list by drag and drop +* Added an option to remove the ability to enter unvisited areas on a town map by hitting number keys +* Added an option to leave the music playing in dialogue with talking heads +* Added an option to skip the **'Move Items'** window when using drap and drop to reload weapons in the inventory + +## 3.7 +* Fixed incorrect bonuses on AC and Melee Damage from the **Heavy Handed** trait when using `perks.ini` +* A new hook script: `hs_invenwield` (when causing a critter to wield/unwield an armor or a weapon) +* Expanded `message_str_game` script function to support all `pro_*.msg` files as well +* **ExtraCRC** can now accept multiple CRC values +* Merged sfall debugging features into the normal version, thus removing the need of a seperate debugging version for modders +* Removed the obsolete Jim's damage formula +* Removed a few options from `ddraw.ini` that should never be turned off + +Original engine bug fixes and various features based on the work by Crafty: +* Fixed **SpeedInterfaceCounterAnims** not displaying the correct negative value when HP drops below zero +* Rewrote the **Sharpshooter** perk fix to match its description correctly +* Rewrote the dodgy door fix to apply to both melee and ranged attacks +* Added a fix for a crash when leaving the map while waiting for someone to die of a super stimpak overdose +* Added a fix for the original engine issue that caused party members to have incorrect stats when they level up while on drugs +* Added a fix for the unlimited ammo exploit +* Added a fix for negative values in Skilldex window +* Added a fix for the clickability issue in the pipboy and an exploit that allows resting in places where you shouldn't be able to +* Added a fix to prevent **'Too Many Items'** bug from corrupting save files +* Added a fix for the exploit that you can gain stats from more than two doses of a specific chem after save/load +* Added a fix for the original engine issues with reverse order of items in memory relative to visual order in the inventory list +* Added a fix for the original engine issue that caused party members to be able to unequip multiple of the same armor and reduce their stats to below the proper values +* Added a fix for the original engine issues that caused the game not to check NPC's addiction properly and Jet Antidote not to work on NPCs +* Added a fix for the maximum text width of the item weight (Wt.) in party member trading window +* Added a fix for the original engine issue that caused NPCs to become unresponsive and act like walking containers if you move to another map while they are under **'lost next turn'** critical miss effect +* Added a fix for the original engine issues with being able to charge the car by using cells on other scenary/critters, and cells getting consumed even when the car is already fully charged +* Added an option to stack empty identical weapons, no matter what type of ammo was loaded previously +* Added an option to highlight containers as well as items +* Added an option to allow 9 options (lines of text) to be displayed correctly in the dialog window +* Added an option to display additional points of damage from **Bonus HtH/Ranged Damage** perks in the inventory + +__For changelogs prior to 3.7, please read the `sfall-readme.txt` in the [release files](https://github.com/sfall-team/sfall/releases).__ diff --git a/README.md b/README.md index 968e5c59c..716129ecc 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,38 @@ A set of engine modifications for the classic game Fallout 2 in the form of a DL - Many additional features for users, such as item highlight button, party member control, etc. - Extended scripting capabilities for modders (many new opcodes to control sfall features as well as previously unavailable vanilla engine functions) - Original author: **Timeslip** -Original description: A set of engine modifications for the classic game Fallout 2 by Interplay. Includes fixes for bugs in the original engine, allows fallout to run correctly on modern operating systems, and adds additional features for modders. +Original description: A set of engine modifications for the classic game Fallout 2 by Interplay. Includes fixes for bugs in the original engine, allows Fallout to run correctly on modern operating systems, and adds additional features for modders. + +## Installation + +- Download `sfall_*.7z` from the [release archive](https://sourceforge.net/projects/sfall/files/). + +- Extract `ddraw.dll`, `ddraw.ini`, `sfall-mods.ini`, `sfall.dat`, and `data` folder to Fallout's base directory (i.e. the one that contains `fallout2.exe`). + +- __Important Note:__\ + If you are using a mod that already included sfall (e.g. killap's [Unofficial Patch](https://github.com/BGforgeNet/Fallout2_Unofficial_Patch) or [Restoration Project](https://github.com/BGforgeNet/Fallout2_Restoration_Project)), then that mod has probably included a custom modified `ddraw.ini`. In that case, overwriting it with sfall's vanilla `ddraw.ini` will be likely break your game. Instead, only overwrite `ddraw.dll`, and keep the mod's existing copy of `ddraw.ini`. (Or, if you know what you're doing, you can merge them together by hand.) + +- The folder `translations` contains translations of some of the strings that sfall displays in the game. To use a translation, copy this folder to Fallout's base directory too, and then in `ddraw.ini` change the __TranslationsINI__ setting to `.\translations\.ini`. + +## Uninstallation + +Delete `ddraw.dll`, `ddraw.ini`, `sfall-mods.ini`, and `sfall.dat` from your Fallout directory. Also, delete `gl_highlighting.int` and `gl_partycontrol.int` from Fallout's `data\scripts\` directory. + +## Usage + +This mod is configured via the `ddraw.ini` and `sfall-mods.ini` files, which can be opened with any text editor. Details of every configerable option are included in those files. Where a comment refers to a DX scancode, the complete list of codes can be found at the link below:\ +https://kippykip.com/b3ddocs/commands/scancodes.htm + +In a default installation using an unmodified copy of `ddraw.ini`, the middle mouse button will be set to switch between weapons and the mouse wheel will be set to scroll through any menus that respond to the up/down arrow keys. Holding Ctrl and hitting numpad keys 0 to 6 (with Num Lock off) will adjust the game speed. Holding left Ctrl will let you move a whole stack of items at once. Pressing left Shift will highlight items on the ground. The script extender and any engine fixes are also enabled. Most of the options that change gameplay in some way not originally intended by the developers are disabled. + +For [__Wine__](https://www.winehq.org/) users:\ +You need to set DLL overrides for `ddraw.dll` to __"native, builtin"__ in `winecfg` or use `WINEDLLOVERRIDES="ddraw=n,b"` to run Fallout from the command line. If you want to play alternative sound files, you'll also need to install GStreamer Good 32-bit plugins. + +## Additional info ---- -#### Fallout Engine IDA Database -[Download for IDA Pro 6.8](https://www.dropbox.com/s/tm0nyx0lnk4yui0/Fallout_1_and_2_IDA68.rar?dl=1 "Download from Dropbox") - | [Download for IDA Pro 7.0](https://www.dropbox.com/s/61srq09pn8grfpu/Fallout_1_and_2_IDA70.rar?dl=1 "Download from Dropbox") (comments are in Russian) +* [Changelog](CHANGELOG.md) +* [Scripting Documentation](https://sfall-team.github.io/sfall/) +* Fallout Engine IDA Database: [for IDA Pro 6.8](https://www.dropbox.com/s/tm0nyx0lnk4yui0/Fallout_1_and_2_IDA68.rar?dl=1 "Download from Dropbox") | [for IDA Pro 7.0](https://www.dropbox.com/s/61srq09pn8grfpu/Fallout_1_and_2_IDA70.rar?dl=1 "Download from Dropbox") (comments are in Russian) +* [Fallout 2 Reference Edition](https://github.com/alexbatalov/fallout2-re) From 254473cf1ccf3e75bf97b43596b0d6b9d4912548 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 15 Mar 2023 12:09:52 +0800 Subject: [PATCH 29/33] Added support for closing the game by Alt+F4 (#457) --- sfall/FalloutEngine/VariableOffsets.h | 1 + sfall/WinProc.cpp | 41 ++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index 331e06bc0..b0c990032 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -139,6 +139,7 @@ #define FO_VAR_GNW95_hDDrawLib 0x51E44C #define FO_VAR_GNW95_hwnd 0x51E434 // main hwnd window #define FO_VAR_GNW95_isActive 0x51E444 +#define FO_VAR_GNW95_keyboardHandle 0x6AC758 #define FO_VAR_GNW95_repeat_delay 0x51E240 #define FO_VAR_GNW95_repeat_rate 0x51E23C #define FO_VAR_GNWWin 0x5195B8 diff --git a/sfall/WinProc.cpp b/sfall/WinProc.cpp index 6cd15ab58..9f1e63c83 100644 --- a/sfall/WinProc.cpp +++ b/sfall/WinProc.cpp @@ -53,13 +53,11 @@ void __stdcall WinProc::WaitMessageWindow() { MessageWindow(); } -static int __stdcall WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { +static long __stdcall WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { RECT rect; //POINT point; switch (msg) { - //case WM_CREATE: - // break; case WM_DESTROY: __asm xor eax, eax; __asm call fo::funcoffs::exit_; @@ -149,7 +147,39 @@ static int __stdcall WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara } static long __stdcall main_menu_loop_hook() { - return (!reqGameQuit) ? fo::func::get_input() : 27; // ESC code + return (!reqGameQuit) ? fo::func::get_input() : VK_ESCAPE; +} + +static long __stdcall GNW95_keyboard_hook(int nCode, WPARAM wParam, LPARAM lParam) { + if (nCode < 0) { + goto callNext; + } + + switch (wParam) { + case VK_DELETE: + if (!(lParam & 0x20000000)) { + break; + } + case VK_ESCAPE: + if (GetAsyncKeyState(VK_CONTROL) < 0) { + return 0; + } + break; + case VK_TAB: + if ((lParam & 0x20000000)) { + return 0; + } + break; + case VK_NUMLOCK: + case VK_CAPITAL: + case VK_SCROLL: + case VK_F4: +callNext: + return CallNextHookEx((HHOOK)fo::var::getInt(FO_VAR_GNW95_keyboardHandle), nCode, wParam, lParam); + default: + break; + } + return 1; } void WinProc::SetWindowProc() { @@ -299,6 +329,9 @@ void WinProc::init() { // Replace the engine WindowProc_ with sfall implementation MakeJump(0x4DE9FC, WindowProc); // WindowProc_ + // Replace the engine GNW95_keyboard_hook_ with sfall implementation + SafeWrite32(0x4C9BD9, (DWORD)&GNW95_keyboard_hook); // GNW95_hook_keyboard_ + HookCall(0x481B2A, main_menu_loop_hook); } From b69e4e0eeb403f85c9f391555a650705d70db8df Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 16 Mar 2023 10:44:58 +0800 Subject: [PATCH 30/33] Fixed being able to call multiple exit msg boxes with Alt+F4 --- sfall/WinProc.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/sfall/WinProc.cpp b/sfall/WinProc.cpp index 9f1e63c83..4821693c1 100644 --- a/sfall/WinProc.cpp +++ b/sfall/WinProc.cpp @@ -34,7 +34,8 @@ static POINT client; static long moveWindowKey[2]; static long windowData; -static long reqGameQuit; +static long reqGameQuit = 0; +static bool isClosing = false; static bool cCursorShow = true; static bool bkgndErased = false; @@ -137,19 +138,20 @@ static long __stdcall WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar call fo::funcoffs::main_menu_is_shown_; test eax, eax; jnz skip; + cmp isClosing, 0; + jnz end; + mov isClosing, 1; call fo::funcoffs::game_quit_with_confirm_; + mov isClosing, al; skip: mov reqGameQuit, eax; + end: } return 0; } return DefWindowProcA(hWnd, msg, wParam, lParam); } -static long __stdcall main_menu_loop_hook() { - return (!reqGameQuit) ? fo::func::get_input() : VK_ESCAPE; -} - static long __stdcall GNW95_keyboard_hook(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode < 0) { goto callNext; @@ -182,6 +184,10 @@ static long __stdcall GNW95_keyboard_hook(int nCode, WPARAM wParam, LPARAM lPara return 1; } +static long __stdcall main_menu_loop_hook() { + return (!reqGameQuit) ? fo::func::get_input() : VK_ESCAPE; +} + void WinProc::SetWindowProc() { SetWindowLongA((HWND)fo::var::getInt(FO_VAR_GNW95_hwnd), GWL_WNDPROC, (LONG)WindowProc); } From 5b4e1653689af8f9cac5edd1f481afb4ba961839 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 27 Mar 2023 20:30:36 +0800 Subject: [PATCH 31/33] Fixed assorted typos in documents Added an example ini to Ammo INI Loader mod. Updated the changelog. --- CHANGELOG.md | 95 +++++---- artifacts/example_mods/AmmoMod/AmmoMod.ini | 201 +++++++++++++++++++ artifacts/example_mods/rain/weather.ini | 4 +- artifacts/scripting/README.md | 2 +- artifacts/scripting/README.txt | 2 +- artifacts/scripting/arrays.md | 2 +- artifacts/scripting/compiler/optimization.md | 8 +- artifacts/scripting/compiler/sslc_readme.md | 12 +- docs/Gemfile.lock | 2 +- docs/arrays.md | 2 +- docs/optimization.md | 8 +- docs/sslc.md | 8 +- 12 files changed, 282 insertions(+), 64 deletions(-) create mode 100644 artifacts/example_mods/AmmoMod/AmmoMod.ini diff --git a/CHANGELOG.md b/CHANGELOG.md index c972cfb63..fbfa47a81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 4.3.8 +* Fixed a bug introduced in 4.2.8 that broke the arguments of `HOOK_RESTTIMER` hook script +* Fixed a bug introduced in 4.3.1 that caused the game to display incorrect names for corpses in some cases +* Fixed a crash bug in **FullItemDescInBarter** when a weapon/ammo has no item description +* Fixed `create_object_sid` script function not setting the script index number upon object creation +* Fixed the broken `read_string` script function +* Fixed the order of autoloaded **.dat** files on the FAT file system +* Changed the way disabled unsafe script functions work. Now they don't cause scripts to end abruptly +* Removed **StackEmptyWeapons** from `ddraw.ini`. Now unloaded weapons will always stack, no matter what type of ammo was loaded previously +* Removed **CreditsAtBottom** from `ddraw.ini`. Now sfall built-in credits are shown at the beginning when from the main menu and at the end during the ending +* Added a fix for the player's traits not being displayed on the character screen in certain cases +* Added a fix for incorrect death endings being shown under certain conditions +* Added a tweak to the ammo information in the inventory for Glovz's damage formula and Haenlomal's YAAM +* Added a tweak to allow premade characters to have less than two traits +* Added a tweak to `INVENTORYMOVE` hook for getting the amount of dropped money/caps +* Added support for closing the game by pressing `Alt+F4` + ## 4.3.7 * Dropped support for older **pre-SSE** processors in favor of more optimized code. Now sfall requires a processor with **SSE** support * Fixed a bug that could prevent loading files from the `art\\` directory @@ -59,7 +76,7 @@ * Fixed incorrect display of name and damage values for unarmed attacks in the inventory in some cases * Fixed the black screen issue in **DX9** mode when returning to the game after using `Alt+Tab` * Fixed the mouse cursor lag in the save/load game screens -* Fixed broken object descriptions for a modified version of `fallout2.exe` that supports Chinese characters +* Fixed broken object descriptions for a modified `fallout2.exe` with Chinese/Japanese support * Fixed and expanded the mouse drop area for the PC's and NPC's inventory on the barter screen * Changed the **'Radiated'** on the character screen to be highlighted in gray when the player still has an impending radiation effect * Changed **SkipCompatModeCheck** to not require sfall debugging mode @@ -108,7 +125,7 @@ * Added the ability to set custom names for unarmed attacks in the inventory to **TranslationsINI** * Added support for using the newline control character `'\n'` in the object description in `pro_*.msg` files * Added support for the new **'Healing Item'** flag to item protos. Now AI will also use items with this flag for healing in combat -* Added support for the new **'Cannot Use'** flag to the misc flags of item objects. This flags makes a weapon object unusable in combat +* Added support for the new **'Cannot Use'** flag to the misc flags of item objects. This flag makes a weapon object unusable in combat * Added missing sounds for the buttons on the world map interface (similar to Fallout 1 behavior) * Added 5 `metarule3` macros for controlling the save slot with scripts to `sfall.h` in the **modders pack** * New script functions: `set_scr_name`, `obj_is_openable` @@ -183,7 +200,7 @@ * Removed the tweak that adds the city name in the description for empty save slots (added in 4.2.7) * Added a fix to update the maximum HP stat of critters on the map when loaded for the first time * Added a fix to the poison/radiation-related engine functions when taking control of an NPC -* Added a fix to AI weapon switching when not having enough action points. Now AI will try to change attack mode before deciding to switch weapon +* Added a fix to AI weapon switching when not having enough AP to make an attack. Now AI will try to change attack mode before deciding to switch weapon * Added a fix for the carry weight penalty of the **Small Frame** trait not being applied to bonus Strength points * Added a fix for the flags of non-door objects being set/unset when using `obj_close/open` script functions * Added a fix for the **'Leave'** event procedure in `AddRegionProc` function not being triggered when the cursor moves to a non-scripted window @@ -221,7 +238,7 @@ * Added a fix for the engine building the path to the central hex of a multihex object * Added a fix for the flags of critters in the line of fire not being taken into account when calculating the hit chance penalty of ranged attacks * Added a fix to the check for ranged weapons in the **Fast Shot** trait and **FastShotFix** -* Added a fix for the background image of the character portrait on the player inventory screen +* Added a fix for the background image of the character portrait on the player's inventory screen * Added a fix for the broken `Print()` script function * Added the original Fallout 1 behavior of the **Fast Shot** trait to **FastShotFix** * Added an option to enable linear texture filtering for **DX9** graphics modes @@ -242,7 +259,7 @@ * Fixed the default values for **Movie1 - Movie17** options * Fixed the playback of additional movies defined in **Movie18 - Movie32** options * Fixed **OverrideMusicDir=2** not overriding the music path properly -* Fixed incorrect Melee Damage stat value being displayed in some cases when setting **BonusHtHDamageFix=1** and **DisplayBonusDamage=0** +* Fixed incorrect Melee Damage stat value being displayed when setting **BonusHtHDamageFix=1** and **DisplayBonusDamage=0** * Fixed `attack_complex script` function not setting result flags correctly for the attacker and the target * Fixed and improved **SFX** and speech playback for alternative sound files * Fixed and improved the behavior of nested timer events in global scripts @@ -251,7 +268,7 @@ * Changed **ObjCanSeeObj_ShootThru_Fix** to allow critters to see through other critters and added a check for the direction the source is facing * Changed the behavior of replacing FRM aliases for critters. Now FRM files from their aliases are taken only if the critter doesn't have its own files * Added a fix for `ANIM_charred_body`/`ANIM_charred_body_sf` animations not being available to most appearances -* Added a fix to remove floating text messages on the map when moving to another map elevation +* Added a fix to remove floating text messages on the map when moving to another map or elevation * Added a fix for a visual glitch on the black edges of the map when the map borders for the hi-res patch are set smaller than the screen size * Added a fix to prevent the execution of `critter_p_proc` and game events when playing movies * Added a fix to prevent crashes and loading maps when the death animation causes the player to cross an exit grid @@ -281,7 +298,7 @@ ## 4.2.5.1 * Fixed the extra check for friendly fire treating non-critter objects as friendly critters -* Changed the debug message about missing art file for critters to be displayed in game only when in sfall debugging mode +* Changed the debug message about a missing critter art file to be displayed in the game only when in sfall debugging mode ## 4.2.5 * Fixed a bug introduced in 4.1.9 that could cause the combat to end automatically in some cases @@ -311,7 +328,7 @@ * Fixed and improved the playback of alternative sound files * Re-added **TownMapHotkeysFix** option to `ddraw.ini` for mod testing * Changed `play/stop_sfall_sound` script functions to return/accept the **ID** number of the played sound instead of a raw pointer -* Changed the **'Radiated'** on the character screen to be highlighted in red color when player's stats are affected by radiation exposure +* Changed the **'Radiated'** on the character screen to be highlighted in red when player's stats are affected by radiation exposure * Added a new **'fullscreen windowed'** mode to **DX9** graphics modes * Added saving the position of the game window to `ddraw.ini` * Added a fix for the player's money not being displayed in the dialog window after leaving the barter/combat control interface @@ -337,11 +354,11 @@ * Added a fix for the playback of the speech sound file for the death screen being ended abruptly in some cases * Added a fix for the barter button on the dialog window not animating until after leaving the barter screen * Added a fix for the division operator treating negative integers as unsigned -* Added a fix for trying to loot corpses with the **'NoSteal'** flag +* Added a fix for trying to loot corpses with the **'NoSteal'** flag set * Added an option to allow using the special `'^'` character in dialog msg files to specify the alternative text that will be displayed in the dialogue based on the player's gender * Added options to draw a dotted line while traveling on the world map (similar to Fallout 1, from Ghosthack) * Added an option to display terrain types when hovering the cursor over the player's marker on the world map (from Ghosthack) -* Added a flashing icon to the horrigan encounter and scripted force encounters by default +* Added a flashing icon to the Horrigan encounter and scripted force encounters by default * Added new flags to `force_encounter_with_flags` script function * Added a procedure and macros for comparing unsigned integers to `lib.math.h` in the **modders pack** * Increased the maximum text width of the total weight display in the inventory @@ -356,7 +373,7 @@ * Restored and fixed **RemoveWindowRounding** option that was removed in 4.1.2 * Improved the functionality of `inventory_redraw` script function * Changed the way **IniConfigFolder** works. Now the game will search for the ini files relative to the specified directory -* Changed the debug message about missing art file for critters to also be displayed in game +* Changed the debug message about a missing critter art file to also be displayed in the game * Code refactoring for various script functions * Added a fix to prevent the player from moving when clicking on a script-created window and prevent the mouse cursor from being toggled when hovering over a **'hidden'** window * Added a fix to prevent crashes when **DebugMode** is enabled and there is a **'%'** character in the printed message @@ -402,10 +419,10 @@ ## 4.2 * Fixed a bug in **XPTable** that prevented the player from reaching the highest specified level * Fixed `create_message_window` script function to prevent it from creating multiple message windows -* Fixed `obj_art_fid` script function returning incorrect player's FID when the **hero appearance mod** mod is enabled +* Fixed `obj_art_fid` script function returning incorrect player's FID when the **hero appearance mod** is enabled * Fixed a crash bug in `message_str_game` script function when passing a negative fileId value * Fixed **MainMenuFontColour** not changing the font color of the copyright text on the main menu -* Fixed a **hero appearance mod** mod issue that caused the incorrect FRM to be displayed when opening bag/backpack in the inventory +* Fixed a **hero appearance mod** issue that caused the incorrect FRM to be displayed when opening bag/backpack in the inventory * Fixed some arguments in `BARTERPRICE` hook when trading with a party member * Fixed a crash bug introduced in 4.1.8 when calling `game_time_advance` in the `map_exit_p_proc` procedure with active explosives on the map * Fixed some of sfall features that depend on the hi-res patch not working properly in some cases @@ -439,7 +456,7 @@ * Fixed the error handling for loading `sfallgv.sav` to improve backward compatibility with older saved games * Fixed `key_pressed` script function not working in `HOOK_KEYPRESS` hook script * Fixed a bug in **NPC combat control** that caused perks picked in combat to disappear after switching control to other critters -* Fixed a bug in **NPC combat control** that caused player's selected weapon mode not to be saved +* Fixed a bug in **NPC combat control** that caused player's selected attack mode not to be saved * Fixed the map elevation check in `get/set_can_rest_on_map` script functions * Improved the functionality of `add_extra_msg_file` script function to allow automatically assigning numbers to msg files * Changed **DebugMode** and **HideObjIsNullMsg** to not require sfall debugging mode @@ -454,7 +471,7 @@ * Fixed a bug in **NPC combat control mod** that caused the last controlled critter to get player's combat xp * Fixed the last procedure in a script being unable to be called through a variable containing its name as a string * Fixed a bug introduced in 4.1.8 that caused the `DAM_KNOCKED_DOWN` flag not to be reset for knocked out party members when leaving a map -* Improved **NPC combat control** to keep the selected weapon mode of the controlled critter +* Improved **NPC combat control** to keep the selected attack mode of the controlled critter * Improved the functionality of the debug editor (in the **modders pack**) * Improved the fix for **'NPC turns into a container'** bug * Changed **DataLoadOrderPatch** to be enabled by default @@ -471,7 +488,7 @@ * Added a fix for knocked down critters not playing stand up animation when the combat ends * Added a fix for dead NPCs reloading their weapons when the combat ends * Added an option to use the expanded world map interface (requires hi-res patch v4.1.8) -* Added an option to allow to set a folder path for the game to automatically search and load custom **.dat** files +* Added an option to allow setting a folder path for the game to automatically search and load custom **.dat** files * Added an option to expand the number of action points displayed on the interface bar * Added an option to change the base value of the duration of the knockout effect * Added a check for the `DAM_KNOCKED_OUT` flag to `wield_obj_critter/inven_unwield` script functions @@ -536,7 +553,7 @@ * Fixed the return value of `has_skill` script function for incorrect skill numbers * Fixed the negative skill points of a skill not being taken into account when calculating the skill level * Fixed incorrect skill point cost for negative skill levels when using a **skills ini file** -* Fixed the screen not returning to the player when moving a controlled critter to another elevation of the map +* Fixed the screen not returning to the player when moving a controlled critter to another map elevation * Fixed some functionality issues of fake perks * Fixed the broken `get_perk_available` script function * Fixed the lighting of controlled critters in **NPC combat control mod** @@ -551,7 +568,7 @@ * Added a fix for the removal of party member's corpse. Now items in party member's inventory are not removed along with the corpse * Added an option to change the timer for deleting corpses on a map after you leave * Added an option to override the global variable number used to show the special death message of the Modoc toilet explosion -* Added a new **[ExtraPatches]** section to allow to set multiple custom paths for loading game data +* Added a new **[ExtraPatches]** section to allow setting multiple custom paths for loading game data * Added a config file to change some parameters for drugs and their addictions * Added displaying the NPC's addictions on the character screen when controlled by the player * Added the ability to add extra non-scripted perks to the **perks ini file** @@ -568,7 +585,7 @@ Various bug fixes and features based on the work by Mr.Stalin: * Fixed `critter_mod_skill` script function taking a negative amount value as a positive * Fixed a crash when calling `use_obj/use_obj_on_obj` without using `set_self` in global scripts * Fixed `pickup_obj`, `drop_obj`, and `use_obj` script functions not working properly in some cases -* Fixed **TimeLimit=-3** not returning the correct year, and removed the setting value of -2 (Now it works the same as -3) +* Fixed **TimeLimit=-3** not returning the correct year, and removed the setting value -2 (Now it works the same as -3) * Fixed the mouse cursor lag on the world map when **WorldMapFPSPatch** is enabled * Fixed issues with the game speed tweak. Now the game speed will be temporarily set to normal speed when in the inventory or dialogue, and it doesn't affect the endgame slideshow * Fixed and improved the functionality of **UseFileSystemOverride** and `fs_*` script functions @@ -579,7 +596,7 @@ Various bug fixes and features based on the work by Mr.Stalin: * Added a fix for player's turn being skipped when loading a game saved in combat mode * Added an option to fix and repurpose the unused **called_shot/num_attacks** arguments of `attack_complex` script function * Added an option to make the game speed tweak also affect the playback speed of **MVE** video files without an audio track -* Added a debugging option to hide error messages in debug output when a null value is passed to the function as an object +* Added a debug option to hide error messages in debug output when a null value is passed to the function as an object * Increased the maximum number of books in **BooksFile** to 50 * New script function: `art_cache_clear` @@ -597,7 +614,7 @@ Various bug fixes and features based on the work by Mr.Stalin: * Changed `INVENTORYMOVE` hook to be called before displaying the **'Move Items'** window for dragging and dropping ammo on weapons * Added a fix to prevent sfall from trying to load global scripts with an extension that exceeds three characters (e.g. gl_test.int123) * Added a fix to the following script functions to ensure they set the correct object: `set_critter_burst_disable`, `set_critter_pickpocket_mod`, `set_critter_skill_mod`, `set_critter_hit_chance_mod`, `set_*_knockback` -* Added a debug option to force sfall to search for global scripts every time the game loads rather than only once on the first game start +* Added a debug option to force sfall to search for global scripts every time the game loads rather than only the first time * Added an option to change the distance at which the player will switch to walking when trying to use objects or pick up items * New hook script: `hs_setlighting` @@ -611,11 +628,11 @@ Various bug fixes and features based on the work by Mr.Stalin: * Fixed the missing return value of -1 for `HOOK_USEOBJON` hook script * Fixed the order of loading global scripts from multiple paths * Fixed the return values of a hook getting corrupted if another hook was called during the execution of the current hook -* Fixed a bug in the **hero appearance mod** mod that caused the player to disappear after saving the game when player's base FID is greater than 255 +* Fixed a bug in the **hero appearance mod** that caused the player to disappear after saving the game when player's base FID is greater than 255 * Changed how `HOOK_FINDTARGET` hook script handles its return values. Now you don't have to specify all 4 targets to override normal sorting * Added a fix for being unable to sell/give items in the barter screen when the player/party member is overloaded * Added a fix for AI still taking distance into account when calculating hit chance using the **'no_range'** flag -* Added a fix for AI not taking `chem_primary_desire` in `AI.txt` as drug use preference when using drugs in their inventory +* Added a fix for AI not taking `chem_primary_desire` in `AI.txt` as a preference list when using drugs in the inventory * Added a fix to display a pop-up message box about **death from radiation** * Added a fix to prevent hook scripts from being executed when the depth limit is exceeded, or the hook is called recursively * Added a new value to **SpeedInterfaceCounterAnims** to update the AC counter instantly when switching to other controlled critters in combat @@ -626,7 +643,7 @@ Various bug fixes and features based on the work by Mr.Stalin: * Updated **NPC combat control mod** to work with **BoxBarCount** and prevent Marcus and non-biped critters from equipping armor when controlled by the player * Updated **item highlighting mod** to be disabled while in the loot screen * Changed the debug editor to require sfall debugging mode -* Removed **RemoveWindowRounding** from `ddraw.ini` because it doesn't affect anything +* Removed **RemoveWindowRounding** option because it doesn't affect anything Original engine bug fixes and various features based on the work by Crafty: * Added a fix for **Heave Ho!** perk increasing Strength stat above 10 when determining the maximum range of thrown weapons @@ -688,13 +705,13 @@ Original engine bug fixes and various features based on the work by Mr.Stalin: * Added options to change the location of quest list scroll buttons * Added options to use more than one save slot for quick saving * Added `DIALOGVIEW` flag to the game mode functions (when reviewing the current conversation) -* Added a new argument to `hs_withinperception` hook script -* Added a new return value to `hs_barterprice` hook script to modify the value of player's goods +* Added a new argument to `HOOK_WITHINPERCEPTION` hook script +* Added a new return value to `HOOK_BARTERPRICE` hook script to modify the value of player's goods * New script functions: `get_string_pointer`, `dialog_message` * New hook scripts: `hs_useanimobj`, `hs_explosivetimer`, `hs_descriptionobj` ## 4.0.7 -* Fixed the game thinking you dropped an active explosive when the dropping is prevented with `hs_inventorymove` (from Mr.Stalin) +* Fixed the game thinking you dropped an active explosive when the dropping is prevented by `HOOK_INVENTORYMOVE` hook script (from Mr.Stalin) * New script function: `inventory_redraw` (from Mr.Stalin) * **NPC combat control mod** now centers the screen on the controlled critter and has new options to display critter's name @@ -710,7 +727,7 @@ Original engine bug fixes and various features based on the work by Mr.Stalin: * Added a fix for a crash when the critter goes through a door with animation triggers * Added a 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 * Added support for adding custom background FRM to the character screen of the **hero appearance mod** -* Added an option to display the range of the second attack mode in the inventory when you switch weapon modes in active item slots +* Added an option to display the range of the secondary attack mode in the inventory when you switch weapon modes in active item slots * Added an option to set up a key to let you move/drop a whole stack of items at once without the **'Move Items'** window * Added an option to change the counter in the **'Move Items'** window to start with maximum number * Added a new mode to `metarule2_explosions` function @@ -732,7 +749,7 @@ Original engine bug fixes and various features based on the work by Mr.Stalin: ## 4.0.3 * Fixed the broken **ExtraGameMsgFileList** option -* Fixed a bug in **NPC combat control mod** that increases the rank of **Gecko Skinning** perk when a combat ends +* Fixed a bug in **NPC combat control mod** that increases the rank of **Gecko Skinning** perk when the combat ends * Fixed `add_mult_objs_to_inven` script function only adding 500 of an object when the value of the **'count'** argument is over 99999 * Improved the fix for player's base EMP DR to make sure the value is set correctly * **Item highlighting mod** now only highlights lootable corpses @@ -754,7 +771,7 @@ Original engine bug fixes and various features based on the work by Mr.Stalin: * **NPC combat control mod** was moved from sfall into a separate script (`gl_partycontrol.int`) * Related options of **item highlighting** and **NPC combat control** mods were moved from `ddraw.ini` into a separate `sfall-mods.ini` * A new version of **NPC armor appearance mod** was implemented as a separate script (`gl_npcarmor.int` in the **modders pack**). It can be configured and made compatible with any Fallout 2 mod -* Improved compatibility between **hero appearance mod**, **NPC combat control**, and **NPC armor appearance** mods +* Improved compatibility between **hero appearance**, **NPC combat control**, and **NPC armor appearance** mods * A bunch of hooks and script functions were added to allow implementing multiple vehicles in the game * New script functions: `item_weight`, `get/set_outline`, `get/set_flags`, `tile_refresh_display`, `outlined_object`, `set_dude_obj`, `real_dude_obj`, `get_ini_sections`, `get_ini_section`, `car_gas_amount`, `set_car_intface_art`, `get/set_cursor_mode` * New hook scripts: `hs_adjustfid`, `hs_combatturn`, `hs_cartravel` @@ -828,13 +845,13 @@ Original engine bug fixes and various features based on the work by Crafty: * Improved the functionality of **ProcessorIdle** ## 3.7.4 -* Improved the functionality of **DisableHorrigan** +* Improved the functionality of **DisableHorrigan** to work on old saved games * Replaced **NumberPatchLoop** with a simpler **MultiPatches** toggle * Added a new value to **PipBoyAvailableAtGameStart** to make the pipboy available by only skipping the vault suit movie check * Changed **BodypartHitModX** to **BodyHit_(body parts)** in `ddraw.ini` to make them easier to understand * Removed **BodyHit_Uncalled** from `ddraw.ini`. Now *body_torso* and *body_uncalled* hit modifiers share the same value, and `set_bodypart_hit_modifier` script function is also tweaked to match the change -* Removed **CarryWeightLimit** from `ddraw.ini` because it can be scripted with `set_stat_max` script function -* Removed **GainStatPerkFix** from `ddraw.ini` +* Removed **CarryWeightLimit** option because it can be scripted with `set_stat_max` script function +* Removed **GainStatPerkFix** from `ddraw.ini` because there is little reason to turn it off Original engine bug fixes and various features based on the work by Crafty: * sfall now loads global/hook scripts, shaders, 32-bit talking head images, and **AVI** movies from **master_patches** path in `fallout2.cfg` instead of the fixed **'data\\'** directory @@ -848,7 +865,7 @@ Original engine bug fixes and various features based on the work by Crafty: Original engine bug fixes and various features based on the work by Crafty: * Fixed `get_screen_width/height` script functions not returning correct values when using the hi-res patch -* Fixed incorrect savegame path detection when reading/writing `sfallgv.sav` and `sfallfs.sav` in certain circumstances +* Fixed incorrect savegame path detection when reading/writing `sfallgv.sav` and `sfallfs.sav` under certain circumstances * Improved the unlimited ammo exploit fix to prevent crashes with some faulty scripting * Added a fix for the original engine issue that caused action points to be initialized incorrectly at the beginning of each turn, thus giving a hidden bonus to your opponent's armor class and reducing your hit chance * Added a fix for `destroy_p_proc` not being called if the critter is killed by explosives when you leave the map @@ -862,7 +879,7 @@ Original engine bug fixes and various features based on the work by Crafty: * Fixed potential undefined behavior and crashes in sfall arrays (from Vennor) * Optimized some code to make the compiled DLLs about 10 KB smaller in size * Switched to using the precomputed CRC table instead of creating the CRC table at runtime. This could potentially improve startup time in emulated or partially emulated environments (from Oppen) -* Added rounding calculation to **ComputeSprayMod** for more balanced bullet distribution in burst attacks +* Added rounding calculation to **ComputeSprayMod** for a more balanced bullet distribution in burst attacks * Re-added **CarChargingFix** option to `ddraw.ini` for mods that have custom vehicles * Removed **MultiHexPathingFix** from `ddraw.ini` because there is little reason to turn it off @@ -887,10 +904,10 @@ Original engine bug fixes and various features based on the work by Crafty: ## 3.7 * Fixed incorrect bonuses on AC and Melee Damage from the **Heavy Handed** trait when using `perks.ini` -* A new hook script: `hs_invenwield` (when causing a critter to wield/unwield an armor or a weapon) +* New hook script: `hs_invenwield` (when causing a critter to wield/unwield an armor or a weapon) * Expanded `message_str_game` script function to support all `pro_*.msg` files as well * **ExtraCRC** can now accept multiple CRC values -* Merged sfall debugging features into the normal version, thus removing the need of a seperate debugging version for modders +* Merged sfall debugging features into the normal version, thus removing the need of a separate debugging version for modders * Removed the obsolete Jim's damage formula * Removed a few options from `ddraw.ini` that should never be turned off @@ -907,10 +924,10 @@ Original engine bug fixes and various features based on the work by Crafty: * Added a fix for the exploit that you can gain stats from more than two doses of a specific chem after save/load * Added a fix for the original engine issues with reverse order of items in memory relative to visual order in the inventory list * Added a fix for the original engine issue that caused party members to be able to unequip multiple of the same armor and reduce their stats to below the proper values -* Added a fix for the original engine issues that caused the game not to check NPC's addiction properly and Jet Antidote not to work on NPCs +* Added a fix for the original engine issues that caused the game not to check NPC's addictions properly and the Jet Antidote not to work on NPCs * Added a fix for the maximum text width of the item weight (Wt.) in party member trading window * Added a fix for the original engine issue that caused NPCs to become unresponsive and act like walking containers if you move to another map while they are under **'lost next turn'** critical miss effect -* Added a fix for the original engine issues with being able to charge the car by using cells on other scenary/critters, and cells getting consumed even when the car is already fully charged +* Added a fix for the original engine issues with being able to charge the car by using cells on other scenery/critters, and cells getting consumed even when the car is already fully charged * Added an option to stack empty identical weapons, no matter what type of ammo was loaded previously * Added an option to highlight containers as well as items * Added an option to allow 9 options (lines of text) to be displayed correctly in the dialog window diff --git a/artifacts/example_mods/AmmoMod/AmmoMod.ini b/artifacts/example_mods/AmmoMod/AmmoMod.ini new file mode 100644 index 000000000..2111793a3 --- /dev/null +++ b/artifacts/example_mods/AmmoMod/AmmoMod.ini @@ -0,0 +1,201 @@ +;Example Ammo INI for vanilla damage formula + +; PID_EXPLOSIVE_ROCKET +[1] +pid=14 +ac_adjust=0 +dr_adjust=-25 +dam_mult=1 +dam_div=1 + +; PID_10MM_JHP +[2] +pid=29 +ac_adjust=0 +dr_adjust=25 +dam_mult=2 +dam_div=1 + +; PID_10MM_AP +[3] +pid=30 +ac_adjust=0 +dr_adjust=-25 +dam_mult=1 +dam_div=2 + +; PID_44_MAGNUM_JHP +[4] +pid=31 +ac_adjust=0 +dr_adjust=20 +dam_mult=2 +dam_div=1 + +; PID_FLAMETHROWER_FUEL +[5] +pid=32 +ac_adjust=-20 +dr_adjust=25 +dam_mult=1 +dam_div=1 + +; PID_14MM_AP +[6] +pid=33 +ac_adjust=0 +dr_adjust=-50 +dam_mult=1 +dam_div=2 + +; PID_223_FMJ +[7] +pid=34 +ac_adjust=-20 +dr_adjust=-20 +dam_mult=1 +dam_div=1 + +; PID_5MM_JHP +[8] +pid=35 +ac_adjust=0 +dr_adjust=35 +dam_mult=2 +dam_div=1 + +; PID_5MM_AP +[9] +pid=36 +ac_adjust=0 +dr_adjust=-35 +dam_mult=1 +dam_div=2 + +; PID_ROCKET_AP +[10] +pid=37 +ac_adjust=-15 +dr_adjust=-50 +dam_mult=1 +dam_div=1 + +; PID_SMALL_ENERGY_CELL +[11] +pid=38 +ac_adjust=0 +dr_adjust=0 +dam_mult=1 +dam_div=1 + +; PID_MICRO_FUSION_CELL +[12] +pid=39 +ac_adjust=0 +dr_adjust=0 +dam_mult=1 +dam_div=1 + +; PID_SHOTGUN_SHELLS +[13] +pid=95 +ac_adjust=-10 +dr_adjust=0 +dam_mult=1 +dam_div=1 + +; PID_44_FMJ_MAGNUM +[14] +pid=111 +ac_adjust=0 +dr_adjust=-20 +dam_mult=1 +dam_div=1 + +; PID_9MM_BALL +[15] +pid=121 +ac_adjust=0 +dr_adjust=0 +dam_mult=1 +dam_div=1 + +; PID_BBS +[16] +pid=163 +ac_adjust=0 +dr_adjust=0 +dam_mult=1 +dam_div=1 + +; PID_ROBO_ROCKET_AMMO +[17] +pid=274 +ac_adjust=0 +dr_adjust=-25 +dam_mult=1 +dam_div=1 + +; PID_45_CALIBER_AMMO +[18] +pid=357 +ac_adjust=0 +dr_adjust=0 +dam_mult=1 +dam_div=1 + +; PID_2MM_EC_AMMO +[19] +pid=358 +ac_adjust=-30 +dr_adjust=-20 +dam_mult=3 +dam_div=2 + +; PID_4_7MM_CASELESS +[20] +pid=359 +ac_adjust=-5 +dr_adjust=-10 +dam_mult=3 +dam_div=2 + +; PID_9MM_AMMO +[21] +pid=360 +ac_adjust=0 +dr_adjust=10 +dam_mult=1 +dam_div=2 + +; PID_HN_NEEDLER_CARTRIDGE +[22] +pid=361 +ac_adjust=-10 +dr_adjust=0 +dam_mult=1 +dam_div=1 + +; PID_HN_AP_NEEDLER_CARTRIDGE +[23] +pid=362 +ac_adjust=-10 +dr_adjust=0 +dam_mult=2 +dam_div=1 + +; PID_7_62MM_AMMO +[24] +pid=363 +ac_adjust=-5 +dr_adjust=-10 +dam_mult=1 +dam_div=1 + +; PID_FLAMETHROWER_FUEL_MK_II +[25] +pid=382 +ac_adjust=-20 +dr_adjust=0 +dam_mult=1 +dam_div=1 diff --git a/artifacts/example_mods/rain/weather.ini b/artifacts/example_mods/rain/weather.ini index e191546c2..0f6b5c8f8 100644 --- a/artifacts/example_mods/rain/weather.ini +++ b/artifacts/example_mods/rain/weather.ini @@ -352,7 +352,7 @@ special=60 ;Each map has 2 variables -; r{index}=region # corrisponds to a region section above +; r{index}=region # corresponds to a region section above ; a{index]=type # set to 0 for no weather or 1 for normal weather [Maps] @@ -547,7 +547,7 @@ r70=16 ;cavern encounter 1 a70=0 r71=16 ;cavern encounter 2 a71=0 -r72=16 ;cavern encoutner 3 +r72=16 ;cavern encounter 3 a72=0 r73=16 ;cavern encounter 4 a73=0 diff --git a/artifacts/scripting/README.md b/artifacts/scripting/README.md index ea108630f..fae0d659b 100644 --- a/artifacts/scripting/README.md +++ b/artifacts/scripting/README.md @@ -22,4 +22,4 @@ This folder contains documentation about sfall scripting extensions. arrays.md - manual for sfall arrays If you are/will be using sfall Script Editor, don't forget to check out new compiler documentation in **.\compiler\sslc_readme.md**. -There are numerious new syntax features and extensions to SSL (Star-Trek Scripting Language). +There are numerous new syntax features and extensions to SSL (Star-Trek Scripting Language). diff --git a/artifacts/scripting/README.txt b/artifacts/scripting/README.txt index 5d5bde972..703314e43 100644 --- a/artifacts/scripting/README.txt +++ b/artifacts/scripting/README.txt @@ -22,4 +22,4 @@ This folder contains documentation about sfall scripting extensions. arrays.html - manual for sfall arrays If you are/will be using sfall Script Editor, don't forget to check out new compiler documentation in .\compiler\sslc_readme.html. -There are numerious new syntax features and extensions to SSL (Star-Trek Scripting Language). +There are numerous new syntax features and extensions to SSL (Star-Trek Scripting Language). diff --git a/artifacts/scripting/arrays.md b/artifacts/scripting/arrays.md index 2745c3bb8..7f8fc690e 100644 --- a/artifacts/scripting/arrays.md +++ b/artifacts/scripting/arrays.md @@ -200,7 +200,7 @@ _*mixed means any type_ - if array was "saved", it will be removed from a savegame #### `mixed scan_array(int arrayID, mixed value)` -- searches for a first occurence of given value inside given array +- searches for a first occurrence of given value inside given array - if value is found, returns its index (for lists) or key (for maps) - if value is not found, returns -1 (be careful, as -1 can be a valid key for a map) diff --git a/artifacts/scripting/compiler/optimization.md b/artifacts/scripting/compiler/optimization.md index 3aa8a305d..08dd1b933 100644 --- a/artifacts/scripting/compiler/optimization.md +++ b/artifacts/scripting/compiler/optimization.md @@ -1,7 +1,7 @@ Optimization ------------ -The executation speed of scripts is not typically important in an unmodded game, given the difference in performance between a modern computer and what Fallout was designed for. When you start adding mods to the mix there's the potential for problems again, since sfall's global script system means that you can have a large amount of scripts being run every single frame. +The execution speed of scripts is not typically important in an unmodded game, given the difference in performance between a modern computer and what Fallout was designed for. When you start adding mods to the mix there's the potential for problems again, since sfall's global script system means that you can have a large amount of scripts being run every single frame. --- ### sslc -O option @@ -26,7 +26,7 @@ The sfall build of sslc supports a `-O` command line option to perform an optimi a := 4; -> ``` -- constant propagation: checks for values assigned to variables which can be computed at compile time, and replaces relevent references to the symbol by the constant. The original store is not removed by this optimization. Global variables are considered for this optimization only if they are not marked import or export, and are not assigned to anywhere in the script. +- constant propagation: checks for values assigned to variables which can be computed at compile time, and replaces relevant references to the symbol by the constant. The original store is not removed by this optimization. Global variables are considered for this optimization only if they are not marked import or export, and are not assigned to anywhere in the script. ``` a := 4; -> a := 4; foo(a); -> foo(4); @@ -103,8 +103,8 @@ The sfall build of sslc supports a `-O` command line option to perform an optimi -> end ``` -- Mark functions with `pure` or `inline` where relevent. +- Mark functions with `pure` or `inline` where relevant. * `pure` is a hint to the optimizer that a procedure has no side effects. (i.e. there's no way to tell that it's been called aside from its return value.) Pure procedures cannot modify global variables, or call any other procedure that isn't itself pure. Functions marked with pure can only be used in expressions (i.e. you cannot use the `call ` syntax to call them.) If there are non-pure terms in an expression, it prevents that expression being considered for dead store removal. Where no such optimizations can be performed, or if optimization is disabled, marking a procedure with pure will have no effect on the compiled code. - * `inline` is an instruction to the compiler to replace calls to the marked procedure with a copy of the procedures code instead of having a seperate call. Inlined procedures cannot use the `return` command, cannot be predefined, and cannot be used as part of an expression. Inlining if a procedure is only going to be called once is always a win, but if there are multiple calls to a procedure you will end up bloating the size of the generated code. + * `inline` is an instruction to the compiler to replace calls to the marked procedure with a copy of the procedures code instead of having a separate call. Inlined procedures cannot use the `return` command, cannot be predefined, and cannot be used as part of an expression. Inlining if a procedure is only going to be called once is always a win, but if there are multiple calls to a procedure you will end up bloating the size of the generated code. diff --git a/artifacts/scripting/compiler/sslc_readme.md b/artifacts/scripting/compiler/sslc_readme.md index 164fd3f69..a8d320066 100644 --- a/artifacts/scripting/compiler/sslc_readme.md +++ b/artifacts/scripting/compiler/sslc_readme.md @@ -99,7 +99,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by x := 5; ``` -- Multiple variable declaration: Multiple variables can be declared on one line, seperated by commas. This is an alterative to the ugly begin/end block, or the bulky single variable per line style. +- Multiple variable declaration: Multiple variables can be declared on one line, separated by commas. This is an alternative to the ugly begin/end block, or the bulky single variable per line style. - new: ``` variable a, b, c; @@ -131,7 +131,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by a := 4096; ``` -- Increment/decrement operators: `++` and `--` can be used as shorthand for `+= 1` and `-= 1` respectively. They are mearly a syntactic shorthand to improve readability, and so their use is only allowed where `+= 1` would normally be allowed. +- Increment/decrement operators: `++` and `--` can be used as shorthand for `+= 1` and `-= 1` respectively. They are merely a syntactic shorthand to improve readability, and so their use is only allowed where `+= 1` would normally be allowed. - new: ``` a++; @@ -222,7 +222,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by - Empty statements in blocks are allowed: This is just a convenience to save scripters a bit of memory. Some of the macros in the Fallout headers include their own semicolons while others do not. With the original compiler you had to remember which was which, and if you got it wrong the script would not compile. Now it's always safe to include your own semicolon, even if the macro already had its own. For example, this would not compile with the original sslc, but will with the sfall edition: ``` - #define my_macro diplay_msg("foo"); + #define my_macro display_msg("foo"); procedure start begin my_macro; @@ -230,7 +230,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by ``` __NOTE:__ **Does not work currently.** -- Procedure stringify operator `@`: Designed to make callback-procedures a better option and allow for basic functional programming. Basically it replaces procedure names preceeded by `@` by a string constant. +- Procedure stringify operator `@`: Designed to make callback-procedures a better option and allow for basic functional programming. Basically it replaces procedure names preceded by `@` by a string constant. - old: ``` callbackVar := "Node000"; @@ -397,7 +397,7 @@ There are several changes in this version of sslc which may result in problems f **sfall 3.6:** - added Python-style ternary operator (conditional expression) -- added `-s` short-circuit evalution option for `AND`, `OR` expressions +- added `-s` short-circuit evaluation option for `AND`, `OR` expressions - **int2ssl** will detect and decompile conditional expressions and short-circuit logical operators - added `-F` option to include full file paths in `#line` directives after preprocessing - added `-D` option to write abstract syntax tree into `.txt` file @@ -408,7 +408,7 @@ There are several changes in this version of sslc which may result in problems f - implemented stringify procedure names using `@` operator, which is helpful to pass procedures around to call them from variables (it will properly handle references) - logic for procedures passed as arguments to script functions was moved from code generation to parsing stage - now it is possible to call user-defined procedures inside argument list of script functions, without compiler attempting to treat them as procedure references and probably fail (procedures will still be passed, but only to appropriate script functions at appropriate argument positions) -- **int2ssl** will now place empty parantheses after a call to user-defined procedure - this will distinct calls from passing procedures to some script functions (like `giq_option`) +- **int2ssl** will now place empty parentheses after a call to user-defined procedure - this will distinct calls from passing procedures to some script functions (like `giq_option`) - fixed `inline` procedure "calls" not working when optimization is enabled - added column numbers to error/warning output - added code to simplify adding sfall opcodes into compiler (need to add code in 3 places, instead of 7 places for each opcode) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index eb7bf09bb..cb748ab93 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.1.7.1) + activesupport (6.1.7.3) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) diff --git a/docs/arrays.md b/docs/arrays.md index 0db5088c3..e670482e3 100644 --- a/docs/arrays.md +++ b/docs/arrays.md @@ -204,7 +204,7 @@ _*mixed means any type_ - if array was "saved", it will be removed from a savegame * `mixed scan_array(int arrayID, mixed value)`: - - searches for a first occurence of given value inside given array + - searches for a first occurrence of given value inside given array - if value is found, returns it's index (for lists) or key (for maps) - if value is not found, returns -1 (be careful, as -1 can be a valid key for a map) diff --git a/docs/optimization.md b/docs/optimization.md index c51d1954e..2f6e3efb1 100644 --- a/docs/optimization.md +++ b/docs/optimization.md @@ -12,7 +12,7 @@ nav_order: 5 * TOC {: toc} -The executation speed of scripts is not typically important in an unmodded game, given the difference in performance between a modern computer and what Fallout was designed for. When you start adding mods to the mix there's the potential for problems again, since sfall's global script system means that you can have a large amount of scripts being run every single frame. +The execution speed of scripts is not typically important in an unmodded game, given the difference in performance between a modern computer and what Fallout was designed for. When you start adding mods to the mix there's the potential for problems again, since sfall's global script system means that you can have a large amount of scripts being run every single frame. ## sslc -O option @@ -36,7 +36,7 @@ The sfall build of sslc supports a `-O` command line option to perform an optimi a := 4; -> ``` -- constant propagation: checks for values assigned to variables which can be computed at compile time, and replaces relevent references to the symbol by the constant. The original store is not removed by this optimization. Global variables are considered for this optimization only if they are not marked import or export, and are not assigned to anywhere in the script. +- constant propagation: checks for values assigned to variables which can be computed at compile time, and replaces relevant references to the symbol by the constant. The original store is not removed by this optimization. Global variables are considered for this optimization only if they are not marked import or export, and are not assigned to anywhere in the script. ``` a := 4; -> a := 4; foo(a); -> foo(4); @@ -112,8 +112,8 @@ The sfall build of sslc supports a `-O` command line option to perform an optimi -> end ``` -- Mark functions with `pure` or `inline` where relevent. +- Mark functions with `pure` or `inline` where relevant. * `pure` is a hint to the optimizer that a procedure has no side effects. (i.e. there's no way to tell that it's been called aside from its return value.) Pure procedures cannot modify global variables, or call any other procedure that isn't itself pure. Functions marked with pure can only be used in expressions (i.e. you cannot use the `call ` syntax to call them.) If there are non-pure terms in an expression, it prevents that expression being considered for dead store removal. Where no such optimizations can be performed, or if optimization is disabled, marking a procedure with pure will have no effect on the compiled code. - * `inline` is an instruction to the compiler to replace calls to the marked procedure with a copy of the procedures code instead of having a seperate call. Inlined procedures cannot use the `return` command, cannot be predefined, and cannot be used as part of an expression. Inlining if a procedure is only going to be called once is always a win, but if there are multiple calls to a procedure you will end up bloating the size of the generated code. + * `inline` is an instruction to the compiler to replace calls to the marked procedure with a copy of the procedures code instead of having a separate call. Inlined procedures cannot use the `return` command, cannot be predefined, and cannot be used as part of an expression. Inlining if a procedure is only going to be called once is always a win, but if there are multiple calls to a procedure you will end up bloating the size of the generated code. diff --git a/docs/sslc.md b/docs/sslc.md index e148dc097..32e2c1ed6 100644 --- a/docs/sslc.md +++ b/docs/sslc.md @@ -107,7 +107,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by x := 5; ``` -- Multiple variable declaration: Multiple variables can be declared on one line, seperated by commas. This is an alterative to the ugly begin/end block, or the bulky single variable per line style. +- Multiple variable declaration: Multiple variables can be declared on one line, separated by commas. This is an alternative to the ugly begin/end block, or the bulky single variable per line style. - new: ``` variable a, b, c; @@ -139,7 +139,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by a := 4096; ``` -- Increment/decrement operators: `++` and `--` can be used as shorthand for `+= 1` and `-= 1` respectively. They are mearly a syntactic shorthand to improve readability, and so their use is only allowed where `+= 1` would normally be allowed. +- Increment/decrement operators: `++` and `--` can be used as shorthand for `+= 1` and `-= 1` respectively. They are merely a syntactic shorthand to improve readability, and so their use is only allowed where `+= 1` would normally be allowed. - new: ``` a++; @@ -230,7 +230,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by - Empty statements in blocks are allowed: This is just a convenience to save scripters a bit of memory. Some of the macros in the Fallout headers include their own semicolons while others do not. With the original compiler you had to remember which was which, and if you got it wrong the script would not compile. Now it's always safe to include your own semicolon, even if the macro already had its own. For example, this would not compile with the original sslc, but will with the sfall edition: ``` - #define my_macro diplay_msg("foo"); + #define my_macro display_msg("foo"); procedure start begin my_macro; @@ -238,7 +238,7 @@ Syntax which requires sfall for compiled scripts to be interpreted is marked by ``` __NOTE:__ **Does not work currently.** -- Procedure stringify operator `@`: Designed to make callback-procedures a better option and allow for basic functional programming. Basically it replaces procedure names preceeded by `@` by a string constant. +- Procedure stringify operator `@`: Designed to make callback-procedures a better option and allow for basic functional programming. Basically it replaces procedure names preceded by `@` by a string constant. - old: ``` callbackVar := "Node000"; From 4fc282fa61b1c710f8d85746948fc9ffd87f22ef Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 29 Mar 2023 14:31:50 +0800 Subject: [PATCH 32/33] Minor edit to the changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbfa47a81..ba8c518cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -451,7 +451,7 @@ * Slightly increased the width of the car fuel gauge on the world map interface * New script function: `register_hook_proc_spec` * New hook script: `hs_stdprocedure` -* + ## 4.1.9.1 * Fixed the error handling for loading `sfallgv.sav` to improve backward compatibility with older saved games * Fixed `key_pressed` script function not working in `HOOK_KEYPRESS` hook script From 29ad2bf3b84acc3f04d405c483b583a88ebef0ee Mon Sep 17 00:00:00 2001 From: NovaRain Date: Fri, 31 Mar 2023 21:54:55 +0800 Subject: [PATCH 33/33] Recompressed sfall resource files --- artifacts/sfall.dat | Bin 158532 -> 158529 bytes artifacts/sfall_ru.dat | Bin 158790 -> 158787 bytes artifacts/sfall_zh.dat | Bin 158549 -> 158546 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/artifacts/sfall.dat b/artifacts/sfall.dat index 8ed060f752a7b02c1f52b8e5e5b0b2242e8def55..116c0a989f76b0651b00b95390b11bf67603539b 100644 GIT binary patch delta 23341 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 delta 23344 zcmW(+bzIY5898!sh|Gta>EDf7q+K?#A&!quvbmtVCmV7m$)J1?xkG zCJj&Ww~zNYw!?&wO{gLNs*dQ2gZZWX){w-@svXIRjb=!H1iE%7)rPxWo(0zacf1Lx zuURImpxe*%`kNFh-&z7+k@B}Yo!=}_mRWL|U>@^;u9pM7%0aY8qbqh|A2ch8l}q$s zdz~`@Zz9$%oU8Ip+=uc51@J(TGQ_CSQvjdHGHFiPw#!2B5UX1BBiTy)Hi z>ks*6<4t|_Oy7WS8g_Ai$zi2%EcO`!IXzE;c=|;(4cM}&{_fcd)N0^Kv`CJOFc@)2 zi_}k0Hi1pty94y*29a;B60!0xnP*3TeBtX((jN<;HJY%gOShF|?;OJRDDlb@;4EUQ zs-gPvr=yzO0G+xjao&5L{Kx&D9cVzz;(opLXAr z0g2fPr6&3z!1@t#IW(O;Mod1#6?Xz#>wu?7=7dEx?SskUvz3TR+`i8*vw>>wV*Y%X z9N~Jlg_TI8`Ge{)ieg&v%{x42?A|4Nch`_Q#qn(8rpCXl*I)B|LAbKT^CQ;Um4y0~ zsTBuvOQ9cnQ`s%d;v8DZ5o``wM6znuJj23-Pp2a}btiBd7O_o)n|p<}3UpG^f+y1@ zVJCo?$Jul9E z@hE%y-gLlxzBy09)N{hu1kX;y9p;TQo;&3rsaVWElbW!L6BJm8KFcjgM5O}LLKC;4 zWEYJMmKt~`rM-umB0-PWzLc@e)7qMzDjRKbAhjhx6~AMLEwI>nr5ey z!4f-D3O6nqVQif_Jw|9I*FQ`vBpT2UU~yd7Lz=kPh;@k!`pTv_h$7ECJcPeVA+!Kd zPc;>-^Ac4P)r(w_K(WD3buSgS4RA%vMMJfJC+iSMMGDW$(Ui>0DKON)HI;X`GJF{l z>6=d-lW)jQZtPaKydTS1cR^gPlhEV7eI*2Kc2{J98orAu&4q@eZ05dd*52ao`8|L{ zek^DPp+du=l&vJG)5qlZ>M8G)1*aQ ~o((fHD2tu8ibU^7Lbv;=HrI{H=+RvKth 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⁣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 delta 23344 zcmW(+bzIY5898!sh|Gta>EDf7q+K?#A&!quvbmtVCmV7m$)J1?xkG zCJj&Ww~zNYw!?&wO{gLNs*dQ2gZZWX){w-@svXIRjb=!H1iE%7)rPxWo(0zacf1Lx zuURImpxe*%`kNFh-&z7+k@B}Yo!=}_mRWL|U>@^;u9pM7%0aY8qbqh|A2ch8l}q$s zdz~`@Zz9$%oU8Ip+=uc51@J(TGQ_CSQvjdHGHFiPw#!2B5UX1BBiTy)Hi z>ks*6<4t|_Oy7WS8g_Ai$zi2%EcO`!IXzE;c=|;(4cM}&{_fcd)N0^Kv`CJOFc@)2 zi_}k0Hi1pty94y*29a;B60!0xnP*3TeBtX((jN<;HJY%gOShF|?;OJRDDlb@;4EUQ zs-gPvr=yzO0G+xjao&5L{Kx&D9cVzz;(opLXAr z0g2fPr6&3z!1@t#IW(O;Mod1#6?Xz#>wu?7=7dEx?SskUvz3TR+`i8*vw>>wV*Y%X z9N~Jlg_TI8`Ge{)ieg&v%{x42?A|4Nch`_Q#qn(8rpCXl*I)B|LAbKT^CQ;Um4y0~ zsTBuvOQ9cnQ`s%d;v8DZ5o``wM6znuJj23-Pp2a}btiBd7O_o)n|p<}3UpG^f+y1@ zVJCo?$Jul9E z@hE%y-gLlxzBy09)N{hu1kX;y9p;TQo;&3rsaVWElbW!L6BJm8KFcjgM5O}LLKC;4 zWEYJMmKt~`rM-umB0-PWzLc@e)7qMzDjRKbAhjhx6~AMLEwI>nr5ey z!4f-D3O6nqVQif_Jw|9I*FQ`vBpT2UU~yd7Lz=kPh;@k!`pTv_h$7ECJcPeVA+!Kd zPc;>-^Ac4P)r(w_K(WD3buSgS4RA%vMMJfJC+iSMMGDW$(Ui>0DKON)HI;X`GJF{l z>6=d-lW)jQZtPaKydTS1cR^gPlhEV7eI*2Kc2{J98orAu&4q@eZ05dd*52ao`8|L{ zek^DPp+du=l&vJG)5qlZ>M8G)1*aQ ~o((fHD2tu8ibU^7Lbv;=HrI{H=+RvKth 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 K0RR9}YXSg=(g#ui delta 23344 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