mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Merge branch 'develop'
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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 -------
|
||||||
------------------------
|
------------------------
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
Reference in New Issue
Block a user