diff --git a/DS_Map/Extensions.cs b/DS_Map/Extensions.cs index 170d59f..a38f50f 100644 --- a/DS_Map/Extensions.cs +++ b/DS_Map/Extensions.cs @@ -12,6 +12,11 @@ namespace DSPRE { public static bool ContainsNumber(this string str) { return str.IndexOfNumber() > 0; } + public static T[] SubArray(this T[] array, int offset, int length) { + T[] result = new T[length]; + Array.Copy(array, offset, result, 0, length); + return result; + } public static Dictionary Reverse (this Dictionary source) { var dictionary = new Dictionary(StringComparer.InvariantCultureIgnoreCase); foreach (var entry in source) { @@ -41,6 +46,18 @@ namespace DSPRE { Console.WriteLine("Fadeout done"); } + public static byte[] ToByteArrayChooseSize(this int num, byte size) { + switch (size) { + case 1: + return new byte[] { checked((byte)num) }; + case 2: + return BitConverter.GetBytes(checked((ushort)num)); + case 4: + return BitConverter.GetBytes(num); + } + throw new InvalidOperationException(); + } + //public static Dictionary Reverse(this IDictionary source) { // var dictionary = new Dictionary(); // foreach (var entry in source) { diff --git a/DS_Map/Main Window.cs b/DS_Map/Main Window.cs index fad2f60..1096150 100644 --- a/DS_Map/Main Window.cs +++ b/DS_Map/Main Window.cs @@ -6233,7 +6233,7 @@ namespace DSPRE { currentScriptFile = userEdited; ScriptEditorSetClean(); } else { - MessageBox.Show("This " + typeof(ScriptFile).Name + " couldn't be saved.", "Can't save", MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show("This " + typeof(ScriptFile).Name + " couldn't be saved, due to a processing error.", "Can't save", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } private void clearCurrentLevelScriptButton_Click(object sender, EventArgs e) { @@ -6246,7 +6246,7 @@ namespace DSPRE { private void importScriptFileButton_Click(object sender, EventArgs e) { /* Prompt user to select .scr file */ OpenFileDialog of = new OpenFileDialog(); - of.Filter = "Script File (*.scr)|*.scr"; + of.Filter = "Script File (*.scr, *.bin)|*.scr, *.bin"; if (of.ShowDialog(this) != DialogResult.OK) return; diff --git a/DS_Map/ROMFiles/ScriptCommand.cs b/DS_Map/ROMFiles/ScriptCommand.cs index 4788ecd..02e433a 100644 --- a/DS_Map/ROMFiles/ScriptCommand.cs +++ b/DS_Map/ROMFiles/ScriptCommand.cs @@ -46,8 +46,9 @@ namespace DSPRE.ROMFiles { this.id = id; this.cmdParams = parametersList; - if (!RomInfo.ScriptCommandNamesDict.TryGetValue(id, out name)) + if (!RomInfo.ScriptCommandNamesDict.TryGetValue(id, out name)) { name = id.ToString("X4"); + } switch (id) { case 0x16: // Jump @@ -105,7 +106,6 @@ namespace DSPRE.ROMFiles { string[] nameParts = wholeLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); // Separate command code from parameters /* Get command id, which is always first in the description */ - ushort cmdID; if (RomInfo.ScriptCommandNamesReverseDict.TryGetValue(nameParts[0].ToLower(), out cmdID)) { id = cmdID; @@ -132,52 +132,94 @@ namespace DSPRE.ROMFiles { byte[] parametersSizeArr = RomInfo.ScriptCommandParametersDict[(ushort)id]; int paramLength = 0; - if (parametersSizeArr.Length == 1 && parametersSizeArr.First() == 0) { + int paramsProcessed = 0; + + if (parametersSizeArr.First() == 0xFF) { + int firstParamValue = int.Parse(GetStringWithoutSpecialCharacters(nameParts[1]), GetNumberStyleFromString(nameParts[1])); + byte firstParamSize = parametersSizeArr[1]; + + cmdParams.Add(firstParamValue.ToByteArrayChooseSize(firstParamSize)); + paramsProcessed++; + + int i = 2; + int optionsCount = 0; + + bool found = false; + while (i < parametersSizeArr.Length) { + paramLength = parametersSizeArr[i + 1]; + + if (parametersSizeArr[i] == firstParamValue) { + //Firstly, build subarray of parameter sizes, starting from the chosen option [firstParamValue] + //FOR EXAMPLE: CMD 0x235 and firstParamValue = 5 + + // { 0xFF, 2, + // 0, 1, 2, + // 1, 3, 2, 2, 2, + // 2, 0, + // 3, 3, 2, 2, 2, + // 4, 2, 2, 2, + // 5, 3, (2, 2, 2) => this will be the parameters subarray + // 6, 1, 2 + // }, + byte[] subParametersSize = parametersSizeArr.SubArray(i + 2, paramLength++); + + //Create a slightly bigger temp array + byte[] temp = new byte[1 + subParametersSize.Length]; + + //Store the size of the firstParamValue there + temp[0] = firstParamSize; + + //Then copy the whole subarray of parameter sizes + Array.Copy(subParametersSize, 0, temp, 1, temp.Length-1); + + //Replace the original parametersSizeArr with the new array + parametersSizeArr = temp; + found = true; + break; + } + i += 2 + paramLength; + optionsCount++; + } + if (!found) { + MessageBox.Show("Command " + '"' + nameParts[0] + '"' + " at line " + lineNumber + " is a special Script command." + Environment.NewLine + + "The value of the first parameter must be a number in the range [0 - " + optionsCount + "].", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + id = null; + return; + } + } else if (parametersSizeArr.Length == 1 && parametersSizeArr.First() == 0) { paramLength = 0; - } else { + } else { paramLength = parametersSizeArr.Length; } if (nameParts.Length - 1 == paramLength) { - for (int i = 0; i < paramLength; i++) { + for (int i = paramsProcessed; i < paramLength; i++) { Console.WriteLine("Parameter #" + i.ToString() + ": " + nameParts[i + 1]); + if (RomInfo.ScriptComparisonOperatorsReverseDict.TryGetValue(nameParts[i + 1].ToLower(), out cmdID)) { cmdParams.Add(new byte[] { (byte)cmdID }); } else { //Not a comparison - int indexOfSpecialCharacter = nameParts[i + 1].IndexOfAny(new char[] { 'x', 'X', '#', '.' }); - - /* If number is preceded by 0x parse it as hex, otherwise as decimal */ - NumberStyles style; - if (nameParts[i + 1].StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) { - style = NumberStyles.HexNumber; - } else { - style = NumberStyles.Integer; + /* Convert strings of parameters to the correct datatypes */ + NumberStyles style = GetNumberStyleFromString(nameParts[i + 1]); + nameParts[i + 1] = GetStringWithoutSpecialCharacters(nameParts[i + 1]); + + int result = 0; + try { + result = int.Parse(nameParts[i + 1], style); + } catch { + try { + result = ScriptDatabase.specialOverworlds.First(x => x.Value.Equals(nameParts[i + 1])).Key; + } catch (InvalidOperationException) { + MessageBox.Show("Argument " + '"' + nameParts[i + 1] + '"' + " at line " + lineNumber + " is not " + "a valid " + "Overworld number or identifier.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + id = null; + } catch (FormatException) { + MessageBox.Show("Argument " + '"' + nameParts[i + 1] + '"' + " at line " + lineNumber + " is not " + "a valid " + style, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + id = null; + } } - nameParts[i + 1] = nameParts[i + 1].Substring(indexOfSpecialCharacter + 1); - /* Convert strings of parameters to the correct datatypes */ try { - switch (parametersSizeArr[i]) { - case 1: - cmdParams.Add(new byte[] { Byte.Parse(nameParts[i + 1], style) }); - break; - case 2: - ushort result; - if (!ushort.TryParse(nameParts[i + 1], style, new CultureInfo("en-US"), result: out result)) { - result = ScriptDatabase.specialOverworlds.First(x => x.Value.Equals(nameParts[i + 1])).Key; - } - cmdParams.Add(BitConverter.GetBytes(result)); - break; - case 4: - cmdParams.Add(BitConverter.GetBytes(Int32.Parse(nameParts[i + 1], style))); - break; - } - } catch (InvalidOperationException) { - MessageBox.Show("Argument " + '"' + nameParts[i + 1] + '"' + " at line " + lineNumber + " is not " + "a valid " + "Overworld number or identifier.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - id = null; - } catch (FormatException) { - MessageBox.Show("Argument " + '"' + nameParts[i + 1] + '"' + " at line " + lineNumber + " is not " + "a valid " + style, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - id = null; + cmdParams.Add(result.ToByteArrayChooseSize(parametersSizeArr[i])); } catch (OverflowException) { MessageBox.Show("Argument " + '"' + nameParts[i + 1] + '"' + " at line " + lineNumber + " is not " + "in the range [" + 0 + ", " + (Math.Pow(2, 8 * parametersSizeArr[i]) - 1) + "].", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); id = null; @@ -185,7 +227,7 @@ namespace DSPRE.ROMFiles { } } } else { - MessageBox.Show("Wrong number of parameters for command " + nameParts[0] + " at line " + lineNumber + "." + Environment.NewLine + + MessageBox.Show("Wrong number of parameters for command " + '"' + nameParts[0] + '"' + " at line " + lineNumber + "." + Environment.NewLine + "Received: " + (nameParts.Length - 1) + Environment.NewLine + "Expected: " + paramLength, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); id = null; } @@ -193,6 +235,29 @@ namespace DSPRE.ROMFiles { #endregion #region Utilities + private string GetStringWithoutSpecialCharacters(string s) { + int indexOfSpecialCharacter = s.IndexOfAny(new char[] { 'x', 'X', '#', '.' }); + return s.Substring(indexOfSpecialCharacter + 1); + } + + public NumberStyles GetNumberStyleFromString(string s) { + if (s.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) { + foreach (char c in s.Substring(2)) { + if (!Char.IsDigit(c) && Char.ToUpper(c) > 'F') { + return NumberStyles.None; + } + } + return NumberStyles.HexNumber; + } else { + foreach (char c in s) { + if (!Char.IsDigit(c)) { + return NumberStyles.None; + } + } + return NumberStyles.Integer; + } + } + public override string ToString() { return name + " (" + ((ushort)id).ToString("X") + ")"; } diff --git a/DS_Map/Resources/ScriptDatabase.cs b/DS_Map/Resources/ScriptDatabase.cs index d8938fc..7727047 100644 --- a/DS_Map/Resources/ScriptDatabase.cs +++ b/DS_Map/Resources/ScriptDatabase.cs @@ -1097,9 +1097,25 @@ namespace DSPRE.Resources { [0x01CC] = new byte[1] { 0 }, [0x01CD] = new byte[] { 2, 2, 2, 2, 2 }, [0x01CE] = new byte[1] { 0 }, - [0x01CF] = new byte[] { }, ///////////////// - [0x01D0] = new byte[] { }, ///////////////// - [0x01D1] = new byte[] { }, ///////////////// + + [0x01CF] = new byte[] { 0xFF, 1, //0xFF signals that this scrcmd takes a variable num of parameters, 1 is the size of the 1st par + 0, 0, //if 1st par is 0, read 0 parameters + 1, 0, //if 1st par is 1, read 0 parameters + 2, 1, 2 //if 1st par is 2, read 1 parameter of size = 2 bytes + }, + + [0x01D0] = new byte[] { 0xFF, 1, //0xFF signals that this scrcmd takes a variable num of parameters, 1 is the size of the 1st par + 0, 0, //if 1st par is 0, read 0 parameters + 1, 0, //if 1st par is 1, read 0 parameters + 2, 1, 2 //if 1st par is 2, read 1 parameter of size = 2 bytes + }, + + [0x01D1] = new byte[] { 0xFF, 1, //0xFF signals that this scrcmd takes a variable num of parameters, 1 is the size of the 1st par + 0, 0, //if 1st par is 0, read 0 parameters + 1, 0, //if 1st par is 1, read 0 parameters + 2, 1, 2 //if 1st par is 2, read 1 parameter of size = 2 bytes + }, + [0x01D2] = new byte[] { 2, 2 }, [0x01D3] = new byte[] { 2, 2, 2 }, [0x01D4] = new byte[1] { 0 }, @@ -1175,7 +1191,14 @@ namespace DSPRE.Resources { [0x021A] = new byte[] { 2 }, [0x021B] = new byte[1] { 0 }, [0x021C] = new byte[] { 1 }, - [0x021D] = new byte[] { }, /////////////////// + [0x021D] = new byte[] { 0xFF, 2, //0xFF = Variable number of parameters, 2 = size of first parameter + 0, 2, 2, 2, //if value is 0, read 2 parameters... first one takes up 2 bytes, second par takes up 2 bytes + 1, 2, 2, 2, //if value is 1, read 2 parameters... first one takes up 2 bytes, second par takes up 2 bytes + 2, 2, 2, 2, //if value is 2, read 2 parameters... first one takes up 2 bytes, second par takes up 2 bytes + 3, 2, 2, 2, //if value is 3, read 2 parameters... first one takes up 2 bytes, second par takes up 2 bytes + 4, 1, 2, //if value is 4, read 1 parameter... which takes up 2 bytes + 5, 1, 2, //if value is 5, read 1 parameter... which takes up 2 bytes + 6, 0}, //if value is 6, don't read anything [0x021E] = new byte[1] { 0 }, [0x021F] = new byte[] { 2, 2 }, [0x0220] = new byte[1] { 0 }, @@ -1199,16 +1222,33 @@ namespace DSPRE.Resources { [0x0232] = new byte[] { 1, 2 }, [0x0233] = new byte[] { 2, 2 }, [0x0234] = new byte[] { 2 }, - [0x0235] = new byte[] { }, /////////////////// + [0x0235] = new byte[] { 0xFF, 2, //0xFF = Variable number of parameters, 2 = size of first parameter + 0, 1, 2, //if value is 0, read 1 parameter... which takes up 2 bytes + 1, 3, 2, 2, 2, //if value is 1, read 3 parameters... each one takes up 2 bytes + 2, 0, //if value is 2, don't read anything + 3, 3, 2, 2, 2, //if value is 3, read 3 parameters... each one takes up 2 bytes + 4, 2, 2, 2, //if value is 4, read 2 parameters... each one takes up 2 bytes + 5, 3, 2, 2, 2, //if value is 5, read 3 parameters... each one takes up 2 bytes + 6, 1, 2}, //if value is 6, read 1 parameter... which takes up 2 bytes [0x0236] = new byte[] { 2 }, - [0x0237] = new byte[] { 2, 2, 2, 2 }, + [0x0237] = new byte[] { 2, 2, 2, 2 }, //u16: 0; Flex: ???; Var: Variable; Var: //u16: 1; Flex: ???; Flex: ???; Flex: ??? [0x0238] = new byte[] { 2, 2 }, [0x0239] = new byte[] { 2 }, [0x023A] = new byte[] { 2, 2, 2 }, [0x023B] = new byte[] { 2 }, [0x023C] = new byte[] { 2, 2 }, [0x023D] = new byte[] { 1, 1, 2, 2, 2 }, - [0x023E] = new byte[] { }, ///////////////// + [0x023E] = new byte[] { 0xFF, 2, //0xFF = Variable number of parameters, 2 = size of first parameter + 0, 0, //if value is 0, don't read anything + 1, 1, 2, //if value is 1, read 1 parameter... which takes up 2 bytes + 2, 1, 2, //if value is 2, read 1 parameter... which takes up 2 bytes + 3, 1, 2, //if value is 3, read 1 parameter... which takes up 2 bytes + 4, 0, //if value is 4, don't read anything + 5, 2, 2, 2, //if value is 5, read 2 parameters... each one takes up 2 bytes + 6, 2, 2, 2, //if value is 6, read 2 parameters... each one takes up 2 bytes + 7, 0, //if value is 7, don't read anything + 8, 0 //if value is 8, don't read anything + }, [0x023F] = new byte[1] { 0 }, [0x0240] = new byte[1] { 0 }, [0x0241] = new byte[1] { 0 }, @@ -2380,9 +2420,25 @@ namespace DSPRE.Resources { [0x018D] = new byte[] { 2, 2 }, [0x018E] = new byte[] { 2, 2, 2 }, [0x018F] = new byte[] { 1, 2, 2 }, - [0x0190] = new byte[] { 1 }, - [0x0191] = new byte[1] { 0 }, - [0x0192] = new byte[1] { 0 }, + + [0x0190] = new byte[] { 0xFF, 1, //0xFF signals that this scrcmd takes a variable num of parameters, 1 is the size of the 1st par + 0, 0, //if 1st par is 0, read 0 parameters + 1, 0, //if 1st par is 1, read 0 parameters + 2, 1, 2 //if 1st par is 2, read 1 parameter of size = 2 bytes + }, + + [0x0191] = new byte[] { 0xFF, 1, //0xFF signals that this scrcmd takes a variable num of parameters, 1 is the size of the 1st par + 0, 0, //if 1st par is 0, read 0 parameters + 1, 0, //if 1st par is 1, read 0 parameters + 2, 1, 2 //if 1st par is 2, read 1 parameter of size = 2 bytes + }, + + [0x0192] = new byte[] { 0xFF, 1, //0xFF signals that this scrcmd takes a variable num of parameters, 1 is the size of the 1st par + 0, 0, //if 1st par is 0, read 0 parameters + 1, 0, //if 1st par is 1, read 0 parameters + 2, 1, 2 //if 1st par is 2, read 1 parameter of size = 2 bytes + }, + [0x0193] = new byte[] { 2, 2 }, [0x0194] = new byte[] { 2, 2, 2 }, [0x0195] = new byte[] { 2, 2 }, @@ -2445,7 +2501,16 @@ namespace DSPRE.Resources { [0x01CE] = new byte[] { 2 }, [0x01CF] = new byte[1] { 0 }, [0x01D0] = new byte[] { 1 }, - [0x01D1] = new byte[] { 2, 2, 2 }, + [0x01D1] = new byte[] { 0xFF, 2, //0xFF = Variable number of parameters, 2 = size of first parameter + 0, 2, 2, 2, //if value is 0, read 2 parameters... first one takes up 2 bytes, second par takes up 2 bytes + 1, 2, 2, 2, //if value is 1, read 2 parameters... first one takes up 2 bytes, second par takes up 2 bytes + 2, 2, 2, 2, //if value is 2, read 2 parameters... first one takes up 2 bytes, second par takes up 2 bytes + 3, 2, 2, 2, //if value is 3, read 2 parameters... first one takes up 2 bytes, second par takes up 2 bytes + 4, 1, 2, //if value is 4, read 1 parameter... which takes up 2 bytes + 5, 1, 2, //if value is 5, read 1 parameter... which takes up 2 bytes + 6, 0, //if value is 6, don't read anything + 7, 1, 2, //if value is 7, read 1 parameter... which takes up 2 bytes + }, [0x01D2] = new byte[] { 2, 2 }, [0x01D3] = new byte[] { 2 }, [0x01D4] = new byte[] { 2, 2 }, @@ -2469,7 +2534,17 @@ namespace DSPRE.Resources { [0x01E6] = new byte[1] { 0 }, [0x01E7] = new byte[] { 2 }, [0x01E8] = new byte[] { 2, 2 }, - [0x01E9] = new byte[] { 2 }, + [0x023E] = new byte[] { 0xFF, 2, //0xFF = Variable number of parameters, 2 = size of first parameter + 0, 0, //if value is 0, don't read anything + 1, 1, 2, //if value is 1, read 1 parameter... which takes up 2 bytes + 2, 1, 2, //if value is 2, read 1 parameter... which takes up 2 bytes + 3, 1, 2, //if value is 3, read 1 parameter... which takes up 2 bytes + 4, 0, //if value is 4, don't read anything + 5, 2, 2, 2, //if value is 5, read 2 parameters... each one takes up 2 bytes + 6, 2, 2, 2, //if value is 6, read 2 parameters... each one takes up 2 bytes + 7, 0, //if value is 7, don't read anything + 8, 0 //if value is 8, don't read anything + }, [0x01EA] = new byte[] { 2 }, [0x01EB] = new byte[] { 2 }, [0x01EC] = new byte[] { 2, 2, 2 },