Merge branch 'develop'

This commit is contained in:
NovaRain
2019-02-12 09:22:18 +08:00
58 changed files with 1625 additions and 1410 deletions
+6 -5
View File
@@ -14,17 +14,18 @@ Part_0=1 ; Tell sfall that we want to modify the head entries
[c_00_0] ; The entries for the head table of the men critter type. [c_00_0] ; The entries for the head table of the men critter type.
e0_DamageMultiplier=100 ;First level critical e0_DamageMultiplier=100 ;First level critical
e0_EffectFlags=0 e0_EffectFlags=0 ; The value of the flags (see DAM_* in Define.h)
; For multiple effects, use the sum of the flags (e.g. 2050 = knocked down + bypass armor)
e0_StatCheck=0 e0_StatCheck=0
e0_StatMod=0 e0_StatMod=0
e0_FailureEffect=0 e0_FailureEffect=0
e0_Message=0 ; This is an index into the msg file, not a string e0_Message=0 ; This is an index into the msg file, not a string
e0_FailMessage=0 e0_FailMessage=0
e1_... ; Second level critical ;e1_... ; Second level critical
... ; And so on up to the hardest hitting level 5 critical ;... ; And so on up to the hardest hitting level 5 critical
e5_... ;e5_...
;You can skip any entries from this section to leave them at their defaults ;You can skip any entries from this section to leave them at their defaults
;Any missing entries for critters 19-37 will be replaced by a 0, since they have no default ;Any missing entries for critters 19-37 will be replaced by a 0, since they have no default
;Note that the UOP fixes are included in the defaults, and do not need to be ;Note that the UOP fixes are included in the defaults, and do not need to be
; added manually when using this override format, as opposed to the old one ; added manually when using this override format, as opposed to the old one
+6 -5
View File
@@ -1,12 +1,13 @@
; Allows to reassign books to different object PIDs, text messages. ; Allows to reassign books to different object PIDs, text messages, and skills.
; Maximum 30 books are allowed (25 if overrideVanilla is 0) ; Maximum 50 books are allowed
[main] [main]
; total number of books in this file ; total number of books in this file
count=5 count=1
; set to 1 to override all vanilla books, so you will have to define ALL books in this file; ; set to 1 to override all vanilla books, so you will have to define ALL the necessary books in this file;
; otherwise only new books are defined here ; otherwise only new books are defined here. To just override the text/skill of a vanilla book,
; specify its PID in the new book and set the parameters
overrideVanilla=0 overrideVanilla=0
; count starts from 1 ; count starts from 1
+25 -13
View File
@@ -1,5 +1,5 @@
;sfall configuration settings ;sfall configuration settings
;v4.1.4 ;v4.1.5
[Main] [Main]
;Change to 1 if you want to use command line args to tell sfall to use another ini file. ;Change to 1 if you want to use command line args to tell sfall to use another ini file.
@@ -34,18 +34,21 @@ Enable=1
;The speeds corresponding to each slot in percent. (i.e. 100 is normal speed) ;The speeds corresponding to each slot in percent. (i.e. 100 is normal speed)
SpeedMulti0=50 SpeedMulti0=50
SpeedMulti1=100 SpeedMulti1=100
SpeedMulti2=150 SpeedMulti2=200
SpeedMulti3=200 SpeedMulti3=300
SpeedMulti4=300 SpeedMulti4=400
SpeedMulti5=500 SpeedMulti5=500
SpeedMulti6=1000 SpeedMulti6=600
SpeedMulti7=100 SpeedMulti7=700
SpeedMulti8=100 SpeedMulti8=800
SpeedMulti9=100 SpeedMulti9=900
;The initial speed at game startup ;The initial speed at game startup
SpeedMultiInitial=100 SpeedMultiInitial=100
;Set to 1 to also affect the playback speed of mve video files without an audio track
AffectPlayback=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Graphics] [Graphics]
;Set to 0 for 8 bit fullscreen ;Set to 0 for 8 bit fullscreen
@@ -159,8 +162,7 @@ DebugEditorKey=0
;Time limit in years. Must be between -3 and 13 ;Time limit in years. Must be between -3 and 13
;Set to 0 if you want to die the instant you leave arroyo ;Set to 0 if you want to die the instant you leave arroyo
;Set to -1 to remove the time limit, and automatically reset the date back to 2241 each time you would have reached it ;Set to -1 to remove the time limit, and automatically reset the date back to 2241 each time you would have reached it
;Set to -2 to remove the time limit without resetting the date. The game will lock up on 8th of March 2255 ;Set to -2 or -3 to remove the time limit, automatically reset the date, but override Fallout's GetDate function to return the correct year
;Set to -3 to remove the time limit, automatically reset the date, but override Fallout's GetDate function to return the correct year
TimeLimit=13 TimeLimit=13
;World map travel time percentage modifier ;World map travel time percentage modifier
@@ -168,9 +170,6 @@ TimeLimit=13
;100 is normal speed, 0 stops time from passing ;100 is normal speed, 0 stops time from passing
WorldMapTimeMod=100 WorldMapTimeMod=100
;Set to 1 to enable functions relating to overriding the file system
UseFileSystemOverride=0
;Set to 1 to use the Fallout 1 code to control world map speed ;Set to 1 to use the Fallout 1 code to control world map speed
WorldMapFPSPatch=1 WorldMapFPSPatch=1
@@ -197,6 +196,9 @@ WorldMapSlots=0
;To use a config file other than fallout2.cfg, uncomment the next line and add the name of your new file ;To use a config file other than fallout2.cfg, uncomment the next line and add the name of your new file
;ConfigFile= ;ConfigFile=
;Set to 1 to enable functions relating to overriding the file system
UseFileSystemOverride=0
;To use a patch file other than patch000.dat, uncomment the next line and add your new file name ;To use a patch file other than patch000.dat, uncomment the next line and add your new file name
;If you want to check for multiple patch files, you can include a %d in the file name (sprintf syntax) ;If you want to check for multiple patch files, you can include a %d in the file name (sprintf syntax)
;By default, only the first patch file found will be used. ;By default, only the first patch file found will be used.
@@ -532,6 +534,13 @@ ObjCanHearObjFix=0
;If the argument value is -1, the mood will be determined by the local variable 0 of the script (vanilla behavior) ;If the argument value is -1, the mood will be determined by the local variable 0 of the script (vanilla behavior)
StartGDialogFix=0 StartGDialogFix=0
;Set to 1 to fix and repurpose the unused called_shot/num_attacks arguments of attack_complex script function
;This also changes the behavior of the result flags arguments
;called_shot - additional damage, when the damage received by the target is above the specified minimum damage
;num_attacks - the number of free action points on the first turn only
;attacker_results - unused, must be 0 or not equal to the target_results argument when specifying result flags for the target
AttackComplexFix=0
;Set to 1 to enable the balanced bullet distribution formula for burst attacks ;Set to 1 to enable the balanced bullet distribution formula for burst attacks
ComputeSprayMod=0 ComputeSprayMod=0
@@ -713,6 +722,9 @@ AlwaysFindScripts=0
;Set to 1 to force sfall to inject all hooks code into the game, even if corresponding hook scripts don't exist ;Set to 1 to force sfall to inject all hooks code into the game, even if corresponding hook scripts don't exist
InjectAllGameHooks=0 InjectAllGameHooks=0
;Set to 1 to hide error messages in debug output when a null value is passed to the function as an object
HideObjIsNullMsg=0
;These options control what output is saved in the debug log (sfall-log.txt) ;These options control what output is saved in the debug log (sfall-log.txt)
;Prints messages duing sfall initialization ;Prints messages duing sfall initialization
Binary file not shown.
@@ -1,7 +1,7 @@
/* /*
Auto Doors mod for Fallout 2 by Mr.Stalin Auto Doors mod v1.1 for Fallout 2 by Mr.Stalin
----------------------------------------- ----------------------------------------------
- allows the player to automatically open/walk through unlocked doors when not in combat - allows the player to automatically open/walk through unlocked doors when not in combat
@@ -12,66 +12,91 @@ NOTE: this script requires compiler from sfall modderspack with -s option
*/ */
/* Include Files */
#include "..\headers\define.h" #include "..\headers\define.h"
#include "..\headers\command.h" //#include "..\headers\command.h"
#include "..\headers\sfall\sfall.h" #include "..\..\scripting_docs\headers\sfall.h"
#include "..\headers\sfall\define_extra.h" #include "..\..\scripting_docs\headers\define_extra.h"
/* Standard Script Procedures */
procedure start; procedure start;
procedure map_enter_p_proc; procedure map_enter_p_proc;
procedure set_door_flag(variable state); procedure set_door_flag(variable state);
procedure set_door_flag_array(variable state);
procedure combatturn_handler; procedure combatturn_handler;
/* Defines */
#define PORTAL (0) #define PORTAL (0)
#define DOOR_FLAGS (0x24) #define DOOR_FLAGS (0x24)
variable only_once := 0; variable only_once := 0;
variable arrayPid;
procedure start begin procedure start begin
if game_loaded then begin if game_loaded then begin
if (sfall_ver_major >= 4) then if (sfall_ver_major >= 4) then
register_hook_proc(HOOK_COMBATTURN, combatturn_handler); register_hook_proc(HOOK_COMBATTURN, combatturn_handler);
else else
set_global_script_repeat(60); set_global_script_repeat(40); // for sfall 3.x
call map_enter_p_proc; call map_enter_p_proc;
end else begin end else begin
if (only_once == 1 and combat_is_initialized) then begin if (only_once == 1 and combat_is_initialized) then begin
only_once := 2; only_once := 2;
call set_door_flag(false); call set_door_flag(0); // reset flag when entering combat mode
end else if (only_once == 2 and not(combat_is_initialized)) then begin end else if (only_once == 2 and not(combat_is_initialized)) then begin
only_once := 1; only_once := 1;
if (sfall_ver_major >= 4) then if (sfall_ver_major >= 4) then set_global_script_repeat(0);
set_global_script_repeat(0); call set_door_flag(FLAG_WALKTHRU); // set flag after combat mode ends
call set_door_flag(FLAG_WALKTHRU);
end end
end end
end end
procedure map_enter_p_proc begin procedure map_enter_p_proc begin
if (arrayPid) then begin
// when changing maps, delete the current array to create a new one
free_array(arrayPid);
arrayPid := 0;
end
only_once := 1; only_once := 1;
call set_door_flag(FLAG_WALKTHRU); call set_door_flag(FLAG_WALKTHRU); // set flag when entering the map
end end
procedure set_door_flag(variable state) begin procedure set_door_flag(variable state) begin
variable objectMap, obj, objPid, arrayPid, i; variable objectMap, obj, objPid, i;
if (arrayPid) then begin
call set_door_flag_array(state);
return;
end
objectMap := list_as_array(LIST_SCENERY); objectMap := list_as_array(LIST_SCENERY);
arrayPid := temp_array(1, 0); arrayPid := create_array(0, 0);
foreach (obj in objectMap) begin foreach (obj in objectMap) begin
objPid := obj_pid(obj); objPid := obj_pid(obj);
if (proto_data(objPid, sc_type) != PORTAL) or is_in_array(objPid, arrayPid) then if (proto_data(objPid, sc_type) != PORTAL) or is_in_array(objPid, arrayPid) then
continue; continue; // next object
resize_array(arrayPid, i + 1);
arrayPid[i] := objPid; arrayPid[i] := objPid;
i++; i++;
resize_array(arrayPid, i + 1); set_proto_data(objPid, DOOR_FLAGS, state);
end
end
procedure set_door_flag_array(variable state) begin
variable objPid;
foreach (objPid in arrayPid) begin
set_proto_data(objPid, DOOR_FLAGS, state); set_proto_data(objPid, DOOR_FLAGS, state);
end end
end end
procedure combatturn_handler begin procedure combatturn_handler begin
if (only_once == 1) then if (only_once == 1) then begin
only_once := 2;
call set_door_flag_array(0);
set_global_script_repeat(60); set_global_script_repeat(60);
end
end end
+2 -2
View File
@@ -1,5 +1,5 @@
Auto Doors mod for Fallout 2 by Mr.Stalin Auto Doors mod v1.1 for Fallout 2 by Mr.Stalin
----------------------------------------- ----------------------------------------------
- allows the player to automatically open/walk through unlocked doors when not in combat - allows the player to automatically open/walk through unlocked doors when not in combat
+1
View File
@@ -238,6 +238,7 @@
#define party_member_list_all party_member_list(1) #define party_member_list_all party_member_list(1)
#define art_cache_clear sfall_func0("art_cache_clear")
#define attack_is_aimed sfall_func0("attack_is_aimed") #define attack_is_aimed sfall_func0("attack_is_aimed")
#define car_gas_amount sfall_func0("car_gas_amount") #define car_gas_amount sfall_func0("car_gas_amount")
#define create_win(winName, x, y, w, h) sfall_func5("create_win", winName, x, y, w, h) #define create_win(winName, x, y, w, h) sfall_func5("create_win", winName, x, y, w, h)
+1 -1
View File
@@ -464,7 +464,7 @@ Runs before and after each turn in combat (for both PC and NPC).
int arg1 - event type: 1 - start of turn, 0 - normal end of turn, -1 - combat ended abruptly (by script or by pressing Enter during PC turn) int arg1 - event type: 1 - start of turn, 0 - normal end of turn, -1 - combat ended abruptly (by script or by pressing Enter during PC turn)
int arg2 - critter doing the turn int arg2 - critter doing the turn
int arg3 - unknown boolean argument bool arg3 - set to 1 at the start of the player's turn after the game has been loaded, 0 otherwise
int ret1 - pass 1 at the start of turn to skip the turn, pass -1 at the end of turn to force end of combat int ret1 - pass 1 at the start of turn to skip the turn, pass -1 at the end of turn to force end of combat
+8 -4
View File
@@ -40,7 +40,7 @@ get/set_critter_current_ap functions should only be used during the target critt
The 'type' value in the weapon knockback functions can be 0 or 1. If 0, the value becomes an absolute distance that targets will be knocked back. If 1, the value is multiplied by the distance they would normally have been knocked back. Weapon knockback modifiers are applied in the order weapon -> attacker -> target, so a x2 weapon wielded by an abs 6 attacker hitting a /2 target will knock the target back 3 squares. The knockback functions will not override the stonewall perk or knockdowns resulting from criticals. knockback values set on weapons or critters are not saved, and must be reset each time the player reloads. The 'type' value in the weapon knockback functions can be 0 or 1. If 0, the value becomes an absolute distance that targets will be knocked back. If 1, the value is multiplied by the distance they would normally have been knocked back. Weapon knockback modifiers are applied in the order weapon -> attacker -> target, so a x2 weapon wielded by an abs 6 attacker hitting a /2 target will knock the target back 3 squares. The knockback functions will not override the stonewall perk or knockdowns resulting from criticals. knockback values set on weapons or critters are not saved, and must be reset each time the player reloads.
The get/set_sfall_global functions require an 8 character long case sensitive string for the variable name. The variables behave the same as normal Fallout globals, except that they don't have to be declared beforehand in vault13.gam. Trying to get a variable which hasn't been set will always return 0. These functions are intended for use when a patch to a mod requires the addition of a new global variable, a case which would otherwise require the player to start a new game. The get/set_sfall_global functions require an 8 characters long case sensitive string for the variable name. The variables behave the same as normal Fallout globals, except that they don't have to be declared beforehand in vault13.gam. Trying to get a variable which hasn't been set will always return 0. These functions are intended for use when a patch to a mod requires the addition of a new global variable, a case which would otherwise require the player to start a new game.
set_pickpocket_max and set_hit_chance_max effect all critters rather than just the player. set_skill_max can't be used to increase the skill cap above 300. set_perk_level_mod sets a modifier between +25 and -25 that is added/subtracted from the players level for the purposes of deciding which perks can be chosen. set_pickpocket_max and set_hit_chance_max effect all critters rather than just the player. set_skill_max can't be used to increase the skill cap above 300. set_perk_level_mod sets a modifier between +25 and -25 that is added/subtracted from the players level for the purposes of deciding which perks can be chosen.
@@ -60,7 +60,7 @@ get/set_unspent_ap_bonus alter the AC bonus you receive per unused action point
nb_* functions are reserved for the brotherhood tactical training mod, and should be avoided. nb_* functions are reserved for the brotherhood tactical training mod, and should be avoided.
The fs_* functions are used to manipulate a virtual file system. Files saved here should have paths relative to the data folder, and use backslashes as the directory separator. They will take precedence over files stored in the normal data folder. They will also be saved into save games, so be avoid creating large files. Using fs_copy followed by fs_read_xxx, you can read the contents of existing files. The fs_* functions are used to manipulate a virtual file system. Files saved here should have paths relative to the data folder, and use backslashes as the directory separator. They will take precedence over files stored in the normal data folder. They will also be saved into save games if you set a flag for them using fs_resize(fileId, -1), so be avoid creating large files. Using fs_copy followed by fs_read_xxx, you can read the contents of existing files.
get/set_proto_data are used to manipulate the in memory copies of the .pro files Fallout makes when they are loaded. The offset refers to the offset in memory from the start of the proto to the element you are reading. Changes are not stored on disc, and are not permanent. If you modify the protos, and then Fallout subsequently reloads the file your changes will be lost. get/set_proto_data are used to manipulate the in memory copies of the .pro files Fallout makes when they are loaded. The offset refers to the offset in memory from the start of the proto to the element you are reading. Changes are not stored on disc, and are not permanent. If you modify the protos, and then Fallout subsequently reloads the file your changes will be lost.
@@ -163,8 +163,9 @@ array - array ID to be used with array-related functions (actually an integer)
- overrides the scripts self_obj for the next function call. - overrides the scripts 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; - 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 revert back to its original value after the next function call. - self_obj will revert back to its original value after the next function call.
- calling self_obj(0) will also revert self_obj to original value - calling self_obj(0) will also revert self_obj to original value. It is recommended to call this after each use of set_self in normal scripts in order to avoid unforeseen side effects.
- source_obj, target_obj, and similar functions will not work if preceded by "set_self" - source_obj, target_obj, and similar functions will not work if preceded by "set_self"
- NOTE: for use_obj/use_obj_on_obj vanilla functions to work correctly, it is required to call set_self twice.
> void mod_skill_points_per_level(int x) > void mod_skill_points_per_level(int x)
- accepts a value of between -100 and 100, and modifies the number of skill points the player receives when they level up. - accepts a value of between -100 and 100, and modifies the number of skill points the player receives when they level up.
@@ -292,7 +293,7 @@ Some utility/math functions are available:
> float sqrt(float x) > float sqrt(float x)
- square root of x - square root of x
> float abs(float x) > int/float abs(int/float x)
- absolute (positive) value of x - absolute (positive) value of x
> float sin(float x) > float sin(float x)
@@ -560,6 +561,9 @@ Some utility/math functions are available:
- returns the setting value from the AI packet of an object (critter) - returns the setting value from the AI packet of an object (critter)
- use AI_CAP_* constants from define_extra.h for the aiParam argument to get AI value - use AI_CAP_* constants from define_extra.h for the aiParam argument to get AI value
> void sfall_func0("art_cache_clear")
- clears the cache of FRM image files loaded into memory
------------------------ ------------------------
------ MORE INFO ------- ------ MORE INFO -------
------------------------ ------------------------
+1 -1
View File
@@ -219,7 +219,7 @@
0x81e9 - int get_unspent_ap_perk_bonus() 0x81e9 - int get_unspent_ap_perk_bonus()
0x81ec - float sqrt(float) 0x81ec - float sqrt(float)
0x81ed - float abs(float) 0x81ed - int/float abs(int/float)
0x81ee - float sin(float) 0x81ee - float sin(float)
0x81ef - float cos(float) 0x81ef - float cos(float)
0x81f0 - float tan(float) 0x81f0 - float tan(float)
+6 -1
View File
@@ -631,7 +631,12 @@ enum AttackType : long
#define CRITTER_EYEDAMAGE (0x40) #define CRITTER_EYEDAMAGE (0x40)
#define WEAPON_TWO_HANDED (0x200) #define WEAPON_TWO_HANDED (0x200)
enum TicksTime : unsigned long
{
ONE_GAME_YEAR = 315360000
};
enum RollResult enum RollResult
{ {
+9
View File
@@ -700,4 +700,13 @@ struct AIcap {
long general_type; long general_type;
}; };
#pragma pack(1)
struct Queue {
DWORD time;
long type;
GameObject* object;
long data;
Queue* next;
};
} }
+1
View File
@@ -28,6 +28,7 @@
#define FO_VAR_character_points 0x518538 #define FO_VAR_character_points 0x518538
#define FO_VAR_cmap 0x51DF34 #define FO_VAR_cmap 0x51DF34
#define FO_VAR_colorTable 0x6A38D0 #define FO_VAR_colorTable 0x6A38D0
#define FO_VAR_combat_end_due_to_load 0x517F98
#define FO_VAR_combat_free_move 0x56D39C #define FO_VAR_combat_free_move 0x56D39C
#define FO_VAR_combat_list 0x56D390 #define FO_VAR_combat_list 0x56D390
#define FO_VAR_combat_state 0x510944 #define FO_VAR_combat_state 0x510944
+13 -15
View File
@@ -49,7 +49,7 @@ static double mousePartX;
static double mousePartY; static double mousePartY;
#define MAX_KEYS (264) #define MAX_KEYS (264)
static DWORD keysDown[MAX_KEYS]; static DWORD keysDown[MAX_KEYS] = {0};
static int mouseX; static int mouseX;
static int mouseY; static int mouseY;
@@ -125,9 +125,9 @@ void _stdcall TapKey(DWORD key) {
data.dwTimeStamp = 0; data.dwTimeStamp = 0;
data.dwSequence = 0; data.dwSequence = 0;
data.dwOfs = key; data.dwOfs = key;
data.dwData = 0x80; data.dwData = 0x80; // flag pressed
bufferedPresses.push(data); bufferedPresses.push(data);
data.dwData = 0x00; data.dwData = 0x00; // flag released
bufferedPresses.push(data); bufferedPresses.push(data);
} }
@@ -193,7 +193,7 @@ public:
return RealDevice->Unacquire(); return RealDevice->Unacquire();
} }
//Only called for the mouse // Only called for the mouse
HRESULT _stdcall GetDeviceState(DWORD a, LPVOID b) { HRESULT _stdcall GetDeviceState(DWORD a, LPVOID b) {
if (forcingGraphicsRefresh) RefreshGraphics(); if (forcingGraphicsRefresh) RefreshGraphics();
if (DeviceType != kDeviceType_MOUSE) { if (DeviceType != kDeviceType_MOUSE) {
@@ -212,10 +212,10 @@ public:
MouseState.rgbButtons[1] = tmp; MouseState.rgbButtons[1] = tmp;
} }
if (adjustMouseSpeed) { if (adjustMouseSpeed) {
double d = ((double)MouseState.lX)*mouseSpeedMod + mousePartX; double d = ((double)MouseState.lX) * mouseSpeedMod + mousePartX;
mousePartX = modf(d, &d); mousePartX = modf(d, &d);
MouseState.lX = (LONG)d; MouseState.lX = (LONG)d;
d = ((double)MouseState.lY)*mouseSpeedMod + mousePartY; d = ((double)MouseState.lY) * mouseSpeedMod + mousePartY;
mousePartY = modf(d, &d); mousePartY = modf(d, &d);
MouseState.lY = (LONG)d; MouseState.lY = (LONG)d;
} }
@@ -263,7 +263,7 @@ public:
return 0; return 0;
} }
//Only called for the keyboard // Only called for the keyboard
HRESULT _stdcall GetDeviceData(DWORD a, DIDEVICEOBJECTDATA* b, DWORD* c, DWORD d) { HRESULT _stdcall GetDeviceData(DWORD a, DIDEVICEOBJECTDATA* b, DWORD* c, DWORD d) {
if (DeviceType != kDeviceType_KEYBOARD) { if (DeviceType != kDeviceType_KEYBOARD) {
return RealDevice->GetDeviceData(a, b, c, d); return RealDevice->GetDeviceData(a, b, c, d);
@@ -271,7 +271,7 @@ public:
onInputLoop.invoke(); onInputLoop.invoke();
if (!b || bufferedPresses.empty() || (d&DIGDD_PEEK)) { if (!b || bufferedPresses.empty() || (d & DIGDD_PEEK)) {
HRESULT hr = RealDevice->GetDeviceData(a, b, c, d); HRESULT hr = RealDevice->GetDeviceData(a, b, c, d);
if (FAILED(hr) || !b || !(*c)) return hr; if (FAILED(hr) || !b || !(*c)) return hr;
for (DWORD i = 0; i < *c; i++) { for (DWORD i = 0; i < *c; i++) {
@@ -295,7 +295,7 @@ public:
} }
HRESULT _stdcall SetDataFormat(const DIDATAFORMAT* a) { HRESULT _stdcall SetDataFormat(const DIDATAFORMAT* a) {
if (formatLock&&oldFormat.dwSize) return RealDevice->SetDataFormat(&oldFormat); if (formatLock && oldFormat.dwSize) return RealDevice->SetDataFormat(&oldFormat);
memcpy(&oldFormat, a, sizeof(DIDATAFORMAT)); memcpy(&oldFormat, a, sizeof(DIDATAFORMAT));
return RealDevice->SetDataFormat(a); return RealDevice->SetDataFormat(a);
} }
@@ -305,8 +305,8 @@ public:
} }
HRESULT _stdcall SetCooperativeLevel(HWND a, DWORD b) { HRESULT _stdcall SetCooperativeLevel(HWND a, DWORD b) {
if (DeviceType == kDeviceType_KEYBOARD&&backgroundKeyboard) b = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE; if (DeviceType == kDeviceType_KEYBOARD && backgroundKeyboard) b = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
if (DeviceType == kDeviceType_MOUSE&&backgroundMouse) b = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE; if (DeviceType == kDeviceType_MOUSE && backgroundMouse) b = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
return RealDevice->SetCooperativeLevel(a, b); return RealDevice->SetCooperativeLevel(a, b);
} }
@@ -362,8 +362,8 @@ public:
/*** IDirectInput8A methods ***/ /*** IDirectInput8A methods ***/
HRESULT _stdcall CreateDevice(REFGUID r, IDirectInputDeviceA** device, IUnknown* unused) { HRESULT _stdcall CreateDevice(REFGUID r, IDirectInputDeviceA** device, IUnknown* unused) {
GUID GUID_SysMouse = { 0x6F1D2B60, 0xD5A0, 0x11CF, { 0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00} }; GUID GUID_SysMouse = { 0x6F1D2B60, 0xD5A0, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} };
GUID GUID_SysKeyboard = { 0x6F1D2B61, 0xD5A0, 0x11CF, { 0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00} }; GUID GUID_SysKeyboard = { 0x6F1D2B61, 0xD5A0, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} };
if (r != GUID_SysKeyboard && r != GUID_SysMouse) { if (r != GUID_SysKeyboard && r != GUID_SysMouse) {
return RealInput->CreateDevice(r, device, unused); return RealInput->CreateDevice(r, device, unused);
@@ -406,8 +406,6 @@ public:
}; };
inline void InitInputFeatures() { inline void InitInputFeatures() {
ZeroMemory(keysDown, sizeof(keysDown));
reverseMouse = GetConfigInt("Input", "ReverseMouseButtons", 0) != 0; reverseMouse = GetConfigInt("Input", "ReverseMouseButtons", 0) != 0;
useScrollWheel = GetConfigInt("Input", "UseScrollWheel", 1) != 0; useScrollWheel = GetConfigInt("Input", "UseScrollWheel", 1) != 0;
+55 -52
View File
@@ -22,12 +22,11 @@
#include "Books.h" #include "Books.h"
namespace sfall namespace sfall
{ {
static int BooksCount = 0; static int BooksCount = 0;
static const int BooksMax = 30; static const int BooksMax = 50;
static char iniBooks[MAX_PATH];
struct sBook { struct sBook {
DWORD bookPid; DWORD bookPid;
@@ -35,10 +34,10 @@ struct sBook {
DWORD skill; DWORD skill;
}; };
static sBook books[BooksMax]; static sBook* books = nullptr;
static sBook* _stdcall FindBook(DWORD pid) { static sBook* __fastcall FindBook(DWORD pid) {
for (int i = 0; i < BooksCount; i++) { for (int i = BooksCount; i >= 0; i--) {
if (books[i].bookPid == pid) { if (books[i].bookPid == pid) {
return &books[i]; return &books[i];
} }
@@ -49,73 +48,77 @@ static sBook* _stdcall FindBook(DWORD pid) {
static const DWORD obj_use_book_hook_back = 0x49BA5A; static const DWORD obj_use_book_hook_back = 0x49BA5A;
static void __declspec(naked) obj_use_book_hook() { static void __declspec(naked) obj_use_book_hook() {
__asm { __asm {
push eax; mov edi, -1;
mov ecx, eax;
call FindBook; call FindBook;
test eax, eax; test eax, eax;
jnz found; cmovnz edi, [eax + 4]; // msgID
mov edi, -1; cmovnz ecx, [eax + 8]; // skill
jmp end; jmp obj_use_book_hook_back;
found:
mov edi, [eax + 4];
mov ecx, [eax + 8];
end:
jmp obj_use_book_hook_back;
} }
} }
void LoadVanillaBooks() { static void LoadVanillaBooks() {
int i = BooksCount;
// book of science // book of science
books[i + 0].bookPid = 73; books[0].bookPid = 73;
books[i + 0].msgID = 802; books[0].msgID = 802;
books[i + 0].skill = 12; books[0].skill = 12;
// Dean's electronics // Dean's electronics
books[i + 1].bookPid = 76; books[1].bookPid = 76;
books[i + 1].msgID = 803; books[1].msgID = 803;
books[i + 1].skill = 13; books[1].skill = 13;
// First Aid // First Aid
books[i + 2].bookPid = 80; books[2].bookPid = 80;
books[i + 2].msgID = 804; books[2].msgID = 804;
books[i + 2].skill = 6; books[2].skill = 6;
// Guns & Bullets // Guns & Bullets
books[i + 3].bookPid = 102; books[3].bookPid = 102;
books[i + 3].msgID = 805; books[3].msgID = 805;
books[i + 3].skill = 0; books[3].skill = 0;
// Scouts Handbook // Scouts Handbook
books[i + 4].bookPid = 86; books[4].bookPid = 86;
books[i + 4].msgID = 806; books[4].msgID = 806;
books[i + 4].skill = 17; books[4].skill = 17;
BooksCount += 5;
} }
void Books::init() { void Books::init() {
auto booksFile = GetConfigString("Misc", "BooksFile", "", MAX_PATH); auto booksFile = GetConfigString("Misc", "BooksFile", "", MAX_PATH);
if (booksFile.size() > 0) { if (!booksFile.empty()) {
sprintf(iniBooks, ".\\%s", booksFile.c_str());
dlog("Applying books patch...", DL_INIT); dlog("Applying books patch...", DL_INIT);
memset(books, 0, sizeof(sBook)*BooksCount); const char* iniBooks = booksFile.insert(0, ".\\").c_str();
int i, n = 0, count; bool includeVanilla = (GetPrivateProfileIntA("main", "overrideVanilla", 0, iniBooks) == 0);
if (GetPrivateProfileIntA("main", "overrideVanilla", 0, iniBooks) == 0) { if (includeVanilla) BooksCount = 5;
LoadVanillaBooks();
}
count = GetPrivateProfileIntA("main", "count", 0, iniBooks);
char section[4]; int count = max(0, GetPrivateProfileIntA("main", "count", 0, iniBooks));
for (i = 1; i <= count; i++) { if (count > BooksMax) count = BooksMax;
_itoa_s(i, section, 10);
if (BooksCount >= BooksMax) break; int n = 0;
if (books[BooksCount].bookPid = GetPrivateProfileIntA(section, "PID", 0, iniBooks)) { if (count > 0) {
books[BooksCount].msgID = GetPrivateProfileIntA(section, "TextID", 0, iniBooks); books = new sBook[BooksCount + count];
books[BooksCount].skill = GetPrivateProfileIntA(section, "Skill", 0, iniBooks);
n++; if (includeVanilla) LoadVanillaBooks();
BooksCount++;
char section[4];
for (int i = 1; i <= count; i++) {
_itoa_s(i, section, 10);
if (books[BooksCount].bookPid = GetPrivateProfileIntA(section, "PID", 0, iniBooks)) {
books[BooksCount].msgID = GetPrivateProfileIntA(section, "TextID", 0, iniBooks);
books[BooksCount].skill = GetPrivateProfileIntA(section, "Skill", 0, iniBooks);
BooksCount++;
n++;
}
} }
} BooksCount--; // set to last index
MakeJump(0x49B9FB, obj_use_book_hook); MakeJump(0x49B9FB, obj_use_book_hook);
}
dlog_f(" (%d/%d books) Done\n", DL_INIT, n, count); dlog_f(" (%d/%d books) Done\n", DL_INIT, n, count);
} }
} }
void Books::exit() {
if (books) delete[] books;
}
} }
+1
View File
@@ -27,6 +27,7 @@ class Books : public Module {
public: public:
const char* name() { return "Books"; } const char* name() { return "Books"; }
void init(); void init();
void exit() override;
}; };
} }
+141 -32
View File
@@ -17,9 +17,9 @@ static DWORD weightOnBody = 0;
static char textBuf[355]; static char textBuf[355];
void ResetBodyState() { void ResetBodyState() {
_asm mov critterBody, 0; __asm mov critterBody, 0;
_asm mov sizeOnBody, 0; __asm mov sizeOnBody, 0;
_asm mov weightOnBody, 0; __asm mov weightOnBody, 0;
} }
void GameInitialization() { void GameInitialization() {
@@ -1166,13 +1166,13 @@ end:
static void __declspec(naked) use_inventory_on_hack() { static void __declspec(naked) use_inventory_on_hack() {
__asm { __asm {
inc ecx inc ecx;
mov edx, [eax] // Inventory.inv_size mov edx, [eax]; // Inventory.inv_size
sub edx, ecx sub edx, ecx;
jge end jge end;
mov edx, [eax] // Inventory.inv_size mov edx, [eax]; // Inventory.inv_size
end: end:
retn retn;
} }
} }
@@ -1610,7 +1610,7 @@ static void __declspec(naked) op_start_gdialog_hack() {
mov eax, dword ptr [esp + 0x3C - 0x30 + 4]; // fix dialog_target (overwritten engine code) mov eax, dword ptr [esp + 0x3C - 0x30 + 4]; // fix dialog_target (overwritten engine code)
retn; retn;
useMood: useMood:
add esp, 4; // Destroy the return address add esp, 4; // Destroy the return address
jmp op_start_gdialog_ret; jmp op_start_gdialog_ret;
} }
} }
@@ -1741,6 +1741,72 @@ skip:
} }
} }
static void __declspec(naked) combat_attack_hack() {
__asm {
mov ebx, ds:[FO_VAR_main_ctd + 0x2C]; // amountTarget
test ebx, ebx;
jz end;
retn;
end:
add esp, 4;
mov ebx, 0x423039;
jmp ebx;
}
}
static void __declspec(naked) op_attack_hook() {
__asm {
mov esi, dword ptr [esp + 0x3C + 4]; // free_move
mov ebx, dword ptr [esp + 0x40 + 4]; // add amount damage to target
jmp fo::funcoffs::gdialogActive_;
}
}
static void __declspec(naked) op_use_obj_on_obj_hack() {
__asm {
test eax, eax; // source
jz fail;
mov edx, [eax + protoId];
shr edx, 24;
retn;
fail:
add esp, 4;
mov edx, 0x45C3A3; // exit func
jmp edx;
}
}
static void __declspec(naked) op_use_obj_hack() {
__asm {
test eax, eax; // source
jz fail;
mov edx, [eax + protoId];
shr edx, 24;
retn;
fail:
add esp, 4;
mov edx, 0x456ABA; // exit func
jmp edx;
}
}
static const DWORD combat_End = 0x422E45;
static const DWORD combat_Load = 0x422E91;
static void __declspec(naked) combat_hack_load() {
__asm {
cmp eax, -1;
je skip;
retn;
skip:
add esp, 4; // destroy addr
cmp ds:[FO_VAR_combat_end_due_to_load], 0;
jnz isLoad;
jmp combat_End;
isLoad:
jmp combat_Load;
}
}
void BugFixes::init() void BugFixes::init()
{ {
@@ -1771,7 +1837,7 @@ void BugFixes::init()
dlog("Applying Sharpshooter patch.", DL_INIT); dlog("Applying Sharpshooter patch.", DL_INIT);
// http://www.nma-fallout.com/threads/fo2-engine-tweaks-sfall.178390/page-119#post-4050162 // http://www.nma-fallout.com/threads/fo2-engine-tweaks-sfall.178390/page-119#post-4050162
// by Slider2k // by Slider2k
HookCall(0x4244AB, &SharpShooterFix); // hooks stat_level_() call in detemine_to_hit_func_() HookCall(0x4244AB, SharpShooterFix); // hooks stat_level_() call in detemine_to_hit_func_()
// // removes this line by making unconditional jump: // // removes this line by making unconditional jump:
// if ( who == obj_dude ) // if ( who == obj_dude )
// dist -= 2 * perk_level_(obj_dude, PERK_sharpshooter); // dist -= 2 * perk_level_(obj_dude, PERK_sharpshooter);
@@ -1792,8 +1858,8 @@ void BugFixes::init()
// Fix for "Too Many Items" bug // Fix for "Too Many Items" bug
//if (GetConfigInt("Misc", "TooManyItemsBugFix", 1)) { //if (GetConfigInt("Misc", "TooManyItemsBugFix", 1)) {
dlog("Applying preventive patch for \"Too Many Items\" bug.", DL_INIT); dlog("Applying preventive patch for \"Too Many Items\" bug.", DL_INIT);
HookCall(0x4A596A, &scr_write_ScriptNode_hook); HookCall(0x4A596A, scr_write_ScriptNode_hook);
HookCall(0x4A59C1, &scr_write_ScriptNode_hook); HookCall(0x4A59C1, scr_write_ScriptNode_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
@@ -1814,7 +1880,7 @@ void BugFixes::init()
// Fix crash when leaving the map while waiting for someone to die of a super stimpak overdose // 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_INIT); dlog("Applying fix for \"leaving the map while waiting for a super stimpak overdose death\" crash.", DL_INIT);
HookCall(0x4A27E7, &queue_clear_type_mem_free_hook); // hooks mem_free_() HookCall(0x4A27E7, queue_clear_type_mem_free_hook); // hooks mem_free_()
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
// Evil bug! If party member has the same armor type in inventory as currently equipped, then // Evil bug! If party member has the same armor type in inventory as currently equipped, then
@@ -1822,14 +1888,14 @@ void BugFixes::init()
// The same happens if you just order NPC to remove the armor through dialogue. // The same happens if you just order NPC to remove the armor through dialogue.
//if (GetConfigInt("Misc", "ArmorCorruptsNPCStatsFix", 1)) { //if (GetConfigInt("Misc", "ArmorCorruptsNPCStatsFix", 1)) {
dlog("Applying fix for armor reducing NPC original stats when removed.", DL_INIT); dlog("Applying fix for armor reducing NPC original stats when removed.", DL_INIT);
HookCall(0x495F3B, &partyMemberCopyLevelInfo_stat_level_hook); HookCall(0x495F3B, partyMemberCopyLevelInfo_stat_level_hook);
HookCall(0x45419B, &correctFidForRemovedItem_adjust_ac_hook); HookCall(0x45419B, correctFidForRemovedItem_adjust_ac_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
// Fix of invalid stats when party member gains a level while being on drugs // 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_INIT); dlog("Applying fix for addicted party member level up bug.", DL_INIT);
HookCall(0x495D5C, &partyMemberCopyLevelInfo_hook); HookCall(0x495D5C, partyMemberCopyLevelInfo_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
// Allow 9 options (lines of text) to be displayed correctly in a dialog window // Allow 9 options (lines of text) to be displayed correctly in a dialog window
@@ -1841,7 +1907,7 @@ void BugFixes::init()
// Fix for "Unlimited Ammo" exploit // Fix for "Unlimited Ammo" exploit
dlog("Applying fix for Unlimited Ammo exploit.", DL_INIT); dlog("Applying fix for Unlimited Ammo exploit.", DL_INIT);
HookCall(0x472957, &invenWieldFunc_item_get_type_hook); // hooks item_get_type_() HookCall(0x472957, invenWieldFunc_item_get_type_hook); // hooks item_get_type_()
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
// Fix for negative values in Skilldex window ("S") // Fix for negative values in Skilldex window ("S")
@@ -1853,8 +1919,8 @@ void BugFixes::init()
dlog("Applying fix for negative SPECIAL values in character creation.", DL_INIT); dlog("Applying fix for negative SPECIAL values in character creation.", DL_INIT);
MakeCall(0x43DF6F, is_supper_bonus_hack); MakeCall(0x43DF6F, is_supper_bonus_hack);
MakeCall(0x434BFF, PrintBasicStat_hack); MakeCall(0x434BFF, PrintBasicStat_hack);
HookCall(0x437AB4, &StatButtonUp_hook); HookCall(0x437AB4, StatButtonUp_hook);
HookCall(0x437B26, &StatButtonDown_hook); HookCall(0x437B26, StatButtonDown_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
// Fix for not counting in the weight/size of equipped items on NPC when stealing or bartering // Fix for not counting in the weight/size of equipped items on NPC when stealing or bartering
@@ -1883,7 +1949,7 @@ void BugFixes::init()
// also for reverse order error // also for reverse order error
MakeJump(0x47114A, inven_pickup_hack2); MakeJump(0x47114A, inven_pickup_hack2);
// Fix for using only one box of ammo when a weapon is above the ammo in the inventory list // 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); HookCall(0x476598, drop_ammo_into_weapon_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
@@ -1895,13 +1961,13 @@ void BugFixes::init()
//if (GetConfigInt("Misc", "BlackSkilldexFix", 1)) { //if (GetConfigInt("Misc", "BlackSkilldexFix", 1)) {
dlog("Applying black Skilldex patch.", DL_INIT); dlog("Applying black Skilldex patch.", DL_INIT);
HookCall(0x497D0F, &PipStatus_AddHotLines_hook); HookCall(0x497D0F, PipStatus_AddHotLines_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
//if (GetConfigInt("Misc", "FixWithdrawalPerkDescCrash", 1)) { //if (GetConfigInt("Misc", "FixWithdrawalPerkDescCrash", 1)) {
dlog("Applying withdrawal perk description crash fix.", DL_INIT); dlog("Applying withdrawal perk description crash fix.", DL_INIT);
HookCall(0x47A501, &perform_withdrawal_start_display_print_hook); HookCall(0x47A501, perform_withdrawal_start_display_print_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
@@ -1940,7 +2006,7 @@ void BugFixes::init()
//if (GetConfigInt("Misc", "WieldObjCritterFix", 1)) { //if (GetConfigInt("Misc", "WieldObjCritterFix", 1)) {
dlog("Applying wield_obj_critter fix.", DL_INIT); dlog("Applying wield_obj_critter fix.", DL_INIT);
SafeWrite8(0x456912, 0x1E); SafeWrite8(0x456912, 0x1E);
HookCall(0x45697F, &op_wield_obj_critter_adjust_ac_hook); HookCall(0x45697F, op_wield_obj_critter_adjust_ac_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
@@ -1966,7 +2032,7 @@ void BugFixes::init()
MakeCall(0x424F8E, set_new_results_hack); MakeCall(0x424F8E, set_new_results_hack);
MakeJump(0x42E46E, critter_wake_clear_hack); MakeJump(0x42E46E, critter_wake_clear_hack);
MakeJump(0x488EF3, obj_load_func_hack); MakeJump(0x488EF3, obj_load_func_hack);
HookCall(0x4949B2, &partyMemberPrepLoadInstance_hook); HookCall(0x4949B2, partyMemberPrepLoadInstance_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
@@ -1985,7 +2051,7 @@ void BugFixes::init()
SafeWrite8(0x478115, 0xBA); SafeWrite8(0x478115, 0xBA);
SafeWrite8(0x478138, 0xBA); SafeWrite8(0x478138, 0xBA);
MakeJump(0x474D22, barter_attempt_transaction_hack); MakeJump(0x474D22, barter_attempt_transaction_hack);
HookCall(0x4798B1, &item_m_turn_off_hook); HookCall(0x4798B1, item_m_turn_off_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
} }
@@ -2020,7 +2086,7 @@ void BugFixes::init()
// Fix for display issues when calling gdialog_mod_barter with critters with no "Barter" flag set // Fix for display issues when calling gdialog_mod_barter with critters with no "Barter" flag set
//if (GetConfigInt("Misc", "gdBarterDispFix", 1)) { //if (GetConfigInt("Misc", "gdBarterDispFix", 1)) {
dlog("Applying gdialog_mod_barter display fix.", DL_INIT); dlog("Applying gdialog_mod_barter display fix.", DL_INIT);
HookCall(0x448250, &gdActivateBarter_hook); HookCall(0x448250, gdActivateBarter_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
@@ -2052,7 +2118,7 @@ void BugFixes::init()
// Fix for Bonus Move APs being replenished when you save and load the game in combat // Fix for Bonus Move APs being replenished when you save and load the game in combat
//if (GetConfigInt("Misc", "BonusMoveFix", 1)) { //if (GetConfigInt("Misc", "BonusMoveFix", 1)) {
dlog("Applying fix for Bonus Move exploit.", DL_INIT); dlog("Applying fix for Bonus Move exploit.", DL_INIT);
HookCall(0x420E93, &combat_load_hook); HookCall(0x420E93, combat_load_hook);
MakeCall(0x422A06, combat_turn_hack); MakeCall(0x422A06, combat_turn_hack);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
@@ -2067,7 +2133,7 @@ void BugFixes::init()
//if (GetConfigInt("Misc", "SilentDeathFix", 1)) { //if (GetConfigInt("Misc", "SilentDeathFix", 1)) {
dlog("Applying Silent Death patch.", DL_INIT); dlog("Applying Silent Death patch.", DL_INIT);
SafeWrite8(0x4238DF, 0x8C); // jl loc_423A0D SafeWrite8(0x4238DF, 0x8C); // jl loc_423A0D
HookCall(0x423A99, &compute_attack_hook); HookCall(0x423A99, compute_attack_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
@@ -2075,7 +2141,7 @@ void BugFixes::init()
MakeCall(0x495FF6, partyMemberGetCurLevel_hack, 1); MakeCall(0x495FF6, partyMemberGetCurLevel_hack, 1);
// Fix for player's base EMP DR not being properly initialized when creating a new character and then starting the game // Fix for player's base EMP DR not being properly initialized when creating a new character and then starting the game
HookCall(0x4A22DF, &ResetPlayer_hook); HookCall(0x4A22DF, ResetPlayer_hook);
// Fix for add_mult_objs_to_inven only adding 500 of an object when the value of "count" argument is over 99999 // Fix for add_mult_objs_to_inven only adding 500 of an object when the value of "count" argument is over 99999
SafeWrite32(0x45A2A0, 0x1869F); // 99999 SafeWrite32(0x45A2A0, 0x1869F); // 99999
@@ -2200,8 +2266,51 @@ void BugFixes::init()
// number of values (for chem_primary_desire) // number of values (for chem_primary_desire)
MakeJump(0x42C12C, config_get_values_hack); MakeJump(0x42C12C, config_get_values_hack);
// Fix returned result value // Fix returned result value when the file is missing
HookCall(0x4C6162, db_freadInt_hook); // TODO: Resolve conflict in FileSystem.cpp HookCall(0x4C6162, db_freadInt_hook);
// Fix for attack_complex still causing minimum damage to the target when the attacker misses
MakeCall(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_INIT);
SafeWrite8(0x45B910, 0x7E); // jbe > jle
dlogr(" Done", DL_INIT);
// Fix and repurpose the unused called_shot/num_attack arguments of attack_complex function
// also change the behavior of the result flags arguments
// called_shot - additional damage, when the damage received by the target is above the specified minimum
// num_attacks - the number of free action points on the first turn only
// attacker_results - unused, must be 0 or not equal to the target_results argument when specifying result flags for the target
if (GetConfigInt("Misc", "AttackComplexFix", 0)) {
dlog("Applying attack_complex fix.", DL_INIT);
HookCall(0x456D4A, op_attack_hook);
SafeWrite8(0x456D61, 0x74); // mov [esp+x], esi
SafeWrite8(0x456D92, 0x5C); // mov [esp+x], ebx
SafeWrite8(0x456D98, 0x94); // setnz > setz (fix setting result flags)
dlogr(" Done", DL_INIT);
}
// Fix crash when calling use_obj/use_obj_on_obj without using set_self in global scripts
MakeCall(0x45C376, op_use_obj_on_obj_hack, 1);
MakeCall(0x456A92, op_use_obj_hack, 1);
// 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_INIT);
SafeWriteBatch<BYTE>(0x34, { // script.target > script.self
0x456554, // op_pickup_obj_
0x456600, // op_drop_obj_
0x456A6D, // op_use_obj_
0x456AA4 // op_use_obj_
});
dlogr(" Done", DL_INIT);
// 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_
// Fix for the player's turn being skipped when loading a game saved in combat mode
MakeCall(0x422E25, combat_hack_load);
} }
} }
+10 -8
View File
@@ -43,10 +43,12 @@ static const char* critNames[] = {
"FailMessage", "FailMessage",
}; };
static fo::CritInfo baseCritTable[Criticals::critTableCount][9][6]; // Base critical table set up via enabling OverrideCriticalTable in ddraw.ini static fo::CritInfo baseCritTable[Criticals::critTableCount][9][6] = {0}; // Base critical table set up via enabling OverrideCriticalTable in ddraw.ini
static fo::CritInfo critTable[Criticals::critTableCount][9][6]; static fo::CritInfo critTable[Criticals::critTableCount][9][6];
static fo::CritInfo (*playerCrit)[9][6]; static fo::CritInfo (*playerCrit)[9][6];
static bool Inited = false; static bool Inited = false;
static const char* errorTable = "\nError: %s - function requires enabling OverrideCriticalTable in ddraw.ini."; static const char* errorTable = "\nError: %s - function requires enabling OverrideCriticalTable in ddraw.ini.";
void Criticals::SetCriticalTable(DWORD critter, DWORD bodypart, DWORD slot, DWORD element, DWORD value) { void Criticals::SetCriticalTable(DWORD critter, DWORD bodypart, DWORD slot, DWORD element, DWORD value) {
@@ -73,12 +75,11 @@ void Criticals::ResetCriticalTable(DWORD critter, DWORD bodypart, DWORD slot, DW
critTable[critter][bodypart][slot].values[element] = baseCritTable[critter][bodypart][slot].values[element]; critTable[critter][bodypart][slot].values[element] = baseCritTable[critter][bodypart][slot].values[element];
} }
void CritLoad() { static void CritLoad() {
if (!Inited) return; if (!Inited) return;
if (mode == 1) { if (mode == 1) {
dlogr("Setting up critical hit table using CriticalOverrides.ini", DL_CRITICALS); dlogr("Setting up critical hit table using CriticalOverrides.ini", DL_CRITICALS);
char section[16]; char section[16];
memset(baseCritTable, 0, sizeof(critTable));
for (DWORD critter = 0; critter < 20; critter++) { for (DWORD critter = 0; critter < 20; critter++) {
for (DWORD part = 0; part < 9; part++) { for (DWORD part = 0; part < 9; part++) {
for (DWORD crit = 0; crit < 6; crit++) { for (DWORD crit = 0; crit < 6; crit++) {
@@ -102,8 +103,8 @@ void CritLoad() {
} else { } else {
dlogr("Setting up critical hit table using RP fixes", DL_CRITICALS); dlogr("Setting up critical hit table using RP fixes", DL_CRITICALS);
memcpy(baseCritTable, fo::var::crit_succ_eff, sizeof(critTable)); memcpy(baseCritTable, fo::var::crit_succ_eff, sizeof(critTable));
memset(&baseCritTable[19], 0, 6 * 9 * 19 * sizeof(fo::CritInfo)); //memset(&baseCritTable[19], 0, 6 * 9 * 19 * sizeof(fo::CritInfo));
memcpy(&baseCritTable[38], &fo::var::pc_crit_succ_eff, 6 * 9 * sizeof(fo::CritInfo)); // PC crit table memcpy(&baseCritTable[38], fo::var::pc_crit_succ_eff, 6 * 9 * sizeof(fo::CritInfo)); // PC crit table
if (mode == 3) { if (mode == 3) {
char buf[32], buf2[32], buf3[32]; char buf[32], buf2[32], buf3[32];
@@ -134,13 +135,14 @@ void CritLoad() {
} }
#define SetEntry(critter, bodypart, effect, param, value) fo::var::crit_succ_eff[critter][bodypart][effect].values[param] = value; #define SetEntry(critter, bodypart, effect, param, value) fo::var::crit_succ_eff[critter][bodypart][effect].values[param] = value;
void CriticalTableOverride() {
static void CriticalTableOverride() {
dlog("Initializing critical table override.", DL_INIT); dlog("Initializing critical table override.", DL_INIT);
playerCrit = &critTable[38]; playerCrit = &critTable[38];
SafeWrite32(0x423F96, (DWORD)playerCrit); SafeWrite32(0x423F96, (DWORD)playerCrit);
SafeWrite32(0x423FB3, (DWORD)critTable); SafeWrite32(0x423FB3, (DWORD)critTable);
if (mode == 2 || mode == 3) { if (mode == 2 || mode == 3) { // bug fixes
SetEntry(2, 4, 1, 4, 0); SetEntry(2, 4, 1, 4, 0);
SetEntry(2, 4, 1, 5, 5216); SetEntry(2, 4, 1, 5, 5216);
SetEntry(2, 4, 1, 6, 5000); SetEntry(2, 4, 1, 6, 5000);
@@ -242,7 +244,7 @@ void CriticalTableOverride() {
} }
#undef SetEntry #undef SetEntry
void RemoveCriticalTimeLimitsPatch() { static void RemoveCriticalTimeLimitsPatch() {
if (GetConfigInt("Misc", "RemoveCriticalTimelimits", 0)) { if (GetConfigInt("Misc", "RemoveCriticalTimelimits", 0)) {
dlog("Removing critical time limits.", DL_INIT); dlog("Removing critical time limits.", DL_INIT);
SafeWrite8(0x424118, 0xEB); // jmps 0x424131 SafeWrite8(0x424118, 0xEB); // jmps 0x424131
+75 -7
View File
@@ -43,6 +43,11 @@ namespace sfall
#define CODE_GET_ARRAY (9) #define CODE_GET_ARRAY (9)
#define CODE_SET_ARRAY (10) #define CODE_SET_ARRAY (10)
static const char* debugLog = "LOG";
static const char* debugGnw = "GNW";
static DWORD debugEditorKey = 0;
static bool SetBlocking(SOCKET s, bool block) { static bool SetBlocking(SOCKET s, bool block) {
DWORD d = !block; DWORD d = !block;
ioctlsocket(s, FIONBIO, &d); ioctlsocket(s, FIONBIO, &d);
@@ -149,7 +154,7 @@ static void RunEditorInternal(SOCKET &s) {
sglobals[id].val = val; sglobals[id].val = val;
break; break;
case 9: case 9:
{ {
InternalRecv(s, &id, 4); InternalRecv(s, &id, 4);
DWORD *types = new DWORD[arrays[id * 3 + 1]]; DWORD *types = new DWORD[arrays[id * 3 + 1]];
char *data = new char[arrays[id * 3 + 1] * arrays[id * 3 + 2]]; char *data = new char[arrays[id * 3 + 1] * arrays[id * 3 + 2]];
@@ -158,17 +163,17 @@ static void RunEditorInternal(SOCKET &s) {
InternalSend(s, data, arrays[id * 3 + 1] * arrays[id * 3 + 2]); InternalSend(s, data, arrays[id * 3 + 1] * arrays[id * 3 + 2]);
delete[] data; delete[] data;
delete[] types; delete[] types;
} }
break; break;
case 10: case 10:
{ {
InternalRecv(s, &id, 4); InternalRecv(s, &id, 4);
char *data = new char[arrays[id * 3 + 1] * arrays[id * 3 + 2]]; char *data = new char[arrays[id * 3 + 1] * arrays[id * 3 + 2]];
InternalRecv(s, data, arrays[id * 3 + 1] * arrays[id * 3 + 2]); InternalRecv(s, data, arrays[id * 3 + 1] * arrays[id * 3 + 2]);
script::DESetArray(arrays[id * 3], 0, data); script::DESetArray(arrays[id * 3], 0, data);
delete[] data; delete[] data;
} }
break; break;
} }
} }
@@ -238,10 +243,69 @@ void RunDebugEditor() {
WSACleanup(); WSACleanup();
} }
static DWORD debugEditorKey = 0; static void __declspec(naked) dbg_error_hack() {
__asm {
cmp ebx, 1;
je hide;
sub esp, 0x104;
retn;
hide:
add esp, 4; // destroy this return addr
pop esi;
pop ecx;
retn;
}
}
static void __declspec(naked) win_debug_hook() {
__asm {
call fo::funcoffs::debug_log_;
xor eax, eax;
cmp ds:[FO_VAR_GNW_win_init_flag], eax;
retn;
}
}
void DebugModePatch() {
DWORD dbgMode = GetPrivateProfileIntA("Debugging", "DebugMode", 0, ::sfall::ddrawIni);
if (dbgMode) {
dlog("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_
SafeWrite32(0x444A68, 0x0120E900); // jmp 0x444B8E
SafeWrite8(0x444A6D, 0);
SafeWrite32(0x444A6E, 0x90909090);
}
SafeWrite8(0x4C6D9B, 0xB8); // mov eax, GNW/LOG
if (dbgMode & 2) {
SafeWrite32(0x4C6D9C, (DWORD)debugLog);
if (dbgMode & 1) {
SafeWrite16(0x4C6E75, 0x66EB); // jmps 0x4C6EDD
SafeWrite8(0x4C6EF2, 0xEB);
SafeWrite8(0x4C7034, 0x0);
MakeCall(0x4DC319, win_debug_hook, 2);
}
} else {
SafeWrite32(0x4C6D9C, (DWORD)debugGnw);
}
dlogr(" Done", DL_INIT);
}
}
void DontDeleteProtosPatch() {
if (GetPrivateProfileIntA("Debugging", "DontDeleteProtos", 0, ::sfall::ddrawIni)) {
dlog("Applying permanent protos patch.", DL_INIT);
SafeWrite8(0x48007E, 0xEB);
dlogr(" Done", DL_INIT);
}
}
void DebugEditor::init() { void DebugEditor::init() {
if (!isDebug) return; if (!isDebug) return;
DebugModePatch();
DontDeleteProtosPatch();
debugEditorKey = GetConfigInt("Input", "DebugEditorKey", 0); debugEditorKey = GetConfigInt("Input", "DebugEditorKey", 0);
if (debugEditorKey != 0) { if (debugEditorKey != 0) {
OnKeyPressed() += [](DWORD scanCode, bool pressed) { OnKeyPressed() += [](DWORD scanCode, bool pressed) {
@@ -250,6 +314,10 @@ void DebugEditor::init() {
} }
}; };
} }
if (GetPrivateProfileIntA("Debugging", "HideObjIsNullMsg", 0, ::sfall::ddrawIni)) {
MakeCall(0x453FD2, dbg_error_hack, 1);
}
} }
} }
+19 -18
View File
@@ -28,12 +28,12 @@ static const int exitsPerElevator = 4;
static const int vanillaElevatorCount = 24; static const int vanillaElevatorCount = 24;
static const int elevatorCount = 50; static const int elevatorCount = 50;
static char elevFile[MAX_PATH] = ".\\"; //static char elevFile[MAX_PATH] = ".\\";
static DWORD elevatorType[elevatorCount]; static DWORD elevatorType[elevatorCount] = {0};
static fo::ElevatorExit elevatorExits[elevatorCount][exitsPerElevator]; // _retvals static fo::ElevatorExit elevatorExits[elevatorCount][exitsPerElevator] = {0}; // _retvals
static fo::ElevatorFrms elevatorsFrms[elevatorCount]; // _intotal static fo::ElevatorFrms elevatorsFrms[elevatorCount] = {0}; // _intotal
static DWORD elevatorsBtnCount[elevatorCount]; // _btncount static DWORD elevatorsBtnCount[elevatorCount] = {0}; // _btncount
static void __declspec(naked) GetMenuHook() { static void __declspec(naked) GetMenuHook() {
__asm { __asm {
@@ -100,16 +100,19 @@ static void __declspec(naked) GetNumButtonsHook3() {
} }
void ResetElevators() { void ResetElevators() {
//memset(&elevatorExits[vanillaElevatorCount], 0, sizeof(fo::ElevatorExit) * (elevatorCount - vanillaElevatorCount) * exitsPerElevator);
//memset(&elevatorsFrms[vanillaElevatorCount], 0, sizeof(fo::ElevatorFrms) * (elevatorCount - vanillaElevatorCount));
//for (int i = vanillaElevatorCount; i < elevatorCount; i++) elevatorType[i] = 0;
}
static void LoadElevators(const char* elevFile) {
//ResetElevators();
memcpy(elevatorExits, fo::var::retvals, sizeof(fo::ElevatorExit) * vanillaElevatorCount * exitsPerElevator); memcpy(elevatorExits, fo::var::retvals, sizeof(fo::ElevatorExit) * vanillaElevatorCount * exitsPerElevator);
memset(&elevatorExits[vanillaElevatorCount], 0, sizeof(fo::ElevatorExit) * (elevatorCount - vanillaElevatorCount) * exitsPerElevator);
memcpy(elevatorsFrms, (void*)FO_VAR_intotal, sizeof(fo::ElevatorFrms) * vanillaElevatorCount); memcpy(elevatorsFrms, (void*)FO_VAR_intotal, sizeof(fo::ElevatorFrms) * vanillaElevatorCount);
memset(&elevatorsFrms[vanillaElevatorCount], 0, sizeof(fo::ElevatorFrms) * (elevatorCount - vanillaElevatorCount));
memcpy(elevatorsBtnCount, (void*)FO_VAR_btncnt, sizeof(DWORD) * vanillaElevatorCount); memcpy(elevatorsBtnCount, (void*)FO_VAR_btncnt, sizeof(DWORD) * vanillaElevatorCount);
for (int i = 0; i < vanillaElevatorCount; i++) elevatorType[i] = i; for (int i = 0; i < vanillaElevatorCount; i++) elevatorType[i] = i;
for (int i = vanillaElevatorCount; i < elevatorCount; i++) elevatorType[i] = 0;
char section[4]; char section[4];
if (elevFile) { if (elevFile) {
@@ -137,9 +140,7 @@ void ResetElevators() {
} }
} }
void ElevatorsInit(const char* file) { void ElevatorsInit() {
strcat_s(elevFile, file);
HookCall(0x43EF83, GetMenuHook); HookCall(0x43EF83, GetMenuHook);
HookCall(0x43F141, CheckHotKeysHook); HookCall(0x43F141, CheckHotKeysHook);
//HookCall(0x43F2D2, UnknownHook2); // unused //HookCall(0x43F2D2, UnknownHook2); // unused
@@ -161,15 +162,15 @@ void ElevatorsInit(const char* file) {
MakeCall(0x43F05D, GetNumButtonsHook1, 2); MakeCall(0x43F05D, GetNumButtonsHook1, 2);
MakeCall(0x43F184, GetNumButtonsHook2, 2); MakeCall(0x43F184, GetNumButtonsHook2, 2);
MakeCall(0x43F1E4, GetNumButtonsHook3, 2); MakeCall(0x43F1E4, GetNumButtonsHook3, 2);
ResetElevators();
} }
void Elevators::init() { void Elevators::init() {
auto elevPath = GetConfigString("Misc", "ElevatorsFile", "", MAX_PATH); auto elevPath = GetConfigString("Misc", "ElevatorsFile", "", MAX_PATH);
if (elevPath.size() > 0) { if (!elevPath.empty()) {
dlogr("Applying elevator patch.", DL_INIT); dlog("Applying elevator patch.", DL_INIT);
ElevatorsInit(elevPath.c_str()); ElevatorsInit();
LoadElevators(elevPath.insert(0, ".\\").c_str());
dlogr(" Done", DL_INIT);
} }
} }

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