Compare commits

...
30 Commits
Author SHA1 Message Date
NovaRain 8b9ffd08a8 Minor edits to ddraw.ini 2019-07-18 09:27:28 +08:00
NovaRain b26208141f Changed DebugMode to not require enabling sfall debugging mode
Changed version to 3.8.19.1 as maintenance release.
2019-07-17 10:10:28 +08:00
NovaRain 147382de25 Minor code edits to LoadGameHook, PartyControl, ScriptExtender.cpp 2019-07-16 13:01:44 +08:00
NovaRain 9529208c7c Fixed the error handling on loading sfallgv.sav
* to improve backward compatibility with older saved games.
2019-07-15 20:51:29 +08:00
NovaRain fc3b7180af Backported the code of COMBATDAMAGE hook from 4.x
Moved instadeath crit fix from COMBATDAMAGE hook to BugFixes.cpp.
Completed the compute_attack struct.
Updated version number.
2019-07-15 09:59:58 +08:00
NovaRain f53aa16923 Excluded Awareness from perks resetting in PartyControl.cpp 2019-07-14 10:46:56 +08:00
NovaRain ce19262283 Excluded barter mode for ItemCounterDefaultMax
Renamed GetCurrentLoops function to "GetLoopFlags".
Minor edits to document/code.
2019-07-10 11:05:28 +08:00
NovaRain e43762b45f Added assignment of unique IDs to items/critters for event queue
* to prevent event queue being added to the incorrect object on the map.
2019-07-09 21:50:46 +08:00
NovaRain ceb9c41e3d Changed the implementation of the bug fix in commit f1ef55d
Added additional fix for "NPC turns into a container" bug.
2019-07-09 10:50:00 +08:00
NovaRain 0aee36f77d Fixed bugs related to knockout/knockdown critters
Fixed knocked down critters not playing stand up animation when the
combat ends.

Fixed dead NPCs reloading their weapons when the combat ends.
2019-07-06 22:34:20 +08:00
NovaRain 9c41ddd243 Fixed the execution of functions before exiting map in commit f13e6bd 2019-07-06 01:57:09 +08:00
NovaRain f38d87e0ee Added KnockoutTime option to change the duration of the knockout effect.
Fixed op_lookup_string_proc_ engine function not searching the last
procedure in a script.
2019-07-04 12:11:00 +08:00
NovaRain 5fa418ae08 Added reassignment of IDs for critters upon first loading a map
* for fixing mapper not checking existing object IDs and generating
duplicated ones for new critters added on a map.
2019-07-03 15:13:46 +08:00
NovaRain c6c66a4b58 Added a check for the DAM_KNOCKED_OUT flag
to wield_obj_critter/inven_unwield script functions.

Added climbing ladders to "interrupted player's movement in combat" fix.
2019-07-03 12:14:23 +08:00
NovaRain feeae8c750 Added debug log entries to PartyControl.cpp as 4.x 2019-07-01 13:12:10 +08:00
NovaRain 58a67d58cb Added SkipOpeningMovies=2 to also skip the splash screen
Changed the order of some code in main.cpp.
Renamed IsDebug variable to "isDebug".
2019-06-29 20:11:53 +08:00
NovaRain 96881c19a3 Fixed combat not ending automatically when there are no hostiles. 2019-06-26 06:15:35 +08:00
NovaRain c18828b61b Changed DataLoadOrderPatch to be 1 by default.
Replaced most of NULL with nullptr, since VS2010 supports it.
Some code edits to MiscOps.hpp and ScriptUtils.hpp.
2019-06-24 12:25:32 +08:00
NovaRain b1e78bb61c Rewrote get/set_pc/critter_*_stat funcs in C++.
* this slightly improved their error handling.

Concentrated the error msg for invalid args of opcodes.
2019-06-23 11:23:42 +08:00
NovaRain bcb0228ed3 Fixed fade in/out of the screen in DX9 mode. 2019-06-18 09:27:39 +08:00
NovaRain a75e634c96 Fixed Scout perk being taken into account for mark_area_known function.
* technically it should only effect the visibility of tiles when you're
exploring on the world map.

