Compare commits

...
24 Commits
Author SHA1 Message Date
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
44 changed files with 1130 additions and 758 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")]
+9 -4
View File
@@ -1,5 +1,5 @@
;sfall configuration settings
;v3.8.18
;v3.8.19
[Main]
;Change to 1 if you want to use command line args to tell sfall to use another ini file.
@@ -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
+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
+244 -57
View File
@@ -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_;
}
}
@@ -1719,7 +1740,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 +2083,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 +2413,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 +2443,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
@@ -2610,4 +2776,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]);
+44 -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,7 @@ void DontDeleteProtosPatch() {
}
void DebugEditorInit() {
if (!IsDebug) return;
if (!isDebug) return;
DebugModePatch();
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);
+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:
+2 -2
View File
@@ -1422,7 +1422,7 @@ static void LoadHookScript(const char* name, int id) {
if (fileExist) {
sScriptProgram prog;
dlog(">", DL_HOOK);
dlog("> ", DL_HOOK);
dlog(name, DL_HOOK);
LoadScriptProgram(prog, name);
if (prog.ptr) {
@@ -1440,7 +1440,7 @@ static void LoadHookScript(const char* name, int id) {
}
static void HookScriptInit2() {
dlogr("Loading hook scripts", DL_HOOK|DL_INIT);
dlogr("Loading hook scripts:", DL_HOOK|DL_INIT);
char* mask = "scripts\\hs_*.int";
DWORD *filenames;
+49 -6
View File
@@ -34,12 +34,12 @@ static DWORD itemFastMoveKey = 0;
static DWORD skipFromContainer = 0;
struct sMessage {
DWORD number;
DWORD flags;
long number;
long flags;
char* audio;
char* message;
};
static const char* MsgSearch(int msgno, DWORD file) {
static const char* MsgSearch(long msgno, DWORD file) {
if(!file) return 0;
sMessage msg = { msgno, 0, 0, 0 };
__asm {
@@ -59,7 +59,7 @@ TGameObj* GetActiveItem() {
}
void InventoryKeyPressedHook(DWORD dxKey, bool pressed, DWORD vKey) {
if (pressed && reloadWeaponKey && dxKey == reloadWeaponKey && IsMapLoaded() && (GetCurrentLoops() & ~(COMBAT | PCOMBAT)) == 0) {
if (pressed && reloadWeaponKey && dxKey == reloadWeaponKey && IsMapLoaded() && (GetLoopFlags() & ~(COMBAT | PCOMBAT)) == 0) {
DWORD maxAmmo, curAmmo;
TGameObj* item = GetActiveItem();
__asm {
@@ -651,6 +651,34 @@ skip:
}
}
static void __declspec(naked) op_inven_unwield_hook() {
__asm {
mov ecx, [eax + 0x64];
and ecx, 0x0F000000;
cmp ecx, OBJ_TYPE_CRITTER << 24;
jne skip;
test byte ptr [eax + 0x44], DAM_KNOCKED_OUT;
jz skip;
push 0x505AFC; // "But is already Inactive (Dead/Stunned/Invisible)"
call debug_printf_;
add esp, 4;
retn;
skip:
jmp inven_unwield_;
}
}
static void __declspec(naked) op_wield_obj_critter_hook() {
__asm {
test byte ptr [eax + 0x44], DAM_KNOCKED_OUT;
jz skip;
mov eax, -1;
retn;
skip:
jmp inven_wield_;
}
}
static const DWORD DoMoveTimer_Ret = 0x476920;
static void __declspec(naked) do_move_timer_hook() {
__asm {
@@ -679,6 +707,16 @@ end:
}
}
static void __declspec(naked) do_move_timer_hack() {
__asm {
mov ebx, 1;
call GetLoopFlags;
test eax, BARTER;
cmovz ebx, ebp; // set max when not in barter
retn;
}
}
static int invenApCost, invenApCostDef;
static char invenApQPReduction;
static const DWORD inven_ap_cost_Ret = 0x46E812;
@@ -804,7 +842,7 @@ void InventoryInit() {
}
if (GetPrivateProfileIntA("Misc", "ItemCounterDefaultMax", 0, ini)) {
BlockCall(0x4768A3); // mov ebx, 1
MakeCall(0x4768A3, do_move_timer_hack);
}
// Move items from bag/backpack to the main inventory list by dragging them on the character portrait (similar to Fallout 1 behavior)
@@ -817,6 +855,11 @@ void InventoryInit() {
if (UseScrollWheel) {
MakeCall(0x473E66, loot_container_hack_scroll);
MakeCall(0x4759F1, barter_inventory_hack_scroll);
*((DWORD*)_max) = 100;
*ptr_max = 100;
};
// Check the DAM_KNOCKED_OUT flag for wield_obj_critter/inven_unwield script functions
// Note: the flag is not checked for the metarule(METARULE_INVEN_UNWIELD_WHO, x) function
HookCall(0x45B0CE, op_inven_unwield_hook);
HookCall(0x45693C, op_wield_obj_critter_hook);
}
+2 -2
View File
@@ -70,7 +70,7 @@ DWORD InDialog() {
return (InLoop & DIALOG) ? 1 : 0;
}
DWORD GetCurrentLoops() {
DWORD GetLoopFlags() {
return InLoop;
}
@@ -210,7 +210,7 @@ static bool _stdcall LoadGame2_Before() {
errorLoad:
CloseHandle(h);
dlog_f("ERROR reading data: %s\n", DL_MAIN, buf);
return (true & !IsDebug);
return (true & !isDebug);
}
static void _stdcall LoadGame2_After() {

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