From 38fc3656be6a1441bdef52b9933205c86bee458c Mon Sep 17 00:00:00 2001 From: jeffman Date: Wed, 25 Mar 2015 13:35:12 -0400 Subject: [PATCH] Add string previewer --- ScriptTool/ScriptTool/Compiler.cs | 188 ++++++++++++++++-- ScriptTool/ScriptTool/ScriptTool.csproj | 3 + ScriptTool/ScriptTool/m2-widths-main.bin | Bin 0 -> 192 bytes ScriptTool/ScriptToolGui/MainForm.Designer.cs | 83 +++++--- ScriptTool/ScriptToolGui/MainForm.cs | 23 +++ ScriptTool/ScriptToolGui/ScriptToolGui.csproj | 3 + .../ScriptToolGui/StringPreviewer.Designer.cs | 27 ++- ScriptTool/ScriptToolGui/StringPreviewer.cs | 61 ++++++ ScriptTool/ScriptToolGui/StringPreviewer.resx | 120 +++++++++++ 9 files changed, 460 insertions(+), 48 deletions(-) create mode 100644 ScriptTool/ScriptTool/m2-widths-main.bin create mode 100644 ScriptTool/ScriptToolGui/StringPreviewer.resx diff --git a/ScriptTool/ScriptTool/Compiler.cs b/ScriptTool/ScriptTool/Compiler.cs index ec260cf..ce89f4c 100644 --- a/ScriptTool/ScriptTool/Compiler.cs +++ b/ScriptTool/ScriptTool/Compiler.cs @@ -9,10 +9,26 @@ namespace ScriptTool { public class Compiler : ICompiler { + private static int[] virtualWidths; + private static int[] renderWidths; + public IEnumerable ControlCodes { get; set; } public Dictionary AddressMap { get; set; } public Func ControlCodePredicate { get; set; } + static Compiler() + { + byte[] widths = File.ReadAllBytes("m2-widths-main.bin"); + virtualWidths = new int[widths.Length / 2]; + renderWidths = new int[widths.Length / 2]; + + for (int i = 0; i < widths.Length; i += 2) + { + virtualWidths[i / 2] = widths[i]; + renderWidths[i / 2] = widths[i + 1]; + } + } + public Compiler(IEnumerable controlCodes, Func controlCodePredicate) { @@ -81,7 +97,7 @@ namespace ScriptTool if (str[i] == '[') { if (str.IndexOf(']', i + 1) == -1) - throw new Exception("Opening bracket has no matching closing bracket"); + throw new Exception("Opening bracket has no matching closing bracket: position " + i); string[] codeStrings = str.Substring(i + 1, str.IndexOf(']', i + 1) - i - 1) .Split(' '); @@ -97,10 +113,10 @@ namespace ScriptTool if (codeString[0] == '_') { if (codeString[codeString.Length - 1] != '_') - throw new Exception("Reference has no closing underscore"); + throw new Exception("Reference has no closing underscore: position " + i); if (codeString.Length <= 2) - throw new Exception("Reference is empty"); + throw new Exception("Reference is empty: position " + i); if (!scanCodesOnly) referenceAddress += 4; @@ -123,19 +139,19 @@ namespace ScriptTool } else if (str[i] == ']') { - throw new Exception("Closing bracket has no matching opening bracket"); + throw new Exception("Closing bracket has no matching opening bracket: position " + i); } else if (str[i] == '^') { if (str.IndexOf('^', i + 1) == -1) - throw new Exception("Label has no matching closing caret"); + throw new Exception("Label has no matching closing caret: position " + i); string label = str.Substring(i + 1, str.IndexOf('^', i + 1) - i - 1); if (AddressMap.ContainsKey(label)) - throw new Exception("Label already defined"); + throw new Exception("Label already defined: position " + i); - if(!scanCodesOnly) + if (!scanCodesOnly) AddressMap.Add(label, referenceAddress); i = str.IndexOf('^', i + 1) + 1; @@ -169,7 +185,7 @@ namespace ScriptTool if (str[i] == '[') { if (str.IndexOf(']', i + 1) == -1) - throw new Exception("Opening bracket has no matching closing bracket"); + throw new Exception("Opening bracket has no matching closing bracket: position " + i); string[] codeStrings = str.Substring(i + 1, str.IndexOf(']', i + 1) - i - 1) .Split(' '); @@ -183,7 +199,7 @@ namespace ScriptTool for (int j = 0; j < codeStrings.Length; j++) { if (!IsHexByte(codeStrings[j])) - throw new Exception("Code string for unrecognized control code block must be a byte literal"); + throw new Exception("Code string for unrecognized control code block must be a byte literal: position " + i); byte value = byte.Parse(codeStrings[j], System.Globalization.NumberStyles.HexNumber); if (buffer != null) @@ -196,7 +212,7 @@ namespace ScriptTool { // Validate if (!code.IsValid(codeStrings)) - throw new Exception("Invalid control code"); + throw new Exception("Invalid control code: position " + i); // Parse code.Compile(codeStrings, buffer, ref referenceAddress, AddressMap); @@ -206,12 +222,12 @@ namespace ScriptTool } else if (str[i] == ']') { - throw new Exception("Closing bracket has no matching opening bracket"); + throw new Exception("Closing bracket has no matching opening bracket: position " + i); } else if (str[i] == '^') { if (str.IndexOf('^', i + 1) == -1) - throw new Exception("Label has no matching closing caret"); + throw new Exception("Label has no matching closing caret: position " + i); i = str.IndexOf('^', i + 1) + 1; } @@ -236,7 +252,8 @@ namespace ScriptTool int bytesWritten = buffer.Count - previousBufferSize; if (bytesWritten > padLength) - throw new Exception("Exceeded pad length"); + throw new Exception("Exceeded pad length: wrote " + bytesWritten + + " bytes, but the pad length is " + padLength + " bytes"); for (int i = bytesWritten; i < padLength; i++) { @@ -257,7 +274,7 @@ namespace ScriptTool if (str[i] == '[') { if (str.IndexOf(']', i + 1) == -1) - throw new Exception("Opening bracket has no matching closing bracket"); + throw new Exception("Opening bracket has no matching closing bracket: position " + i); sb.Append(str.Substring(i, str.IndexOf(']', i + 1) - i + 1)); @@ -265,12 +282,12 @@ namespace ScriptTool } else if (str[i] == ']') { - throw new Exception("Closing bracket has no matching opening bracket"); + throw new Exception("Closing bracket has no matching opening bracket: position " + i); } else if (str[i] == '^') { if (str.IndexOf('^', i + 1) == -1) - throw new Exception("Label has no matching closing caret"); + throw new Exception("Label has no matching closing caret: position " + i); sb.Append(str.Substring(i, str.IndexOf('^', i + 1) - i + 1)); @@ -284,5 +301,144 @@ namespace ScriptTool return sb.ToString(); } + + public IList FormatPreviewM12(string str, out IList widths, IDictionary charLookup) + { + var sb = new StringBuilder(); + widths = new List(); + int currentWidth = 0; + + var strings = new List(); + + for (int i = 0; i < str.Length; ) + { + if (str[i] == '[') + { + if (str.IndexOf(']', i + 1) == -1) + throw new Exception("Opening bracket has no matching closing bracket: position " + i); + + string[] codeStrings = str.Substring(i + 1, str.IndexOf(']', i + 1) - i - 1) + .Split(' '); + + M12ControlCode code = (M12ControlCode)ControlCodes.FirstOrDefault(c => c.IsMatch(codeStrings)); + + foreach (var codeString in codeStrings) + { + if (codeString[0] == '_') + { + if (codeString[codeString.Length - 1] != '_') + throw new Exception("Reference has no closing underscore: position " + i); + + if (codeString.Length <= 2) + throw new Exception("Reference is empty: position " + i); + } + else if (!IsHexByte(codeString)) + { + throw new Exception(String.Format( + "Encountered invalid code string at position {0}: {1}", i, codeString)); + } + } + + i = str.IndexOf(']', i + 1) + 1; + + + switch (code.Identifier) + { + case 0xC: + case 0xD: + case 0xE: + case 0xF: + case 0x10: + case 0x11: + case 0x12: + case 0x15: + case 0x1A: + case 0x2D: + case 0x9F: + case 0xAD: + // Name/item code + sb.Append("[NAME]"); + currentWidth += 60; + break; + + case 0x1: + case 0x2: + // Line break + strings.Add(sb.ToString()); + sb.Clear(); + widths.Add(currentWidth); + currentWidth = 0; + break; + + case 0x20: + sb.Append("[SMAAASH]"); + currentWidth += 72; + break; + + case 0x21: + sb.Append("[YOU WIN]"); + currentWidth += 72; + break; + + case 0x23: + case 0x63: + case 0x98: + case 0xB7: + sb.Append("[MONEY]"); + currentWidth += 36; + break; + + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + sb.Append("[STAT]"); + currentWidth += 18; + break; + + case 0x1E: + case 0x1F: + sb.Append("_"); + currentWidth += 10; + break; + } + + } + else if (str[i] == ']') + { + throw new Exception("Closing bracket has no matching opening bracket: position " + i); + } + else if (str[i] == '^') + { + if (str.IndexOf('^', i + 1) == -1) + throw new Exception("Label has no matching closing caret: position " + i); + + string label = str.Substring(i + 1, str.IndexOf('^', i + 1) - i - 1); + + i = str.IndexOf('^', i + 1) + 1; + } + else + { + if (!(str[i] == '\r') && !(str[i] == '\n')) + { + sb.Append(str[i]); + currentWidth += virtualWidths[GetByte(str[i], charLookup) - 0x50]; + } + i++; + } + } + + if (sb.Length > 0) + { + strings.Add(sb.ToString()); + widths.Add(currentWidth); + } + + return strings; + } } } diff --git a/ScriptTool/ScriptTool/ScriptTool.csproj b/ScriptTool/ScriptTool/ScriptTool.csproj index 2defe99..5259d7b 100644 --- a/ScriptTool/ScriptTool/ScriptTool.csproj +++ b/ScriptTool/ScriptTool/ScriptTool.csproj @@ -86,6 +86,9 @@ Always + + Always + diff --git a/ScriptTool/ScriptTool/m2-widths-main.bin b/ScriptTool/ScriptTool/m2-widths-main.bin new file mode 100644 index 0000000000000000000000000000000000000000..7bdf7c4171e1ae24a118934ff450e7978213a7a1 GIT binary patch literal 192 zcmY+80Sdq{2m@C&(e3{aUP2kHgjSo2(!4S%Gl=J&ac>bB7K)(HpResources.resx True + + StringPreviewer.cs + SettingsSingleFileGenerator diff --git a/ScriptTool/ScriptToolGui/StringPreviewer.Designer.cs b/ScriptTool/ScriptToolGui/StringPreviewer.Designer.cs index dcf9a70..3fd68f8 100644 --- a/ScriptTool/ScriptToolGui/StringPreviewer.Designer.cs +++ b/ScriptTool/ScriptToolGui/StringPreviewer.Designer.cs @@ -28,10 +28,35 @@ /// private void InitializeComponent() { - components = new System.ComponentModel.Container(); + this.stringPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.SuspendLayout(); + // + // stringPanel + // + this.stringPanel.AutoSize = true; + this.stringPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.stringPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.stringPanel.Location = new System.Drawing.Point(0, 0); + this.stringPanel.Name = "stringPanel"; + this.stringPanel.Size = new System.Drawing.Size(0, 0); + this.stringPanel.TabIndex = 0; + // + // StringPreviewer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScroll = true; + this.Controls.Add(this.stringPanel); + this.Name = "StringPreviewer"; + this.Size = new System.Drawing.Size(324, 105); + this.ResumeLayout(false); + this.PerformLayout(); + } #endregion + + private System.Windows.Forms.FlowLayoutPanel stringPanel; + } } diff --git a/ScriptTool/ScriptToolGui/StringPreviewer.cs b/ScriptTool/ScriptToolGui/StringPreviewer.cs index aafd954..b71e8cd 100644 --- a/ScriptTool/ScriptToolGui/StringPreviewer.cs +++ b/ScriptTool/ScriptToolGui/StringPreviewer.cs @@ -7,14 +7,75 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using ScriptTool; namespace ScriptToolGui { public partial class StringPreviewer : UserControl { + public Compiler M12Compiler { get; set; } + public IDictionary CharLookup { get; set; } + + public int MaxWidth { get; set; } + + private string text; + public string DisplayedString + { + get + { + return text; + } + set + { + text = value; + Redraw(); + } + } + public StringPreviewer() { InitializeComponent(); } + + private void Redraw() + { + stringPanel.Controls.Clear(); + + if (M12Compiler == null || CharLookup == null || text == null) + { + return; + } + + try + { + IList widths; + IList parsed = M12Compiler.FormatPreviewM12(text, out widths, CharLookup); + + for (int i = 0; i < parsed.Count; i++) + { + var label = new Label(); + label.AutoSize = true; + label.Text = parsed[i] + "(" + widths[i] + ")"; + + if (widths[i] <= MaxWidth) + label.ForeColor = Color.Green; + else + label.ForeColor = Color.Red; + + stringPanel.Controls.Add(label); + } + } + catch (Exception e) + { + stringPanel.Controls.Clear(); + + var errLabel = new Label(); + errLabel.AutoSize = true; + errLabel.Font = new Font(errLabel.Font, FontStyle.Bold); + errLabel.Text = "Error: " + e.Message; + + stringPanel.Controls.Add(errLabel); + } + } } } diff --git a/ScriptTool/ScriptToolGui/StringPreviewer.resx b/ScriptTool/ScriptToolGui/StringPreviewer.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/ScriptTool/ScriptToolGui/StringPreviewer.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file