diff --git a/MPClient/DebugEditor.Designer.cs b/MPClient/DebugEditor.Designer.cs index 4f67d06e..c9ce1dae 100644 --- a/MPClient/DebugEditor.Designer.cs +++ b/MPClient/DebugEditor.Designer.cs @@ -23,6 +23,7 @@ /// the contents of this method with the code editor. /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.dataGridView1 = new System.Windows.Forms.DataGridView(); this.Column0 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); @@ -34,6 +35,7 @@ this.bSGlobals = new System.Windows.Forms.Button(); this.bArrays = new System.Windows.Forms.Button(); this.bEdit = new System.Windows.Forms.Button(); + this.bCrittersLvar = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); this.SuspendLayout(); // @@ -153,11 +155,23 @@ this.bEdit.UseVisualStyleBackColor = true; this.bEdit.Click += new System.EventHandler(this.bEdit_Click); // + // bCrittersLvar + // + 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.Name = "bCrittersLvar"; + this.bCrittersLvar.Size = new System.Drawing.Size(99, 23); + this.bCrittersLvar.TabIndex = 7; + this.bCrittersLvar.Text = "Local variables"; + this.bCrittersLvar.UseVisualStyleBackColor = true; + // // DebugEditor // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(585, 436); + this.Controls.Add(this.bCrittersLvar); this.Controls.Add(this.bEdit); this.Controls.Add(this.bArrays); this.Controls.Add(this.bSGlobals); @@ -187,6 +201,7 @@ private System.Windows.Forms.DataGridViewTextBoxColumn Column1; private System.Windows.Forms.DataGridViewTextBoxColumn Column2; private System.Windows.Forms.DataGridViewTextBoxColumn Column3; + private System.Windows.Forms.Button bCrittersLvar; } } \ No newline at end of file diff --git a/MPClient/DebugEditor.cs b/MPClient/DebugEditor.cs index 42b21368..a9051113 100644 --- a/MPClient/DebugEditor.cs +++ b/MPClient/DebugEditor.cs @@ -187,8 +187,9 @@ namespace FalloutClient { return; } if (e.ColumnIndex == 2) { + string str = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString(); int val; - if (!int.TryParse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString(), out val)) { + if (str == null || !int.TryParse(str, out val)) { dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = array[e.RowIndex]; } else { array[e.RowIndex] = val; @@ -197,8 +198,9 @@ namespace FalloutClient { connection.WriteInt(val); } } else { + string str = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString(); float val; - if (!float.TryParse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString(), out val)) { + if (str == null || !float.TryParse(str, out val)) { dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = array[e.RowIndex]; } else { array[e.RowIndex] = converter.GetAsInt(val); @@ -226,9 +228,7 @@ namespace FalloutClient { lenData += lenType[j]; } byte[] buf = connection.ReadBytes(lenData); // read data - MemoryStream ms=new MemoryStream(buf); - BinaryReader br=new BinaryReader(ms); - ms.Position = 0; + BinaryReader br = new BinaryReader(new MemoryStream(buf)); for (int j = 0; j < strings.Length; j++) { switch (types[j]) { case DataType.Int: @@ -239,19 +239,16 @@ namespace FalloutClient { break; case DataType.String: byte[] bytes = br.ReadBytes(lenType[j]); - strings[j] = System.Text.Encoding.ASCII.GetString(bytes, 0, lenType[j] - 1); //Array.IndexOf(bytes, 0) + strings[j] = System.Text.Encoding.ASCII.GetString(bytes, 0, Array.IndexOf(bytes, 0)); break; } } br.Close(); - strings = EditorWindow.ShowEditor(null, types, strings, true); + strings = EditorWindow.ShowEditor(this, null, types, strings, connection.ArrayIsMap[i]); if (strings != null) { // save - /*connection.WriteDataType(DataTypeSend.SetArray); - connection.WriteInt(i); - ms = new MemoryStream(connection.ArrayLengths[i] * connection.ArrayFlag[i]); - BinaryWriter bw=new BinaryWriter(ms); + MemoryStream ms = new MemoryStream(lenData); + BinaryWriter bw = new BinaryWriter(ms); for (int j = 0; j < strings.Length; j++) { - ms.Position = j * connection.ArrayFlag[i]; switch (types[j]) { case DataType.Int: bw.Write(int.Parse(strings[j])); @@ -260,15 +257,21 @@ namespace FalloutClient { bw.Write(float.Parse(strings[j])); break; case DataType.String: - byte[] bytes=System.Text.Encoding.ASCII.GetBytes(strings[j]); - if (bytes.Length < connection.ArrayFlag[i]) bw.Write(bytes); - else bw.Write(bytes, 0, connection.ArrayFlag[i] - 1); - bw.Write(0); + byte[] bytes = System.Text.Encoding.ASCII.GetBytes(strings[j]); + if (bytes.Length < lenType[j]) + bw.Write(bytes); + else + bw.Write(bytes, 0, lenType[j] - 1); + bw.Write((byte)0); break; } } - connection.WriteBytes(ms.GetBuffer(), 0, connection.ArrayLengths[i] * connection.ArrayFlag[i]); - bw.Close();*/ + // send data to sfall + connection.WriteDataType(DataTypeSend.SetArray); + connection.WriteInt(i); // index + connection.WriteInt(lenData); + connection.WriteBytes(ms.GetBuffer(), 0, lenData); + bw.Close(); } } break; @@ -309,7 +312,7 @@ namespace FalloutClient { names[29] = " Outline flags"; names[30] = " Script ID"; names[32] = " Script index"; - strings = EditorWindow.ShowEditor(names, types, strings); + strings = EditorWindow.ShowEditor(this, names, types, strings); if (strings != null) { MemoryStream ms = new MemoryStream(33 * 4); BinaryWriter bw = new BinaryWriter(ms); diff --git a/MPClient/EditorWindow.Designer.cs b/MPClient/EditorWindow.Designer.cs index 69487443..b2e7b02d 100644 --- a/MPClient/EditorWindow.Designer.cs +++ b/MPClient/EditorWindow.Designer.cs @@ -109,6 +109,7 @@ this.Controls.Add(this.bCancel); this.Controls.Add(this.bSave); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; + this.MinimumSize = new System.Drawing.Size(300, 200); this.Name = "EditorWindow"; this.Text = "Editor Values"; ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); diff --git a/MPClient/EditorWindow.cs b/MPClient/EditorWindow.cs index d3b9c423..b7a9eb60 100644 --- a/MPClient/EditorWindow.cs +++ b/MPClient/EditorWindow.cs @@ -28,7 +28,7 @@ namespace FalloutClient { dataGridView1.ResumeLayout(); } - public static string[] ShowEditor(string[] names, DataType[] types, string[] values, bool isMap = false) { + 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) @@ -51,7 +51,7 @@ namespace FalloutClient { private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) { string str = (string)dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value; - if (CheckInput(types[e.RowIndex], str)) + if (str != null && CheckInput(types[e.RowIndex], str)) values[e.RowIndex] = str; else dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = values[e.RowIndex]; diff --git a/MPClient/EditorWindow.resx b/MPClient/EditorWindow.resx index f9914ad8..a4ce6fe7 100644 --- a/MPClient/EditorWindow.resx +++ b/MPClient/EditorWindow.resx @@ -126,4 +126,13 @@ True + + True + + + True + + + True + \ No newline at end of file diff --git a/MPClient/Program.cs b/MPClient/Program.cs index a1afae60..f8e7308c 100644 --- a/MPClient/Program.cs +++ b/MPClient/Program.cs @@ -15,7 +15,8 @@ namespace FalloutClient { if (args.Length == 1 && args[0] == "-debugedit") { Application.Run(new DebugEditor(new EditorConnection())); } else { - throw new Exception("Multiplayer is no longer supported"); + MessageBox.Show("The debug editor can only be run from the game.", + "sfall Debug Editor", MessageBoxButtons.OK, MessageBoxIcon.Stop); } } } diff --git a/sfall/FalloutEngine/Functions_def.h b/sfall/FalloutEngine/Functions_def.h index 8053ea0f..2b8ef827 100644 --- a/sfall/FalloutEngine/Functions_def.h +++ b/sfall/FalloutEngine/Functions_def.h @@ -92,6 +92,7 @@ WRAP_WATCOM_FUNC2(void, perk_add_effect, GameObject*, critter, long, perkId) WRAP_WATCOM_FUNC2(long, perk_can_add, GameObject*, critter, long, perkId) //WRAP_WATCOM_FUNC2(void, perk_remove_effect, GameObject*, critter, long, perkId) WRAP_WATCOM_FUNC6(long, pick_death, GameObject*, attacker, GameObject*, target, GameObject*, weapon, long, amount, long, anim, long, hitFromBack) +WRAP_WATCOM_FUNC0(void, process_bk) WRAP_WATCOM_FUNC0(void, proto_dude_update_gender) WRAP_WATCOM_FUNC2(long*, queue_find_first, GameObject*, object, long, qType) WRAP_WATCOM_FUNC2(long*, queue_find_next, GameObject*, object, long, qType) diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index a8a26ef1..14159628 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -180,8 +180,9 @@ #define FO_VAR_retvals 0x43EA7C #define FO_VAR_rotation 0x631D34 #define FO_VAR_sad 0x530014 -#define FO_VAR_script_path_base 0x51C710 #define FO_VAR_scr_size 0x6AC9F0 +#define FO_VAR_script_engine_running 0x51C714 +#define FO_VAR_script_path_base 0x51C710 #define FO_VAR_scriptListInfo 0x51C7C8 #define FO_VAR_skill_data 0x51D118 #define FO_VAR_slot_cursor 0x5193B8 diff --git a/sfall/Modules/DebugEditor.cpp b/sfall/Modules/DebugEditor.cpp index cda17442..884de027 100644 --- a/sfall/Modules/DebugEditor.cpp +++ b/sfall/Modules/DebugEditor.cpp @@ -30,18 +30,20 @@ namespace sfall { -#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_EXIT = 254 +}; static const char* debugLog = "LOG"; static const char* debugGnw = "GNW"; @@ -55,6 +57,10 @@ struct sArray { long flag; }; +static void DEGameWinRedraw() { + fo::func::process_bk(); +} + static bool SetBlocking(SOCKET s, bool block) { DWORD d = !block; ioctlsocket(s, FIONBIO, &d); @@ -63,13 +69,12 @@ static bool SetBlocking(SOCKET s, bool block) { static bool InternalSend(SOCKET s, const void* _data, int size) { const char* data = (const char*)_data; int upto = 0; - int tmp; - DWORD d; while (upto < size) { - tmp = send(s, &data[upto], size - upto, 0); - if (tmp > 0) upto += tmp; - else { - d = WSAGetLastError(); + int tmp = send(s, &data[upto], size - upto, 0); + if (tmp > 0) { + upto += tmp; + } else { + DWORD d = WSAGetLastError(); if (d != WSAEWOULDBLOCK && d != WSAENOBUFS) return true; } } @@ -79,13 +84,12 @@ static bool InternalSend(SOCKET s, const void* _data, int size) { static bool InternalRecv(SOCKET s, void* _data, int size) { char* data = (char*)_data; int upto = 0; - int tmp; - DWORD d; while (upto < size) { - tmp = recv(s, &data[upto], size - upto, 0); - if (tmp > 0) upto += tmp; - else { - d = WSAGetLastError(); + int tmp = recv(s, &data[upto], size - upto, 0); + if (tmp > 0) { + upto += tmp; + } else { + DWORD d = WSAGetLastError(); if (d != WSAEWOULDBLOCK && d != WSAENOBUFS) return true; } } @@ -93,6 +97,8 @@ static bool InternalRecv(SOCKET s, void* _data, int size) { } static void RunEditorInternal(SOCKET &s) { + *(DWORD*)FO_VAR_script_engine_running = 0; + std::vector vec = std::vector(); for (int elv = 0; elv < 3; elv++) { for (int tile = 0; tile < 40000; tile++) { @@ -105,13 +111,12 @@ static void RunEditorInternal(SOCKET &s) { } } } - int numCritters = vec.size(); - int numGlobals = fo::var::num_game_global_vars; int numMapVars = fo::var::num_map_global_vars; int numSGlobals = GetNumGlobals(); int numArrays = script::GetNumArrays(); + InternalSend(s, &numGlobals, 4); InternalSend(s, &numMapVars, 4); InternalSend(s, &numSGlobals, 4); @@ -120,6 +125,7 @@ static void RunEditorInternal(SOCKET &s) { GlobalVar* sglobals = new GlobalVar[numSGlobals]; GetGlobals(sglobals); + sArray* arrays = new sArray[numArrays]; script::GetArrays((int*)arrays); @@ -138,30 +144,30 @@ static void RunEditorInternal(SOCKET &s) { if (code == CODE_EXIT) break; int id, val; switch (code) { - case 0: + case CODE_SET_GLOBAL: InternalRecv(s, &id, 4); InternalRecv(s, &val, 4); fo::var::game_global_vars[id] = val; break; - case 1: + case CODE_SET_MAPVAR: InternalRecv(s, &id, 4); InternalRecv(s, &val, 4); fo::var::map_global_vars[id] = val; break; - case 2: // Retrieve Critter + case CODE_GET_CRITTER: InternalRecv(s, &id, 4); InternalSend(s, vec[id], 0x84); break; - case 3: // Set Critter + case CODE_SET_CRITTER: InternalRecv(s, &id, 4); InternalRecv(s, vec[id], 0x84); break; - case 4: + case CODE_SET_SGLOBAL: InternalRecv(s, &id, 4); InternalRecv(s, &val, 4); sglobals[id].val = val; break; - case 9: // get array values + case CODE_GET_ARRAY: // get array values { InternalRecv(s, &id, 4); DWORD *types = new DWORD[arrays[id].size * 2]; // type, len @@ -178,22 +184,25 @@ static void RunEditorInternal(SOCKET &s) { delete[] types; } break; - case 10: // set array values + case CODE_SET_ARRAY: // set array values { - //InternalRecv(s, &id, 4); - //InternalRecv(s, &val, 4); - //char *data = new char[arrays[id].size * arrays[id * 3 + 2]]; - //InternalRecv(s, data, arrays[id].size * arrays[id * 3 + 2]); - //script::DESetArray(arrays[id].id, 0, data); - //delete[] data; + InternalRecv(s, &id, 4); + InternalRecv(s, &val, 4); // len data + char *data = new char[val]; + InternalRecv(s, data, val); + script::DESetArray(arrays[id].id, nullptr, data); + delete[] data; } break; } + DEGameWinRedraw(); } SetGlobals(sglobals); delete[] sglobals; delete[] arrays; + + *(DWORD*)FO_VAR_script_engine_running = 1; } void RunDebugEditor() { @@ -201,13 +210,13 @@ void RunDebugEditor() { SOCKET sock, client; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) return; - //create the socket + // create the socket sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { WSACleanup(); return; } - //bind the socket + // bind the socket sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr("127.0.0.1"); @@ -224,7 +233,7 @@ void RunDebugEditor() { return; } - //Start up the editor + // Start up the editor STARTUPINFO si; PROCESS_INFORMATION pi; @@ -242,7 +251,7 @@ void RunDebugEditor() { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); - //Connect to the editor + // Connect to the editor client = accept(sock, 0, 0); if (client == SOCKET_ERROR) { closesocket(sock); @@ -284,7 +293,7 @@ void DebugModePatch() { DWORD dbgMode = GetPrivateProfileIntA("Debugging", "DebugMode", 0, ::sfall::ddrawIni); if (dbgMode) { dlog("Applying debugmode patch.", DL_INIT); - //If the player is using an exe with the debug patch already applied, just skip this block without erroring + // If the player is using an exe with the debug patch already applied, just skip this block without erroring if (*((DWORD*)0x444A64) != 0x082327E8) { SafeWrite32(0x444A64, 0x082327E8); // call debug_register_env_ SafeWrite32(0x444A68, 0x0120E900); // jmp 0x444B8E diff --git a/sfall/Modules/Scripting/Arrays.cpp b/sfall/Modules/Scripting/Arrays.cpp index c8801f79..15f021c6 100644 --- a/sfall/Modules/Scripting/Arrays.cpp +++ b/sfall/Modules/Scripting/Arrays.cpp @@ -340,10 +340,24 @@ void DEGetArray(int id, DWORD* types, char* data) { } } -// those too are not really used yet in FalloutClient (AFAIK) -- phobos2077 -void DESetArray(int id, const DWORD* types, const void* data) { - //if (types) memcpy(arrays[id].types, types, arrays[id].len * 4); - //memcpy(arrays[id].data, data, arrays[id].len*arrays[id].datalen); +void DESetArray(int id, const DWORD* types, const char* data) { + int pos = 0; + for (size_t i = 0; i < arrays[id].val.size(); i++) { + auto& arVal = arrays[id].val[i]; + switch (arVal.type) { + case DataType::INT: + arVal.intVal = *(long*)(data + pos); + pos += 4; + break; + case DataType::FLOAT: + arVal.floatVal = *(float*)(data + pos); + pos += 4; + break; + case DataType::STR: + strcpy(arVal.strVal, data + pos); + pos += arVal.len; + } + } } /* diff --git a/sfall/Modules/Scripting/Arrays.h b/sfall/Modules/Scripting/Arrays.h index 3a745b85..bdd2918a 100644 --- a/sfall/Modules/Scripting/Arrays.h +++ b/sfall/Modules/Scripting/Arrays.h @@ -161,7 +161,7 @@ int GetNumArrays(); void GetArrays(int* arrays); void DEGetArray(int id, DWORD* types, char* data); -void DESetArray(int id, const DWORD* types, const void* data); +void DESetArray(int id, const DWORD* types, const char* data); // creates new normal (persistent) array. len == -1 specifies associative array (map) DWORD _stdcall CreateArray(int len, DWORD flags);