Fixed the incorrect coordinates for small/medium location circles when
highlighting their sub-tiles (one of bugs listed in #228)

Moved the fix for the position of the target marker from Worldmap.cpp to
BugFixes.cpp.

Slightly adjusted the position/size for Local variables button in debug
editor.
2019-06-17 11:24:57 +08:00
NovaRain c4f6c762c4 Added viewing and modifying local vars for critters to the debug editor. 2019-06-15 10:09:50 +08:00
NovaRain 5ccd1534f4 Added "metarule_exist" script function.
Limited the maximum number of extra game msg files to 4096 (from 4.x).
Code edit to Message.cpp and ScriptUtils.hpp.
2019-06-14 23:32:01 +08:00
NovaRain 8e0190939e Minor edit to error messages in MiscOps.hpp. 2019-06-12 09:14:12 +08:00
NovaRain 0f7a8592a9 Fixed the interrupted player's movement in combat.
* it happens when the player try to use objects with Bonus Move APs
available. The distance has to be greater than remaining normal APs.

Replaced calling db_dir_entry_ with db_access_ in HeroAppearance.cpp.
2019-06-10 09:45:52 +08:00
NovaRain e9f3fd5039 Fixed the position of the target maker for location circles. 2019-06-09 11:35:30 +08:00
NovaRain 6cc988aef5 Fixed the reserve movement fix in commit f1ef55d.
* before the reserve movement didn't work correctly if the player has
free move AP (yellow, from Bonus Move) left.
2019-06-09 07:26:32 +08:00
NovaRain e50369c18d Fixed the up/down button images in the world map interface. 2019-06-08 23:56:20 +08:00
NovaRain f1ef55d22d Fixed anim_move_to_tile_ ignoring the distance argument.
* this also fixes the broken "reserve movement" feature.
2019-06-08 09:46:30 +08:00
NovaRain d1fe920cf7 Fixed a few bugs in WorldMapSlots option.
Updated version number.
2019-06-06 10:21:36 +08:00
47 changed files with 1275 additions and 892 deletions
+3 -2
View File
@@ -158,12 +158,13 @@
//
this.bCrittersLvar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.bCrittersLvar.Enabled = false;
this.bCrittersLvar.Location = new System.Drawing.Point(119, 401);
this.bCrittersLvar.Location = new System.Drawing.Point(118, 401);
this.bCrittersLvar.Name = "bCrittersLvar";
this.bCrittersLvar.Size = new System.Drawing.Size(99, 23);
this.bCrittersLvar.Size = new System.Drawing.Size(100, 23);
this.bCrittersLvar.TabIndex = 7;
this.bCrittersLvar.Text = "Local variables";
this.bCrittersLvar.UseVisualStyleBackColor = true;
this.bCrittersLvar.Click += new System.EventHandler(this.bCrittersLvar_Click);
//
// DebugEditor
//
+42 -1
View File
@@ -38,7 +38,7 @@ namespace FalloutClient {
private static ByteConverter converter = new ByteConverter();
private enum Mode { Globals, MapVars, SGlobals, Arrays, Critters }
private enum Mode { Globals, MapVars, SGlobals, Arrays, Critters, LocalVars }
private readonly EditorConnection connection;
private Mode mode;
@@ -47,6 +47,7 @@ namespace FalloutClient {
private readonly Dictionary<uint, string> CritNames = new Dictionary<uint, string>();
private void Redraw() {
bCrittersLvar.Enabled = false;
bEdit.Enabled = false;
Column2.ReadOnly = false;
Column3.ReadOnly = false;
@@ -96,6 +97,7 @@ namespace FalloutClient {
Column2.HeaderText = "PID";
Column3.HeaderText = "Pointer";
bEdit.Enabled = true;
bCrittersLvar.Enabled = true;
for (int i = 0; i < connection.Critters.Length / 2; i++) {
uint modcrit = (connection.Critters[i, 0] & 0xfffff);
string name = CritNames.ContainsKey(modcrit) ? CritNames[modcrit] : "";
@@ -333,6 +335,45 @@ namespace FalloutClient {
}
}
private void bCrittersLvar_Click(object sender, EventArgs e) {
if (dataGridView1.SelectedRows.Count == 0) return;
int i = (int)dataGridView1.SelectedRows[0].Tag;
connection.WriteDataType(DataTypeSend.RetrieveCritter);
connection.WriteInt(i);
BinaryReader br = new BinaryReader(new System.IO.MemoryStream(connection.ReadBytes(33 * 4)));
br.BaseStream.Position = 30 * 4;
int sid = br.ReadInt32();
br.Close();
if (sid != -1) {
connection.WriteDataType(DataTypeSend.GetLocal);
connection.WriteInt(sid);
int totalVar = connection.ReadInt();
string[] values = new string[totalVar];
if (totalVar > 0) {
br = new BinaryReader(new System.IO.MemoryStream(connection.ReadBytes(totalVar * 4)));
for (int j = 0; j < totalVar; j++) {
values[j] = br.ReadInt32().ToString();
}
br.Close();
}
values = EditorWindow.ShowEditor(this, values);
if (values != null) {
int countVar = values.Length;
MemoryStream ms = new MemoryStream(countVar * 4);
BinaryWriter bw = new BinaryWriter(ms);
for (int j = 0; j < countVar; j++) bw.Write(int.Parse(values[j]));
connection.WriteDataType(DataTypeSend.SetLocal);
connection.WriteInt(sid);
connection.WriteInt(countVar);
connection.WriteBytes(ms.GetBuffer(), 0, countVar * 4);
bw.Close();
}
} else {
MessageBox.Show("This critter has no script attached.");
}
}
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e) {
bEdit.PerformClick();
}
+16
View File
@@ -29,6 +29,7 @@
this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column3 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.checkBox = new System.Windows.Forms.CheckBox();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
@@ -100,11 +101,24 @@
this.Column3.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
this.Column3.Width = 150;
//
// checkBox
//
this.checkBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.checkBox.AutoSize = true;
this.checkBox.Location = new System.Drawing.Point(103, 341);
this.checkBox.Name = "checkBox";
this.checkBox.Size = new System.Drawing.Size(91, 17);
this.checkBox.TabIndex = 3;
this.checkBox.Text = "Values in Hex";
this.checkBox.UseVisualStyleBackColor = true;
this.checkBox.Click += new System.EventHandler(this.checkBox_Click);
//
// EditorWindow
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(458, 371);
this.Controls.Add(this.checkBox);
this.Controls.Add(this.dataGridView1);
this.Controls.Add(this.bCancel);
this.Controls.Add(this.bSave);
@@ -115,6 +129,7 @@
this.Text = "Edit Values";
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
@@ -126,5 +141,6 @@
private System.Windows.Forms.DataGridViewTextBoxColumn Column1;
private System.Windows.Forms.DataGridViewTextBoxColumn Column2;
private System.Windows.Forms.DataGridViewTextBoxColumn Column3;
private System.Windows.Forms.CheckBox checkBox;
}
}
+64 -6
View File
@@ -8,15 +8,34 @@ namespace FalloutClient {
public partial class EditorWindow : Form
{
private readonly DataType[] types;
private readonly string[] values;
private readonly DataType[] types = null;
private string[] values;
private bool save;
private static bool valueInHex = false;
private void ConvertValues(bool toHex) {
for (int i = 0; i < values.Length; i++) {
if (toHex) {
if (types == null || types[i] == DataType.Int) {
int val = int.Parse(values[i]);
values[i] = "0x" + val.ToString("x").ToUpper();
}
} else {
if (types == null || types[i] == DataType.Int) {
values[i] = Convert.ToInt32(values[i], 16).ToString();
}
}
}
}
private EditorWindow(string[] names, DataType[] types, string[] values, bool isMap) {
this.types = types;
this.values = values;
InitializeComponent();
checkBox.Checked = EditorWindow.valueInHex;
dataGridView1.SuspendLayout();
if (valueInHex) ConvertValues(true);
if (names == null)
for (int i = 0; i < types.Length; i++) {
string element = i.ToString();
@@ -31,15 +50,46 @@ namespace FalloutClient {
public static string[] ShowEditor(DebugEditor form, string[] names, DataType[] types, string[] values, bool isMap = false) {
EditorWindow editor = new EditorWindow(names, types, values, isMap);
editor.ShowDialog();
if (editor.save)
if (editor.save) {
if (valueInHex) editor.ConvertValues(false);
return editor.values;
else
return null;
}
return null;
}
private EditorWindow(string[] values) {
this.values = values;
InitializeComponent();
checkBox.Checked = EditorWindow.valueInHex;
dataGridView1.SuspendLayout();
if (valueInHex) ConvertValues(true);
for (int i = 0; i < values.Length; i++) {
dataGridView1.Rows.Add(i.ToString(), "Int", values[i]);
}
dataGridView1.ResumeLayout();
}
public static string[] ShowEditor(DebugEditor form, string[] lvalues) {
EditorWindow editor = new EditorWindow(lvalues);
editor.ShowDialog();
if (editor.save) {
if (valueInHex) editor.ConvertValues(false);
return editor.values;
}
return null;
}
private bool CheckInput(DataType type, string str) {
switch (type) {
case DataType.Int:
if (valueInHex) {
try {
Convert.ToInt32(str, 16);
return true;
} catch (Exception) {
return false;
}
}
int i;
return int.TryParse(str, out i);
case DataType.Float:
@@ -51,7 +101,7 @@ namespace FalloutClient {
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
string str = (string)dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
if (str != null && CheckInput(types[e.RowIndex], str))
if (str != null && CheckInput(((types != null) ? types[e.RowIndex] : DataType.Int), str))
values[e.RowIndex] = str;
else
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = values[e.RowIndex];
@@ -65,5 +115,13 @@ namespace FalloutClient {
save = true;
Close();
}
private void checkBox_Click(object sender, EventArgs e) {
valueInHex = checkBox.Checked;
ConvertValues(valueInHex);
for (int i = 0; i < values.Length; i++) {
dataGridView1.Rows[i].Cells[2].Value = values[i];
}
}
}
}
+2
View File
@@ -29,6 +29,8 @@ namespace FalloutClient {
SetSGlobal = 4,
GetArray = 9,
SetArray = 10,
GetLocal = 11,
SetLocal = 12,
Exit = 254
}
}
+2 -2
View File
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("4.1.7.0")]
[assembly: AssemblyFileVersion("4.1.7.0")]
[assembly: AssemblyVersion("4.1.9.0")]
[assembly: AssemblyFileVersion("4.1.9.0")]
+15 -8
View File
@@ -1,5 +1,5 @@
;sfall configuration settings
;v3.8.18
;v3.8.19.1
[Main]
;Change to 1 if you want to use command line args to tell sfall to use another ini file.
@@ -15,7 +15,7 @@ UseCommandLine=0
NumSoundBuffers=0
;Set to 1 to allow attaching sound files to combat float messages
AllowSoundForFloats=1
AllowSoundForFloats=0
;Set to 1 to automatically search for alternative formats (mp3/wma/wav) when Fallout tries to play an acm
;Set to 2 to play alternative music files even if original acm files are not present in the music folder
@@ -173,7 +173,7 @@ FastMoveFromContainer=0
;A key to press to open a debug game editor
;Set to 0 to disable, or a DX scancode otherwise
;Requires sfall debugging mode and FalloutClient.exe from the modders pack
;Requires sfall debugging mode to be enabled and FalloutClient.exe from the modders pack
DebugEditorKey=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -225,7 +225,7 @@ UseFileSystemOverride=0
;Set to 1 to use the modified data load order for the engine to find game data
;Original: patchXXX.dat > critter_patches > critter_dat > f2_res_patches > f2_res_dat > master_patches > master_dat
;Modified: master_patches > critter_patches > patchXXX.dat > critter_dat > f2_res_patches > f2_res_dat > master_dat
DataLoadOrderPatch=0
DataLoadOrderPatch=1
;To change the default and starting player models, uncomment the next four lines.
;The default models can also be changed ingame via script
@@ -376,6 +376,7 @@ ProcessorIdle=-1
EnableHeroAppearanceMod=0
;Set to 1 to skip the 3 opening movies
;Set to 2 to also skip the splash screen
SkipOpeningMovies=0
;Causes NPCs who complete their combat turn with AP left over will try and find other ways to spend it.
@@ -390,7 +391,7 @@ AIBestWeaponFix=0
;Set to 1 to fix NPCs not taking chem_primary_desire in AI.txt as drug use preference when using drugs in their inventory
AIDrugUsePerfFix=0
;Allows the use of tiles over 80*36 in size. sfall will just split and resave them at startup
;Allows the use of tiles over 80x36 in size. sfall will just split and resave them at startup
;Set to 1 to check all tiles on started (slow)
;Set to 2 if you provide a XLtiles.lst file in art\tiles\ containing a list of the tile ids that need checking
AllowLargeTiles=0
@@ -611,7 +612,7 @@ StackEmptyWeapons=0
;If the amount of ammo boxes in the inventory is less than or equal to the reserve, only one box will be used
ReloadReserve=-1
;Set to 1 to change the counter in the 'Move Items' window to start at the maximum number of items
;Set to 1 to change the counter in the 'Move Items' window to start with maximum number except in the barter screen
ItemCounterDefaultMax=0
;Set to 1 to leave the music playing in dialogue with talking heads
@@ -664,6 +665,10 @@ SpecialDeathGVAR=491
;Note that enabling this option can break the map changes in Modoc and Vault 15
DisableSpecialMapIDs=0
;Changes the base value of the duration of the knockout effect (valid range: 35..100)
;The formula for the duration in ticks is: 10 * (value - 3 * EN)
KnockoutTime=35
;Set to 1 to display sfall built-in credits at the bottom of credits.txt contents instead of at the top
CreditsAtBottom=0
@@ -677,6 +682,7 @@ Enable=0
;Fallout 2 Debug Patch
;Set to 1 to send debug output to the screen, 2 to a debug.log file, or 3 to both the screen and a debug.log file
;Does not require enabling sfall debugging mode
;While you don't need to create an environment variable, you do still need to set the appropriate lines in fallout2.cfg:
;-------
;[debug]
@@ -695,12 +701,12 @@ DebugMode=0
SkipCompatModeCheck=0
;Set to 1 to skip the executable file size check
;Does not require sfall debugging mode
;Does not require enabling sfall debugging mode
SkipSizeCheck=0
;If you're testing changes to the Fallout exe, you can override the CRC that sfall looks for here
;You can use several hex values, separated by commas
;Does not require sfall debugging mode
;Does not require enabling sfall debugging mode
;ExtraCRC=0x00000000,0x00000000
;Set to 1 to stop Fallout from deleting non read-only protos at startup
@@ -711,6 +717,7 @@ DontDeleteProtos=0
AllowUnsafeScripting=0
;Set to 1 to hide error messages in debug output when a null value is passed to the function as an object
;Requires DebugMode to be enabled
HideObjIsNullMsg=0
;Set to 1 to force critters to display combat float messages
+2
View File
@@ -232,6 +232,7 @@
#define get_cursor_mode sfall_func0("get_cursor_mode")
#define get_flags(obj) sfall_func1("get_flags", obj)
#define get_map_enter_position sfall_func0("get_map_enter_position")
#define get_metarule_table sfall_func0("get_metarule_table")
#define get_object_data(obj, offset) sfall_func2("get_object_data", obj, offset)
#define get_outline(obj) sfall_func1("get_outline", obj)
#define intface_hide sfall_func0("intface_hide")
@@ -242,6 +243,7 @@
#define item_weight(obj) sfall_func1("item_weight", obj)
#define lock_is_jammed(obj) sfall_func1("lock_is_jammed", obj)
#define loot_obj sfall_func0("loot_obj")
#define metarule_exist(metarule) sfall_func1("metarule_exist", metarule)
#define npc_engine_level_up(toggle) sfall_func1("npc_engine_level_up", toggle)
#define obj_under_cursor(crSwitch, inclDude) sfall_func2("obj_under_cursor", crSwitch, inclDude)
#define outlined_object sfall_func0("outlined_object")
+5 -2
View File
@@ -305,7 +305,7 @@ Some utility/math functions are available:
> string message_str_game(int fileId, int messageId)
- works exactly the same as message_str, except you get messages from files in "text\<language>\game\" directory
- use GAME_MSG_* defines or mstr_* macros from sfall.h to use specific msg file
- Additional game msg files added by ExtraGameMsgFileList setting will have consecutive fileIds assigned beginning from 0x2000. (e.g. if you set ExtraGameMsgFileList=foo,bar in ddraw.ini, foo.msg will be associated with 0x2000 and bar.msg with 0x2001.)
- Additional game msg files added by ExtraGameMsgFileList setting will have consecutive fileIds assigned beginning from 0x2000 to 0x2FFF. (e.g. if you set ExtraGameMsgFileList=foo,bar in ddraw.ini, foo.msg will be associated with 0x2000 and bar.msg with 0x2001.)
> int sneak_success
- returns 1 if the player is currently sneaking, and last sneak attempt (roll against skill) was successful; 0 otherwise
@@ -359,8 +359,11 @@ Some utility/math functions are available:
> array sfall_func0("get_metarule_table")
- returns names of all currently available scripting functions (via sfall_funcX)
> bool sfall_func1("metarule_exist", string metaruleName)
- returns True if the specified name of metarule (sfall_funcX) function exists in the current version of sfall
> int sfall_func1("spatial_radius", object object)
- return radius of spatial script, associated with given dummy-object (returned by create_spatial)
- returns radius of spatial script, associated with given dummy-object (returned by create_spatial)
> object sfall_func2("critter_inven_obj2", object invenObj, int type)
- works just like vanilla critter_inven_obj, but correctly reports item in player's inactive hand slot
+18 -15
View File
@@ -176,12 +176,13 @@ bool LoadArrayElement(sArrayElement* el, HANDLE h)
return (el->len) ? (unused != el->len) : (unused != 4);
}
static bool LoadArraysOld(HANDLE h) {
dlogr("Loading arrays (old fmt)", DL_MAIN);
static long LoadArraysOld(HANDLE h) {
DWORD count, unused, id;
ReadFile(h, &count, 4, &unused, 0); // count of saved arrays
if (unused != 4) return true;
if (unused != 4) return -1;
if (!count) return 0;
dlogr("Loading arrays (old fmt)", DL_MAIN);
sArrayVarOld var;
sArrayVar varN;
@@ -189,7 +190,7 @@ static bool LoadArraysOld(HANDLE h) {
for (DWORD i = 0; i < count; i++) {
ReadFile(h, &id, 4, &unused, 0);
ReadFile(h, &var, 8, &unused, 0);
if (unused != 8) return true;
if (unused != 8) return -1;
var.types = new DWORD[var.len];
var.data = new char[var.len * var.datalen];
@@ -219,23 +220,25 @@ static bool LoadArraysOld(HANDLE h) {
arrays.insert(array_pair(id, varN));
savedArrays[varN.key] = id;
}
return false;
return 1;
}
bool LoadArrays(HANDLE h) {
long LoadArrays(HANDLE h) {
nextArrayID = 1;
if (LoadArraysOld(h)) return true;
dlogr("Loading arrays (new fmt)", DL_MAIN);
long result = LoadArraysOld(h);
if (result) return result;
DWORD count, unused, elCount;
ReadFile(h, &count, 4, &unused, 0); // count of saved arrays
if (unused != 4) return true;
if (unused != 4 && !result) return 1;
dlogr("Loading arrays (new fmt)", DL_MAIN);
if (unused != 4) return -1;
sArrayVar arrayVar;
for (DWORD i = 0; i < count; i++) {
if (LoadArrayElement(&arrayVar.key, h)) return true;
if (LoadArrayElement(&arrayVar.key, h)) return -1;
if (arrayVar.key.intVal == 0 || static_cast<long>(arrayVar.key.type) >= 4) { // partial compatibility with 3.4
arrayVar.key.intVal = static_cast<long>(arrayVar.key.type);
arrayVar.key.type = DATATYPE_INT;
@@ -243,12 +246,12 @@ bool LoadArrays(HANDLE h) {
ReadFile(h, &arrayVar.flags, 4, &unused, 0);
ReadFile(h, &elCount, 4, &unused, 0); // actual number of elements: keys+values
if (unused != 4) return true;
if (unused != 4) return -1;
bool isAssoc = arrayVar.isAssoc();
arrayVar.val.resize(elCount);
for (size_t j = 0; j < elCount; j++) { // normal and associative arrays stored and loaded equally
if (LoadArrayElement(&arrayVar.val[j], h)) return true;
if (LoadArrayElement(&arrayVar.val[j], h)) return -1;
if (isAssoc && (j % 2) == 0) { // only difference is that keyHash is filled with appropriate indexes
arrayVar.keyHash[arrayVar.val[j]] = j;
}
@@ -260,7 +263,7 @@ bool LoadArrays(HANDLE h) {
savedArrays[arrayVar.key] = nextArrayID++;
arrayVar.keyHash.clear();
}
return false;
return 0;
}
void SaveArrays(HANDLE h) {
+1 -1
View File
@@ -142,7 +142,7 @@ extern DWORD arraysBehavior;
// saved arrays: arrayKey => arrayId
extern ArrayKeysMap savedArrays;
bool LoadArrays(HANDLE h);
long LoadArrays(HANDLE h);
void SaveArrays(HANDLE h);
int GetNumArrays();
void GetArrays(int* arrays);
+270 -58
View File
@@ -47,7 +47,7 @@ void DrugsSaveFix(HANDLE file) {
bool DrugsLoadFix(HANDLE file) {
DWORD count, sizeRead;
ReadFile(file, &count, 4, &sizeRead, 0);
//if (sizeRead != 4) return true;
if (sizeRead != 4) return false;
for (DWORD i = 0; i < count; i++) {
DWORD pid;
ReadFile(file, &pid, 4, &sizeRead, 0);
@@ -862,8 +862,7 @@ static void __declspec(naked) action_melee_hack() {
mov edx, 0x4113DC
mov ebx, [eax + 0x20] // objStruct->FID
and ebx, 0x0F000000
sar ebx, 0x18
cmp ebx, OBJ_TYPE_CRITTER // check if object FID type flag is set to critter
cmp ebx, OBJ_TYPE_CRITTER << 24 // check if object FID type flag is set to critter
jne end // if object not a critter leave jump condition flags
// set to skip dodge animation
test byte ptr [eax + 0x44], DAM_KNOCKED_OUT or DAM_KNOCKED_DOWN // (original code)
@@ -879,8 +878,7 @@ static void __declspec(naked) action_ranged_hack() {
mov edx, 0x411B6D
mov ebx, [eax + 0x20] // objStruct->FID
and ebx, 0x0F000000
sar ebx, 0x18
cmp ebx, OBJ_TYPE_CRITTER // check if object FID type flag is set to critter
cmp ebx, OBJ_TYPE_CRITTER << 24 // check if object FID type flag is set to critter
jne end // if object not a critter leave jump condition flags
// set to skip dodge animation
test byte ptr [eax + 0x44], DAM_KNOCKED_OUT or DAM_KNOCKED_DOWN // (original code)
@@ -891,75 +889,98 @@ end:
}
}
static const DWORD SetNewResults_Ret = 0x424FC6;
static void __declspec(naked) set_new_results_hack() {
__asm {
test ah, DAM_KNOCKED_OUT // DAM_KNOCKED_OUT?
jz end // No
mov eax, esi
xor edx, edx
inc edx // type = knockout
jmp queue_remove_this_ // Remove knockout from queue (if there is one)
end:
add esp, 4 // Destroy the return address
jmp SetNewResults_Ret
call stat_level_;
push eax;
mov eax, esi;
xor edx, edx;
inc edx; // type = knockout
call queue_remove_this_; // Remove knockout from queue (if there is one)
pop eax;
retn;
}
}
static void __declspec(naked) critter_wake_clear_hack() {
__asm {
jne end // This is not a critter
mov dl, [esi + 0x44]
test dl, DAM_DEAD // DAM_DEAD?
jnz end // This is a corpse
and dl, ~DAM_KNOCKED_OUT // 0xFE Unset DAM_KNOCKED_OUT
or dl, DAM_KNOCKED_DOWN // Set DAM_KNOCKED_DOWN
mov [esi + 0x44], dl
jne end; // This is not a critter
mov dl, [esi + 0x44];
test dl, DAM_DEAD; // DAM_DEAD?
jnz end; // This is a corpse
and dl, ~DAM_KNOCKED_OUT; // Unset DAM_KNOCKED_OUT
or dl, DAM_KNOCKED_DOWN; // Set DAM_KNOCKED_DOWN
mov [esi + 0x44], dl;
end:
xor eax, eax
inc eax
pop esi
pop ecx
pop ebx
retn
xor eax, eax;
inc eax;
pop esi;
pop ecx;
pop ebx;
retn; // exit from func
}
}
static const DWORD obj_load_func_Ret = 0x488F14;
static void __declspec(naked) obj_load_func_hack() {
__asm {
test byte ptr [eax+0x25], 0x4 // Temp_
jnz end
mov edi, [eax + 0x64]
shr edi, 0x18
cmp edi, OBJ_TYPE_CRITTER
jne skip
test byte ptr [eax + 0x44], DAM_KNOCKED_DOWN
jz clear // No
pushadc
push ebx
xor ecx, ecx
mov edx, eax // object
mov ebx, ecx // extramem null
mov eax, ecx // time = 0
inc ecx // type = 1
call queue_add_
pop ebx
popadc
test byte ptr [eax + 0x25], 0x4; // Temp_
jz fix;
retn;
fix:
mov edi, [eax + 0x64];
and edi, 0x0F000000;
cmp edi, OBJ_TYPE_CRITTER << 24;
jne skip;
test byte ptr [eax + 0x44], DAM_KNOCKED_OUT;
jnz clear; // Yes
test byte ptr [eax + 0x44], DAM_KNOCKED_DOWN;
jz clear; // No
push eax;
xor ecx, ecx;
mov edx, eax; // object
mov ebx, ecx; // extramem null
mov eax, ecx; // time = 0
inc ecx; // type = 1
call queue_add_; // run stand up anim
pop eax;
clear:
and word ptr [eax + 0x44], ~(DAM_LOSE_TURN or DAM_KNOCKED_DOWN) // 0x7FFD
and word ptr [eax + 0x44], ~(DAM_LOSE_TURN or DAM_KNOCKED_DOWN);
skip:
push 0x488F14
retn
end:
push 0x488EF9
retn
add esp, 4;
jmp obj_load_func_Ret;
}
}
static void __declspec(naked) partyMemberPrepLoadInstance_hook() {
__asm {
and word ptr [eax + 0x44], ~(DAM_LOSE_TURN or DAM_KNOCKED_DOWN) // 0x7FFD
jmp dude_stand_
and word ptr [eax + 0x44], ~(DAM_LOSE_TURN or DAM_KNOCKED_DOWN);
jmp dude_stand_;
}
}
static void __declspec(naked) combat_over_hack() {
__asm {
mov [eax + 0x3C], edx;
and word ptr [eax + 0x44], ~DAM_LOSE_TURN;
retn;
}
}
static void __declspec(naked) combat_over_hook() {
__asm {
test byte ptr [eax + 0x44], DAM_DEAD;
jz fix;
retn; // the dead cannot reload their weapons
fix:
test byte ptr [eax + 0x44], DAM_KNOCKED_DOWN;
jz skip;
push eax;
call dude_standup_;
pop eax;
xor edx, edx;
skip:
jmp cai_attempt_w_reload_;
}
}
@@ -1419,6 +1440,26 @@ end:
}
}
//zero damage insta death criticals fix (moved from compute_damage hook)
static void __fastcall InstantDeathFix(TComputeAttack &ctd) {
if (ctd.targetDamage == 0 && (ctd.targetFlags & DAM_DEAD)) {
ctd.targetDamage++; // set 1 hp damage
}
}
static const DWORD ComputeDamageRet = 0x424BA7;
static void __declspec(naked) compute_damage_hack() {
__asm {
mov ecx, esi; // ctd
call InstantDeathFix;
// overwritten engine code
add esp, 0x34;
pop ebp;
pop edi;
jmp ComputeDamageRet;
}
}
static int currDescLen = 0;
static bool showItemDescription = false;
static void __stdcall AppendText(const char* text, const char* desc) {
@@ -1719,7 +1760,7 @@ static void __declspec(naked) process_rads_hook() {
__asm {
push eax; // death message for DialogOut
call display_print_;
call GetCurrentLoops;
call GetLoopFlags;
test eax, PIPBOY;
jz skip;
mov eax, 1;
@@ -2062,10 +2103,148 @@ dude:
}
}
static long blockingTileObj = 0;
static const DWORD anim_move_to_tile_jmp = 0x416D91;
static void __declspec(naked) anim_move_to_tile_hook() {
__asm {
call obj_blocking_at_;
mov blockingTileObj, eax;
cmp edi, ds:[_obj_dude];
je isDude;
retn;
isDude:
test eax, eax;
jnz skip; // tile is blocked
mov ebx, dword ptr [esp + 0x18 - 0x10 + 4]; // distance
test ebx, ebx;
jl skip; // dist < 0
sub ebx, ds:[_combat_free_move];
cmp ebx, [edi + 0x40];
jge skip; // dist >= source.curr_mp
test eax, eax;
jnz skip;
add esp, 4;
jmp anim_move_to_tile_jmp;
skip:
retn;
}
}
static void __declspec(naked) anim_move_to_tile_hook_tile() {
__asm {
cmp blockingTileObj, 0;
jne getTile;
retn;
getTile:
jmp tile_num_in_direction_;
}
}
static void __declspec(naked) action_use_an_item_on_object_hack() {
__asm {
add ebx, ds:[_combat_free_move];
mov eax, 2; // RB_RESERVED
retn;
}
}
static void __declspec(naked) action_climb_ladder_hack() {
__asm {
add ecx, ds:[_combat_free_move];
mov eax, 2; // RB_RESERVED
retn;
}
}
//static const DWORD wmAreaMarkVisitedState_Error = 0x4C4698;
static const DWORD wmAreaMarkVisitedState_Ret = 0x4C46A2;
static void __declspec(naked) wmAreaMarkVisitedState_hack() {
__asm {
mov [ecx + 0x40], esi; // wmAreaInfoList.visited
test esi, esi; // mark "unknown" state
jz skip;
mov eax, [ecx + 0x2C]; // wmAreaInfoList.world_posx
mov edx, [ecx + 0x30]; // wmAreaInfoList.world_posy
// fix loc coordinates
cmp [ecx + 0x34], 1; // wmAreaInfoList.size
jg largeLoc;
je mediumLoc;
//smallLoc:
sub eax, 5;
lea edx, [edx - 5];
mediumLoc:
sub eax, 10;
lea edx, [edx - 10];
largeLoc:
mov ebx, esp; // ppSubTile out
push edx;
push eax;
call wmFindCurSubTileFromPos_;
// cmp eax, -1; // always return 0
// jz error;
pop eax;
pop edx;
mov ebx, [esp];
mov ebx, [ebx + 0x18]; // sub-tile state
test ebx, ebx;
jnz skip;
inc ebx; // 1
skip:
cmp [ecx + 0x38], 1; // wmAreaInfoList.start_state
jne hideLoc;
cmp esi, 2; // mark visited state
jne fix;
call wmMarkSubTileRadiusVisited_;
hideLoc:
jmp wmAreaMarkVisitedState_Ret;
fix:
push ebx;
mov ebx, 1; // radius (fix w/o PERK_scout)
call wmSubTileMarkRadiusVisited_;
pop ebx;
jmp wmAreaMarkVisitedState_Ret;
//error:
// add esp, 8;
// jmp wmAreaMarkVisitedState_Error;
}
}
static void __declspec(naked) wmWorldMap_hack() {
__asm {
mov ebx, [ebx + 0x34]; // wmAreaInfoList.size
cmp ebx, 1;
jg largeLoc;
je mediumLoc;
//smallLoc:
sub eax, 5;
lea edx, [edx - 5];
mediumLoc:
sub eax, 10;
lea edx, [edx - 10];
largeLoc:
xor ebx, ebx;
jmp wmPartyInitWalking_;
}
}
static const DWORD combat_should_end_break = 0x422D00;
static void __declspec(naked) combat_should_end_hack() {
__asm { // ecx = dude.team_num
cmp ecx, [ebp + 0x50]; // npc who_hit_me.team_num
je break;
test byte ptr [edx], 1; // npc combat_data.combat_state
jnz break;
retn; // check next critter
break:
add esp, 4;
jmp combat_should_end_break;
}
}
void BugFixesInit()
{
#ifndef NDEBUG
if (IsDebug && (GetPrivateProfileIntA("Debugging", "BugFixes", 1, ".\\ddraw.ini")) == 0)) return;
if (isDebug && (GetPrivateProfileIntA("Debugging", "BugFixes", 1, ".\\ddraw.ini") == 0)) return;
#endif
// fix vanilla negate operator on float values
@@ -2254,6 +2433,8 @@ void BugFixesInit()
SafeWrite8(0x4415CC, 0x00); // Prevent crashes when re-exporting
dlogr(" Done", DL_INIT);
//}
// Fix for op_lookup_string_proc_ engine function not searching the last procedure in a script
SafeWrite8(0x46C7AC, 0x76); // jb > jbe
//if (GetPrivateProfileIntA("Misc", "WieldObjCritterFix", 1, ini)) {
dlog("Applying wield_obj_critter fix.", DL_INIT);
@@ -2282,12 +2463,17 @@ void BugFixesInit()
// Fix for "NPC turns into a container" bug
//if (GetPrivateProfileIntA("Misc", "NPCTurnsIntoContainerFix", 1, ini)) {
dlog("Applying fix for \"NPC turns into a container\" bug.", DL_INIT);
MakeCall(0x424F8E, set_new_results_hack);
MakeJump(0x42E46E, critter_wake_clear_hack);
MakeJump(0x488EF3, obj_load_func_hack);
MakeCall(0x488EF3, obj_load_func_hack, 1);
HookCall(0x4949B2, partyMemberPrepLoadInstance_hook);
MakeCall(0x421F64, combat_over_hack, 1);
dlogr(" Done", DL_INIT);
//}
// Fix for multiple knockout events being added to the queue
HookCall(0x424F9A, set_new_results_hack);
// Fix for knocked down critters not playing stand up animation when the combat ends
// and prevent dead NPCs from reloading their weapons
HookCall(0x421F30, combat_over_hook);
dlog("Applying fix for explosives bugs.", DL_INIT);
// Fix crashes when killing critters with explosives
@@ -2407,6 +2593,11 @@ void BugFixesInit()
// in their AI packages is set to stay_close/charge, or NPCsTryToSpendExtraAP is enabled
HookCall(0x42A1A8, ai_move_steps_closer_hook); // 0x42B24D
// Fix instant death critical
dlog("Applying instant death fix.", DL_INIT);
MakeJump(0x424BA2, compute_damage_hack);
dlogr(" Done", DL_INIT);
// Fix missing AC/DR mod stats when examining ammo in the barter screen
dlog("Applying fix for displaying ammo stats in barter screen.", DL_INIT);
MakeCall(0x49B4AD, obj_examine_func_hack_ammo0, 2);
@@ -2610,4 +2801,25 @@ void BugFixesInit()
// up an item due to not enough space in the inventory
HookCall(0x49B6E7, obj_pickup_hook);
HookCall(0x49B71C, obj_pickup_hook_message);
// Fix for anim_move_to_tile_ engine function ignoring the distance argument for the player
HookCall(0x416D44, anim_move_to_tile_hook);
HookCall(0x416DD2, anim_move_to_tile_hook_tile);
// Fix for the player's movement in combat being interrupted when trying to use objects with Bonus Move APs available
MakeCall(0x411FD6, action_use_an_item_on_object_hack);
MakeCall(0x411DF7, action_climb_ladder_hack); // bug caused by anim_move_to_tile_ fix
// Fix for Scout perk being taken into account when setting the visibility of locations with mark_area_known function
// also fix the incorrect coordinates for small/medium location circles that the engine uses to highlight their sub-tiles
// and fix visited tiles on the world map being darkened again when a location is added next to them
MakeJump(0x4C466F, wmAreaMarkVisitedState_hack);
SafeWrite8(0x4C46AB, 0x58); // esi > ebx
// Fix the position of the target marker for small/medium location circles
MakeCall(0x4C03AA, wmWorldMap_hack, 2);
// Fix for combat not ending automatically when there are no hostile critters
MakeCall(0x422CF3, combat_should_end_hack);
SafeWrite16(0x422CEA, 0x0C74); // jz 0x422CF8 (skip party members)
}
+1 -1
View File
@@ -100,7 +100,7 @@ void CritLoad() {
int slot2 = crit + part * 6 + ((critter == 19) ? 38 : critter) * 9 * 6;
for (int i = 0; i < 7; i++) {
baseCritTable[slot2].values[i] = GetPrivateProfileIntA(section, CritNames[i], defaultTable[slot1].values[i], CritTableFile);
if (IsDebug) {
if (isDebug) {
char logmsg[256];
if (baseCritTable[slot2].values[i] != defaultTable[slot1].values[i]) {
sprintf_s(logmsg, "Entry %s value %d changed from %d to %d", section, i, defaultTable[slot1].values[i], baseCritTable[slot2].values[i]);
+45 -13
View File
@@ -25,18 +25,22 @@
#include "FalloutEngine.h"
#include "ScriptExtender.h"
#define CODE_EXIT (254)
#define CODE_SET_GLOBAL (0)
#define CODE_SET_MAPVAR (1)
#define CODE_GET_CRITTER (2)
#define CODE_SET_CRITTER (3)
#define CODE_SET_SGLOBAL (4)
#define CODE_GET_PROTO (5)
#define CODE_SET_PROTO (6)
#define CODE_GET_PLAYER (7)
#define CODE_SET_PLAYER (8)
#define CODE_GET_ARRAY (9)
#define CODE_SET_ARRAY (10)
enum DECode {
CODE_SET_GLOBAL = 0,
CODE_SET_MAPVAR = 1,
CODE_GET_CRITTER = 2,
CODE_SET_CRITTER = 3,
CODE_SET_SGLOBAL = 4,
CODE_GET_PROTO = 5,
CODE_SET_PROTO = 6,
CODE_GET_PLAYER = 7,
CODE_SET_PLAYER = 8,
CODE_GET_ARRAY = 9,
CODE_SET_ARRAY = 10,
CODE_GET_LOCVARS = 11,
CODE_SET_LOCVARS = 12,
CODE_EXIT = 254
};
static const char* debugLog = "LOG";
static const char* debugGnw = "GNW";
@@ -194,6 +198,33 @@ static void RunEditorInternal(SOCKET &s) {
delete[] data;
}
break;
case CODE_GET_LOCVARS:
{
InternalRecv(s, &id, 4); // sid
val = GetScriptLocalVars(id);
InternalSend(s, &val, 4);
if (val) {
std::vector<int> values(val);
long varVal;
for (int i = 0; i < val; i++) {
ScrGetLocalVar(id, i, &varVal);
values[i] = varVal;
}
InternalSend(s, values.data(), val * 4);
}
}
break;
case CODE_SET_LOCVARS:
{
InternalRecv(s, &id, 4); // sid
InternalRecv(s, &val, 4); // len data
std::vector<int> values(val);
InternalRecv(s, values.data(), val * 4);
for (int i = 0; i < val; i++) {
ScrSetLocalVar(id, i, values[i]);
}
}
break;
}
DEGameWinRedraw();
}
@@ -328,7 +359,8 @@ void DontDeleteProtosPatch() {
}
void DebugEditorInit() {
if (!IsDebug) return;
DebugModePatch();
if (!isDebug) return;
DontDeleteProtosPatch();
}
+18
View File
@@ -365,3 +365,21 @@ enum RollResult
ROLL_SUCCESS = 0x2,
ROLL_CRITICAL_SUCCESS = 0x3,
};
enum QueueType : long
{
drug_effect_event = 0, // critter use drug
knockout_event = 1, // critter
addict_event = 2, // critter
script_timer_event = 3, // any object
game_time_event = 4, // no object
poison_event = 5, // dude
radiation_event = 6, // dude
flare_time_event = 7, // item
explode_event = 8, // item
item_trickle_event = 9,
sneak_event = 10, // dude
explode_fail_event = 11, // item
map_update_event = 12,
gsound_sfx_event = 13 // no object
};
+58 -6
View File
@@ -265,6 +265,7 @@ const DWORD automap_ = 0x41B8BC;
const DWORD barter_compute_value_ = 0x474B2C;
const DWORD barter_inventory_ = 0x4757F0;
const DWORD buf_to_buf_ = 0x4D36D4;
const DWORD cai_attempt_w_reload_ = 0x42AECC;
const DWORD check_death_ = 0x410814;
const DWORD Check4Keys_ = 0x43F73C;
const DWORD combat_ = 0x422D2C;
@@ -339,6 +340,7 @@ const DWORD DrawFolder_ = 0x43410C;
const DWORD DrawInfoWin_ = 0x4365AC;
const DWORD drop_into_container_ = 0x476464;
const DWORD dude_stand_ = 0x418378;
const DWORD dude_standup_ = 0x418574;
const DWORD editor_design_ = 0x431DF8;
const DWORD elapsed_time_ = 0x4C93E0;
const DWORD elevator_end_ = 0x43F6D0;
@@ -509,8 +511,10 @@ const DWORD obj_dist_ = 0x48BBD4;
const DWORD obj_dist_with_tile_ = 0x48BC08;
const DWORD obj_drop_ = 0x49B8B0;
const DWORD obj_erase_object_ = 0x48B0FC;
const DWORD obj_find_first_ = 0x48B3A8;
const DWORD obj_find_first_at_ = 0x48B48C;
const DWORD obj_find_first_at_tile_ = 0x48B5A8;
const DWORD obj_find_next_ = 0x48B41C;
const DWORD obj_find_next_at_ = 0x48B510;
const DWORD obj_find_next_at_tile_ = 0x48B608;
const DWORD obj_lock_is_jammed_ = 0x49D410;
@@ -529,6 +533,7 @@ const DWORD obj_use_book_ = 0x49B9F0;
const DWORD obj_use_power_on_car_ = 0x49BDE8;
const DWORD object_under_mouse_ = 0x44CEC4;
const DWORD OptionWindow_ = 0x437C08;
const DWORD palette_init_ = 0x493A00;
const DWORD palette_set_to_ = 0x493B48;
const DWORD partyMemberCopyLevelInfo_ = 0x495EA8;
const DWORD partyMemberGetAIOptions_ = 0x4941F0;
@@ -591,15 +596,18 @@ const DWORD roll_random_ = 0x4A30C0;
const DWORD runProgram_ = 0x46E154;
const DWORD SaveGame_ = 0x47B88C;
const DWORD SavePlayer_ = 0x43A7DC;
const DWORD scr_exec_map_exit_scripts_ = 0x4A69A0;
const DWORD scr_exec_map_update_scripts_ = 0x4A67E4;
const DWORD scr_find_first_at_ = 0x4A6524;
const DWORD scr_find_next_at_ = 0x4A6564;
const DWORD scr_find_obj_from_program_ = 0x4A39AC;
const DWORD scr_find_sid_from_program_ = 0x4A390C;
const DWORD scr_get_local_var_ = 0x4A6D64;
const DWORD scr_new_ = 0x4A5F28;
const DWORD scr_ptr_ = 0x4A5E34;
const DWORD scr_remove_ = 0x4A61D4;
const DWORD scr_set_ext_param_ = 0x4A3B34;
const DWORD scr_set_local_var_ = 0x4A6E58;
const DWORD scr_set_objs_ = 0x4A3B0C;
const DWORD scr_write_ScriptNode_ = 0x4A5704;
const DWORD set_game_time_ = 0x4A347C;
@@ -636,6 +644,7 @@ const DWORD text_font_ = 0x4D58DC;
const DWORD text_object_create_ = 0x4B036C;
const DWORD tile_coord_ = 0x4B1674;
const DWORD tile_num_ = 0x4B1754;
const DWORD tile_num_in_direction_ = 0x4B1A6C;
const DWORD tile_refresh_display_ = 0x4B12D8;
const DWORD tile_refresh_rect_ = 0x4B12C0;
const DWORD tile_scroll_to_ = 0x4B3924;
@@ -659,8 +668,13 @@ const DWORD win_register_button_ = 0x4D8260;
const DWORD win_register_button_disable_ = 0x4D8674;
const DWORD win_register_button_sound_func_ = 0x4D87F8;
const DWORD win_show_ = 0x4D6DAC;
const DWORD wmFindCurSubTileFromPos_ = 0x4C0C00;
const DWORD wmInterfaceScrollTabsStart_ = 0x4C219C;
const DWORD wmMapIsSaveable_ = 0x4BFA64;
const DWORD wmMarkSubTileRadiusVisited_ = 0x4C3550;
const DWORD wmPartyInitWalking_ = 0x4C1E54;
const DWORD wmPartyWalkingStep_ = 0x4C1F90;
const DWORD wmSubTileMarkRadiusVisited_ = 0x4C35A8;
const DWORD wmWorldMapFunc_ = 0x4BFE10;
const DWORD wmWorldMapLoadTempData_ = 0x4BD6B4;
const DWORD xfclose_ = 0x4DED6C;
@@ -713,21 +727,26 @@ long __stdcall PartyMemberGetCurrentLevel(TGameObj* obj) {
}
}
char* GetProtoPtr(DWORD pid) {
char* GetProtoPtr(long pid) {
char* proto;
long result;
__asm {
mov eax, pid;
lea edx, proto;
call proto_ptr_;
mov result, eax;
}
return proto;
if (result != -1) {
return proto;
}
return nullptr;
}
char AnimCodeByWeapon(TGameObj* weapon) {
if (weapon != NULL) {
if (weapon != nullptr) {
char* proto = GetProtoPtr(weapon->pid);
if (proto && *(int*)(proto + 32) == item_type_weapon) {
return (char)(*(int*)(proto + 36));
if (proto != nullptr && *(int*)(proto + 32) == item_type_weapon) {
return (char)(*(int*)(proto + 36));
}
}
return 0;
@@ -741,7 +760,7 @@ void DisplayConsoleMessage(const char* msg) {
}
static DWORD mesg_buf[4] = {0, 0, 0, 0};
const char* _stdcall GetMessageStr(DWORD fileAddr, DWORD messageId) {
const char* __stdcall GetMessageStr(DWORD fileAddr, DWORD messageId) {
DWORD buf = (DWORD)mesg_buf;
const char* result;
__asm {
@@ -792,6 +811,8 @@ void SkillSetTags(int* tags, DWORD num) {
}
}
// Saves pointer to script object into scriptPtr using scriptID.
// Returns 0 on success, -1 on failure.
long __stdcall ScrPtr(long scriptId, TScript** scriptPtr) {
__asm {
mov eax, scriptId;
@@ -800,6 +821,29 @@ long __stdcall ScrPtr(long scriptId, TScript** scriptPtr) {
}
}
// Returns the number of local variables of the object script
long GetScriptLocalVars(long sid) {
TScript* script = nullptr;
ScrPtr(sid, &script);
return (script) ? script->num_local_vars : 0;
}
long __fastcall ScrGetLocalVar(long sid, long varId, long* value) {
__asm {
mov ebx, value;
mov eax, ecx;
call scr_get_local_var_;
}
}
long __fastcall ScrSetLocalVar(long sid, long varId, long value) {
__asm {
mov ebx, value;
mov eax, ecx;
call scr_set_local_var_;
}
}
// redraws the main game interface windows (useful after changing some data like active hand, etc.)
void InterfaceRedraw() {
__asm call intface_redraw_;
@@ -1028,6 +1072,14 @@ long __stdcall QueueFindFirst(TGameObj* object, long qType) {
}
}
TGameObj* __stdcall ObjFindFirst() {
__asm call obj_find_first_;
}
TGameObj* __stdcall ObjFindNext() {
__asm call obj_find_next_;
}
long __stdcall NewObjId() {
__asm call new_obj_id_;
}
+33 -9
View File
@@ -17,9 +17,9 @@
*/
#pragma once
/*
* FALLOUT2.EXE structs, function offsets and wrappers should be placed here
*
/*
* FALLOUT2.EXE structs, function offsets and wrappers should be placed here
*
* only place functions and variables here which are likely to be used in more than one module
*
*/
@@ -488,6 +488,7 @@ extern const DWORD automap_;
extern const DWORD barter_compute_value_;
extern const DWORD barter_inventory_;
extern const DWORD buf_to_buf_;
extern const DWORD cai_attempt_w_reload_;
extern const DWORD check_death_;
extern const DWORD Check4Keys_;
extern const DWORD combat_;
@@ -562,6 +563,7 @@ extern const DWORD DrawFolder_;
extern const DWORD DrawInfoWin_;
extern const DWORD drop_into_container_;
extern const DWORD dude_stand_;
extern const DWORD dude_standup_;
extern const DWORD editor_design_;
extern const DWORD elapsed_time_;
extern const DWORD elevator_end_;
@@ -618,7 +620,7 @@ extern const DWORD interpretPopLong_;
extern const DWORD interpretPopShort_;
extern const DWORD interpretPushLong_;
extern const DWORD interpretPushShort_;
extern const DWORD interpretError_;
extern const DWORD interpretError_;
extern const DWORD intface_get_attack_;
extern const DWORD intface_hide_;
extern const DWORD intface_is_hidden_;
@@ -698,7 +700,7 @@ extern const DWORD main_game_loop_;
extern const DWORD main_init_system_;
extern const DWORD main_menu_hide_;
extern const DWORD main_menu_loop_;
// (int aObjFrom<eax>, int aTileFrom<edx>, char* aPathPtr<ecx>, int aTileTo<ebx>, int a5, int (__fastcall *a6)(_DWORD, _DWORD))
// (int aObjFrom<eax>, int aTileFrom<edx>, char* aPathPtr<ecx>, int aTileTo<ebx>, int a5, int (__fastcall *a6)(_DWORD, _DWORD))
// - path is saved in ecx as a sequence of tile directions (0..5) to move on each step,
// - returns path length
extern const DWORD make_path_func_;
@@ -737,8 +739,10 @@ extern const DWORD obj_dist_;
extern const DWORD obj_dist_with_tile_;
extern const DWORD obj_drop_;
extern const DWORD obj_erase_object_;
extern const DWORD obj_find_first_;
extern const DWORD obj_find_first_at_;
extern const DWORD obj_find_first_at_tile_; // <eax>(int elevation<eax>, int tile<edx>)
extern const DWORD obj_find_next_;
extern const DWORD obj_find_next_at_;
extern const DWORD obj_find_next_at_tile_; // no args
extern const DWORD obj_lock_is_jammed_;
@@ -760,6 +764,7 @@ extern const DWORD obj_use_book_;
extern const DWORD obj_use_power_on_car_;
extern const DWORD object_under_mouse_;
extern const DWORD OptionWindow_;
extern const DWORD palette_init_;
extern const DWORD palette_set_to_;
extern const DWORD partyMemberCopyLevelInfo_;
extern const DWORD partyMemberGetAIOptions_;
@@ -822,15 +827,18 @@ extern const DWORD roll_random_;
extern const DWORD runProgram_; // eax - programPtr, called once for each program after first loaded - hooks program to game and UI events
extern const DWORD SaveGame_;
extern const DWORD SavePlayer_;
extern const DWORD scr_exec_map_exit_scripts_;
extern const DWORD scr_exec_map_update_scripts_;
extern const DWORD scr_find_first_at_; // eax - elevation, returns spatial scriptID
extern const DWORD scr_find_next_at_; // no args, returns spatial scriptID
extern const DWORD scr_find_obj_from_program_; // eax - *program - finds self_obj by program pointer (has nice additional effect - creates fake object for a spatial script)
extern const DWORD scr_find_sid_from_program_;
extern const DWORD scr_get_local_var_;
extern const DWORD scr_new_; // eax - script index from scripts lst, edx - type (0 - system, 1 - spatials, 2 - time, 3 - items, 4 - critters)
extern const DWORD scr_ptr_; // eax - scriptId, edx - **TScript (where to store script pointer)
extern const DWORD scr_remove_;
extern const DWORD scr_set_ext_param_;
extern const DWORD scr_set_local_var_;
extern const DWORD scr_set_objs_;
extern const DWORD scr_write_ScriptNode_;
extern const DWORD set_game_time_;
@@ -867,6 +875,7 @@ extern const DWORD text_font_;
extern const DWORD text_object_create_;
extern const DWORD tile_coord_; // eax - tilenum, edx (int*) - x, ebx (int*) - y
extern const DWORD tile_num_;
extern const DWORD tile_num_in_direction_;
extern const DWORD tile_refresh_display_;
extern const DWORD tile_refresh_rect_; // (int elevation<edx>, unkown<ecx>)
extern const DWORD tile_scroll_to_;
@@ -890,8 +899,13 @@ extern const DWORD win_register_button_;
extern const DWORD win_register_button_disable_;
extern const DWORD win_register_button_sound_func_;
extern const DWORD win_show_;
extern const DWORD wmFindCurSubTileFromPos_;
extern const DWORD wmInterfaceScrollTabsStart_;
extern const DWORD wmMapIsSaveable_;
extern const DWORD wmMarkSubTileRadiusVisited_;
extern const DWORD wmPartyInitWalking_;
extern const DWORD wmPartyWalkingStep_;
extern const DWORD wmSubTileMarkRadiusVisited_;
extern const DWORD wmWorldMapFunc_;
extern const DWORD wmWorldMapLoadTempData_;
extern const DWORD xfclose_;
@@ -918,7 +932,7 @@ extern const DWORD xvfprintf_;
* in ASM code, call offsets directly, don't call wrappers as they might not be _stdcall
* in C++ code, use wrappers (add new ones if the don't exist yet)
*
* Note: USE C++!
* Note: USE C++!
* 1) Place thin __declspec(naked) hooks, only use minimum ASM to pass values to/from C++
* 2) Call _stdcall functions from (1), write those entirely in C++ (with little ASM blocks only to call engine functions, when you are too lazy to add wrapper)
*/
@@ -948,11 +962,11 @@ extern const DWORD xvfprintf_;
// TODO: move these to different namespace
long __stdcall IsPartyMember(TGameObj* obj);
long __stdcall PartyMemberGetCurrentLevel(TGameObj* obj);
char* GetProtoPtr(DWORD pid);
char* GetProtoPtr(long pid);
char AnimCodeByWeapon(TGameObj* weapon);
// Displays message in main UI console window
void DisplayConsoleMessage(const char* msg);
const char* _stdcall GetMessageStr(DWORD fileAddr, DWORD messageId);
const char* __stdcall GetMessageStr(DWORD fileAddr, DWORD messageId);
long __stdcall ItemGetType(TGameObj* item);
long __stdcall ItemSize(TGameObj* item);
@@ -962,10 +976,16 @@ void CritterPcSetName(const char* newName);
// Returns the name of the critter
const char* __stdcall CritterName(TGameObj* critter);
// Saves pointer to script object into scriptPtr using scriptID.
// Saves pointer to script object into scriptPtr using scriptID.
// Returns 0 on success, -1 on failure.
long __stdcall ScrPtr(long scriptId, TScript** scriptPtr);
// Returns the number of local variables of the object script
long GetScriptLocalVars(long sid);
long __fastcall ScrGetLocalVar(long sid, long varId, long* value);
long __fastcall ScrSetLocalVar(long sid, long varId, long value);
void SkillGetTags(int* result, DWORD num);
void SkillSetTags(int* tags, DWORD num);
@@ -1035,6 +1055,10 @@ long __stdcall TraitLevel(long traitID);
long __stdcall QueueFindFirst(TGameObj* object, long qType);
TGameObj* __stdcall ObjFindFirst();
TGameObj* __stdcall ObjFindNext();
long __stdcall NewObjId();
FrmFrameData* __fastcall FramePtr(FrmHeaderData* frm, long frame, long direction);
+18 -11
View File
@@ -78,20 +78,27 @@ struct TGameObj
#pragma pack(push, 1)
struct TComputeAttack
{
TGameObj *attacker;
char gap_4[4];
TGameObj *weapon;
char gap_C[4];
long damageAttacker;
long flagsAttacker;
long rounds;
char gap_1C[4];
TGameObj *target;
TGameObj* attacker;
long hitMode;
TGameObj* weapon;
long field_C;
long attackerDamage;
long attackerFlags;
long numRounds;
long message;
TGameObj* target;
long targetTile;
long bodyPart;
long damageTarget;
long flagsTarget;
long targetDamage;
long targetFlags;
long knockbackValue;
TGameObj* mainTarget;
long numExtras;
TGameObj* extraTarget[6];
long extraBodyPart[6];
long extraDamage[6];
long extraFlags[6];
long extraKnockbackValue[6];
};
#pragma pack(pop)
+24 -13
View File
@@ -62,11 +62,13 @@ static DDSURFACEDESC surfaceDesc;
static DDSURFACEDESC movieDesc;
static DWORD palette[256];
//static bool paletteInit = false;
static DWORD gWidth;
static DWORD gHeight;
static int ScrollWindowKey;
static bool windowInit = false;
static DWORD windowLeft = 0;
static DWORD windowTop = 0;
@@ -124,8 +126,7 @@ static const char* gpuEffect=
"technique T0"
"{"
"pass p0 { PixelShader = compile ps_2_0 P0(); }"
"}"
;
"}";
static D3DXHANDLE gpuBltBuf;
static D3DXHANDLE gpuBltPalette;
@@ -169,11 +170,11 @@ void GetFalloutWindowInfo(DWORD* width, DWORD* height, HWND* wnd) {
}
long Gfx_GetGameWidthRes() {
return ptr_scr_size->offx - (ptr_scr_size->x + 1);
return (ptr_scr_size->offx - ptr_scr_size->x) + 1;
}
long Gfx_GetGameHeightRes() {
return ptr_scr_size->offy - (ptr_scr_size->y + 1);
return (ptr_scr_size->offy - ptr_scr_size->y) + 1;
}
int _stdcall GetShaderVersion() {
@@ -388,7 +389,8 @@ static void Present() {
if (ScrollWindowKey != 0 && ((ScrollWindowKey > 0 && KeyDown((BYTE)ScrollWindowKey))
|| (ScrollWindowKey == -1 && (KeyDown(DIK_LCONTROL) || KeyDown(DIK_RCONTROL)))
|| (ScrollWindowKey == -2 && (KeyDown(DIK_LMENU) || KeyDown(DIK_RMENU)))
|| (ScrollWindowKey == -3 && (KeyDown(DIK_LSHIFT) || KeyDown(DIK_RSHIFT))))) {
|| (ScrollWindowKey == -3 && (KeyDown(DIK_LSHIFT) || KeyDown(DIK_RSHIFT)))))
{
int winx, winy;
GetMouse(&winx, &winy);
windowLeft += winx;
@@ -474,8 +476,8 @@ void RefreshGraphics() {
}
for (int d = shadersSize - 1; d >= 0; d--) {
if (!shaders[d].Effect || !shaders[d].Active) continue;
if (shaders[d].mode2 && !(shaders[d].mode2 & GetCurrentLoops())) continue;
if (shaders[d].mode & GetCurrentLoops()) continue;
if (shaders[d].mode2 && !(shaders[d].mode2 & GetLoopFlags())) continue;
if (shaders[d].mode & GetLoopFlags()) continue;
if (shaders[d].ehTicks) shaders[d].Effect->SetInt(shaders[d].ehTicks, GetTickCount());
UINT passes;
@@ -499,7 +501,7 @@ void RefreshGraphics() {
gpuBltEffect->BeginPass(0);
}
d3d9Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
if (GPUBlt) {
if (GPUBlt && !shadersSize) {
gpuBltEffect->EndPass();
gpuBltEffect->End();
}
@@ -623,10 +625,10 @@ public:
HRESULT _stdcall GetEntries(DWORD, DWORD, DWORD, LPPALETTEENTRY) { UNUSEDFUNCTION; }
HRESULT _stdcall Initialize(LPDIRECTDRAW, DWORD, LPPALETTEENTRY) { UNUSEDFUNCTION; }
HRESULT _stdcall SetEntries(DWORD, DWORD b, DWORD c, LPPALETTEENTRY d) {
if (c == 0 || b + c > 256) return DDERR_INVALIDPARAMS;
HRESULT _stdcall SetEntries(DWORD, DWORD b, DWORD c, LPPALETTEENTRY destPal) {
if (!windowInit || c == 0 || b + c > 256) return DDERR_INVALIDPARAMS;
CopyMemory(&palette[b], d, c * 4);
CopyMemory(&palette[b], destPal, c * 4);
if (GPUBlt) {
if (gpuPalette) {
D3DLOCKED_RECT rect;
@@ -638,11 +640,12 @@ public:
} else {
for (DWORD i = b; i < b + c; i++) { // swap color R <> B
//palette[i]&=0x00ffffff;
BYTE clr = *(BYTE*)((DWORD)&palette[i]);
*(BYTE*)((DWORD)&palette[i]) = *(BYTE*)((DWORD)&palette[i] + 2);
BYTE clr = *(BYTE*)((DWORD)&palette[i]); // B
*(BYTE*)((DWORD)&palette[i]) = *(BYTE*)((DWORD)&palette[i] + 2); // R
*(BYTE*)((DWORD)&palette[i] + 2) = clr;
}
}
RefreshGraphics();
return DD_OK;
}
};
@@ -1058,6 +1061,13 @@ HRESULT _stdcall FakeDirectDrawCreate2(void*, IDirectDraw** b, void*) {
return DD_OK;
}
static __declspec(naked) void game_init_hook() {
__asm {
mov windowInit, 1;
jmp palette_init_;
}
}
static double fadeMulti;
static __declspec(naked) void palette_fade_to_hook() {
__asm {
@@ -1091,6 +1101,7 @@ void GraphicsInit() {
}
#undef _DLL_NAME
SafeWrite8(0x50FB6B, '2'); // Set call DirectDrawCreate2
HookCall(0x44260C, game_init_hook);
dlogr(" Done", DL_INIT);
}
+10 -13
View File
@@ -82,7 +82,7 @@ typedef class UNLSTDframe {
}
~UNLSTDframe() {
if (indexBuff != nullptr)
delete[] indexBuff;
delete[] indexBuff;
}
} UNLSTDframe;
@@ -112,7 +112,7 @@ typedef class UNLSTDfrm {
}
~UNLSTDfrm() {
if (frames != nullptr)
delete[] frames;
delete[] frames;
}
} UNLSTDfrm;
@@ -769,8 +769,8 @@ void _stdcall RefreshHeroBaseArt() {
}
/*
// Check fallout paths for file
long __stdcall db_file_exist(const char *fileName, DWORD *sizeOut) {
// Check fallout file and get file size (result 0 - file exists)
long __stdcall db_dir_entry(const char *fileName, DWORD *sizeOut) {
__asm {
mov edx, sizeOut;
mov eax, fileName;
@@ -864,19 +864,16 @@ setPath:
static void __declspec(naked) CheckHeroExist() {
__asm {
cmp esi, critterArraySize; // check if loading hero art
cmp esi, critterArraySize; // check if loading hero art
jle endFunc;
sub esp, 4;
lea edx, [esp]; // size out
mov eax, _art_name; // critter art file name address
call db_dir_entry_; // check art file exists
add esp, 4;
cmp eax, -1;
jne endFunc;
mov eax, _art_name; // critter art file name address (file name)
call db_access_; // check art file exists
test eax, eax;
jnz endFunc;
// if file not found load regular critter art instead
sub esi, critterArraySize;
add esp, 4; // drop func ret address
add esp, 4; // drop func ret address
mov eax, 0x4194E2;
jmp eax;
endFunc:

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