Overhaul EB compiler and decompiler

This commit is contained in:
jeffman 2015-03-22 19:55:34 -04:00
parent 5dd4cc9f2a
commit 1802ce35d3
26 changed files with 2806 additions and 811 deletions

View File

@ -7,72 +7,75 @@ using System.IO;
namespace ScriptTool
{
public class M12Compiler : ICompiler
public class Compiler : ICompiler
{
private static IEnumerable<M12ControlCode> controlCodes;
private static string[] charLookup;
private const string hexChars = "0123456789ABCDEFabcdef";
private const string ebCharLookup = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZØØØØØ`abcdefghijklmnopqrstuvwxyz{|}~\\";
public IEnumerable<IControlCode> ControlCodes { get; set; }
public Dictionary<string, int> AddressMap { get; set; }
public Func<byte[], int, bool> ControlCodePredicate { get; set; }
static M12Compiler()
public Compiler(IEnumerable<IControlCode> controlCodes,
Func<byte[], int, bool> controlCodePredicate)
{
controlCodes = M12ControlCode.Codes;
charLookup = File.ReadAllLines("m12-text-table.txt");
}
ControlCodes = controlCodes;
ControlCodePredicate = controlCodePredicate;
public M12Compiler()
{
AddressMap = new Dictionary<string, int>();
}
public static bool IsHexByte(string str)
{
if (str == null || str.Length > 2)
try
{
Convert.ToByte(str, 16);
return true;
}
catch
{
return false;
}
for (int i = 0; i < str.Length; i++)
{
if (hexChars.IndexOf(str[i]) == -1)
{
return false;
}
}
return true;
}
public static bool IsValidChar(char c)
private byte GetByte(char c, IDictionary<byte, string> charLookup)
{
if (!ebCharLookup.Contains(c))
{
return false;
}
if (c == 'Ø')
{
return false;
}
return true;
return charLookup.First(kv => kv.Value[0] == c).Key; // lazy
}
public static byte GetByte(char c)
public void ScanString(string str, ref int referenceAddress, IDictionary<byte, string> charLookup, bool scanCodesOnly)
{
return (byte)(ebCharLookup.IndexOf(c) + 0x50);
ISet<IControlCode> codes;
IList<string> references;
ScanString(str, ref referenceAddress, charLookup, scanCodesOnly, out references, out codes);
}
public IList<string> ScanString(string str, bool scanCodesOnly)
public void ScanString(string str, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out IList<string> references)
{
int temp = 0;
return ScanString(str, ref temp, scanCodesOnly);
ISet<IControlCode> codes;
ScanString(str, ref temp, charLookup, scanCodesOnly, out references, out codes);
}
public IList<string> ScanString(string str, ref int referenceAddress, bool scanCodesOnly)
public void ScanString(string str, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out ISet<IControlCode> codes)
{
var references = new List<string>();
int temp = 0;
IList<string> references;
ScanString(str, ref temp, charLookup, scanCodesOnly, out references, out codes);
}
public void ScanString(string str, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out IList<string> references, out ISet<IControlCode> controlCodes)
{
int temp = 0;
ScanString(str, ref temp, charLookup, scanCodesOnly, out references, out controlCodes);
}
public void ScanString(string str, ref int referenceAddress, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out IList<string> references, out ISet<IControlCode> controlCodes)
{
references = new List<string>();
controlCodes = new HashSet<IControlCode>();
for (int i = 0; i < str.Length; )
{
if (str[i] == '[')
@ -83,6 +86,12 @@ namespace ScriptTool
string[] codeStrings = str.Substring(i + 1, str.IndexOf(']', i + 1) - i - 1)
.Split(' ');
IControlCode code = ControlCodes.FirstOrDefault(c => c.IsMatch(codeStrings));
if (!controlCodes.Contains(code))
{
controlCodes.Add(code);
}
foreach (var codeString in codeStrings)
{
if (codeString[0] == '_')
@ -137,25 +146,21 @@ namespace ScriptTool
{
if (!scanCodesOnly)
{
if (!IsValidChar(str[i]))
throw new Exception("Invalid character: " + str[i]);
GetByte(str[i], charLookup); // just check if it's valid
referenceAddress++;
}
}
i++;
}
}
return references;
}
public void CompileString(string str, IList<byte> buffer, ref int referenceAddress)
public void CompileString(string str, IList<byte> buffer, ref int referenceAddress, IDictionary<byte, string> charLookup)
{
CompileString(str, buffer, ref referenceAddress, -1);
CompileString(str, buffer, ref referenceAddress, charLookup, -1);
}
public void CompileString(string str, IList<byte> buffer, ref int referenceAddress, int padLength)
public void CompileString(string str, IList<byte> buffer, ref int referenceAddress, IDictionary<byte, string> charLookup, int padLength)
{
int previousBufferSize = buffer.Count;
@ -170,7 +175,7 @@ namespace ScriptTool
.Split(' ');
// Match the code
M12ControlCode code = controlCodes.FirstOrDefault(c => c.IsMatch(codeStrings));
IControlCode code = ControlCodes.FirstOrDefault(c => c.IsMatch(codeStrings));
if (code == null)
{
@ -194,44 +199,7 @@ namespace ScriptTool
throw new Exception("Invalid control code");
// Parse
foreach (var codeString in codeStrings)
{
if (codeString[0] == '_')
{
if (codeString[codeString.Length - 1] != '_')
throw new Exception("Reference has no closing underscore");
if (codeString.Length <= 2)
throw new Exception("Reference is empty");
string label = codeString.Substring(1, codeString.Length - 2);
int pointer = AddressMap[label];
if (!code.AbsoluteAddressing)
{
pointer -= referenceAddress;
}
else
{
pointer |= 0x8000000;
}
if (buffer != null)
buffer.AddInt(pointer);
referenceAddress += 4;
}
else if (IsHexByte(codeString))
{
byte value = byte.Parse(codeString, System.Globalization.NumberStyles.HexNumber);
buffer.Add(value);
referenceAddress++;
}
else
{
throw new Exception(String.Format(
"Encountered invalid code string at position {0}: {1}", i, codeString));
}
}
code.Compile(codeStrings, buffer, ref referenceAddress, AddressMap);
}
i = str.IndexOf(']', i + 1) + 1;
@ -251,12 +219,11 @@ namespace ScriptTool
{
if (!(str[i] == '\r') && !(str[i] == '\n'))
{
if (!IsValidChar(str[i]))
throw new Exception("Invalid character: " + str[i]);
byte value = GetByte(str[i], charLookup);
byte value = GetByte(str[i]);
if (buffer != null)
buffer.Add(value);
referenceAddress++;
}
i++;
@ -267,6 +234,7 @@ namespace ScriptTool
if (padLength != -1)
{
int bytesWritten = buffer.Count - previousBufferSize;
if (bytesWritten > padLength)
throw new Exception("Exceeded pad length");
@ -274,6 +242,7 @@ namespace ScriptTool
{
if (buffer != null)
buffer.Add(0);
referenceAddress++;
}
}

View File

@ -7,21 +7,20 @@ using System.IO;
namespace ScriptTool
{
class M12Decompiler : IDecompiler
class Decompiler : IDecompiler
{
private static IEnumerable<IControlCode> controlCodes;
private static string[] charLookup;
public IEnumerable<IControlCode> ControlCodes { get; set; }
public IDictionary<byte, string> CharLookup { get; set; }
public LabelMap LabelMap { get; set; }
public Func<byte[], int, bool> ControlCodePredicate { get; set; }
static M12Decompiler()
public Decompiler(IEnumerable<IControlCode> controlCodes, IDictionary<byte, string> charLookup,
Func<byte[], int, bool> controlCodePredicate)
{
controlCodes = M12ControlCode.Codes;
charLookup = File.ReadAllLines("m12-text-table.txt");
}
ControlCodes = controlCodes;
CharLookup = charLookup;
ControlCodePredicate = controlCodePredicate;
public M12Decompiler()
{
LabelMap = new LabelMap();
}
@ -33,9 +32,9 @@ namespace ScriptTool
int address = startAddress;
while (address < endAddress)
{
if (rom[address + 1] == 0xFF)
if (ControlCodePredicate(rom, address))
{
IControlCode code = controlCodes.FirstOrDefault(c => c.IsMatch(rom, address));
IControlCode code = ControlCodes.FirstOrDefault(c => c.IsMatch(rom, address));
if (code == null)
throw new Exception("Control code not found");
@ -82,21 +81,29 @@ namespace ScriptTool
builder.Append('^');
}
if (rom[address + 1] == 0xFF)
if (ControlCodePredicate(rom, address))
{
IControlCode code = (M12ControlCode)controlCodes.FirstOrDefault(c => c.IsMatch(rom, address));
IControlCode code = ControlCodes.FirstOrDefault(c => c.IsMatch(rom, address));
if (code == null)
throw new Exception("Control code not found");
IList<CodeString> codeStrings = code.GetCodeStrings(rom, address);
var filtered = codeStrings.Select(cs => FilterCodeString(cs)).ToArray();
builder.Append(String.Format("[{0}]", String.Join(" ", filtered)));
if (newLines && code.IsEnd)
// Check if it's compressed text
if (code.IsCompressedString)
{
builder.AppendLine();
builder.Append(code.GetCompressedString(rom, address));
}
else
{
IList<CodeString> codeStrings = code.GetCodeStrings(rom, address);
var filtered = codeStrings.Select(cs => FilterCodeString(cs)).ToArray();
builder.Append(String.Format("[{0}]", String.Join(" ", filtered)));
if (newLines && code.IsEnd)
{
builder.AppendLine();
}
}
address += code.ComputeLength(rom, address);
@ -111,7 +118,7 @@ namespace ScriptTool
}
else
{
builder.Append(CharLookup(rom[address++]));
builder.Append(GetChar(rom[address++]));
}
if (!readUntilEnd && address >= endAddress)
@ -135,13 +142,13 @@ namespace ScriptTool
{
if (rom[address] == 0 && rom[address + 1] == 0xFF)
{
builder.AppendLine("[00 FF]");
builder.Append("[00 FF]");
ended = true;
address += 2;
}
else if (rom[address] != 0xFF)
{
builder.AppendLine(CharLookup(rom[address++]));
builder.Append(GetChar(rom[address++]));
}
else
{
@ -152,17 +159,15 @@ namespace ScriptTool
return builder.ToString();
}
public string CharLookup(byte value)
public string GetChar(byte value)
{
if ((value >= 83 && value <= 95) ||
(value >= 180 && value <= 191) ||
value == 255)
if (!CharLookup.ContainsKey(value))
{
// Invalid
throw new Exception("Invalid character");
}
return charLookup[value];
return CharLookup[value];
}
}
}

View File

@ -0,0 +1,317 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;
namespace ScriptTool
{
public class EbControlCode : IControlCode, IComparable, IComparable<EbControlCode>
{
public static IEnumerable<IControlCode> Codes { get; private set; }
private static string[][] compressedStrings;
public IList<byte> Identifier { get; set; }
public string Description { get; set; }
public bool IsEnd { get; set; }
public bool IsCompressedString { get; set; }
public int Length { get; set; }
public bool IsVariableLength { get; set; }
public int ReferenceOffset { get; set; }
public int CountOffset { get; set; }
public bool HasReferences { get; set; }
public bool AbsoluteAddressing { get { return true; } }
static EbControlCode()
{
// Load compressed strings
compressedStrings = new string[3][];
string[] stringsFromFile = File.ReadAllLines(@"eb-compressed-strings.txt");
compressedStrings[0] = stringsFromFile.Take(0x100).ToArray();
compressedStrings[1] = stringsFromFile.Skip(0x100).Take(0x100).ToArray();
compressedStrings[2] = stringsFromFile.Skip(0x200).Take(0x100).ToArray();
// Load codes
Codes = JsonConvert.DeserializeObject<List<EbControlCode>>(
File.ReadAllText("eb-codelist.json"));
}
public bool IsMatch(byte[] rom, int address)
{
for (int i = 0; i < Identifier.Count; i++)
if (rom[address + i] != Identifier[i])
return false;
return true;
}
public bool IsMatch(string[] codeStrings)
{
if (codeStrings == null || codeStrings.Length < Identifier.Count)
return false;
for (int i = 0; i < Identifier.Count; i++)
if (Convert.ToByte(codeStrings[i], 16) != Identifier[i])
return false;
return true;
}
public bool IsValid(string[] codeStrings)
{
if (codeStrings == null || codeStrings.Length < 1)
return false;
if (!HasReferences)
{
if (codeStrings.Length != Length)
return false;
// Check that each codestring is a byte
for (int i = Identifier.Count; i < codeStrings.Length; i++)
{
if (!Compiler.IsHexByte(codeStrings[i]))
return false;
}
}
else
{
// If there's at least one reference, then there must be at least 5 code strings
if (codeStrings.Length < 5)
return false;
// Check bytes before references
for (int i = Identifier.Count; i < ReferenceOffset; i++)
{
if (!Compiler.IsHexByte(codeStrings[i]))
return false;
}
// Check references
int numReferences;
if (!IsVariableLength)
{
numReferences = (Length - ReferenceOffset) / 4;
}
else
{
byte count;
if (!byte.TryParse(codeStrings[CountOffset], System.Globalization.NumberStyles.HexNumber,
null, out count))
return false;
numReferences = count;
}
for (int i = 0; i < numReferences; i++)
{
string reference = codeStrings[(i * 4) + ReferenceOffset];
if (reference.Length < 3)
return false;
if (!(reference[0] == '_' && reference[reference.Length - 1] == '_'))
return false;
}
// Check bytes after references
for (int i = ReferenceOffset + (numReferences * 4); i < codeStrings.Length; i++)
{
if (!Compiler.IsHexByte(codeStrings[i]))
return false;
}
}
return true;
}
public int ComputeLength(byte[] rom, int address)
{
if (!IsVariableLength)
{
return Length;
}
else
{
int count = rom[address + CountOffset];
return (count * 4) + 1 + Identifier.Count;
}
}
private int GetReference(byte[] rom, int referenceAddress)
{
return rom.ReadSnesPointer(referenceAddress);
}
public IList<int> GetReferences(byte[] rom, int address)
{
if (!HasReferences)
return null;
var refs = new List<int>();
if (!IsVariableLength)
{
for (int i = ReferenceOffset; i < Length; i += 4)
refs.Add(GetReference(rom, address + i));
}
else
{
int count = rom[address + CountOffset];
for (int i = 0; i < count; i++)
{
refs.Add(GetReference(rom, address + ReferenceOffset + (i * 4)));
}
}
return refs;
}
public IList<CodeString> GetCodeStrings(byte[] rom, int address)
{
var codeStrings = new List<CodeString>();
foreach (var b in Identifier)
codeStrings.Add(new CodeByte(b));
int length = ComputeLength(rom, address);
if (!HasReferences)
{
// Direct copy
for (int i = Identifier.Count; i < length; i++)
{
codeStrings.Add(new CodeByte(rom[address + i]));
}
}
else
{
// Get references
var references = GetReferences(rom, address);
// Copy bytes before reference
for (int i = Identifier.Count; i < ReferenceOffset; i++)
{
codeStrings.Add(new CodeByte(rom[address + i]));
}
// Copy references
foreach (var reference in references)
{
codeStrings.Add(new CodeReference(reference));
}
// Copy bytes after reference
for (int i = ReferenceOffset + (references.Count * 4); i < length; i++)
{
codeStrings.Add(new CodeByte(rom[address + i]));
}
}
return codeStrings;
}
public void Compile(string[] codeStrings, IList<byte> buffer, ref int referenceAddress, IDictionary<string, int> addressMap)
{
foreach (var codeString in codeStrings)
{
if (codeString[0] == '_')
{
if (codeString[codeString.Length - 1] != '_')
throw new Exception("Reference has no closing underscore");
if (codeString.Length <= 2)
throw new Exception("Reference is empty");
string label = codeString.Substring(1, codeString.Length - 2);
int pointer = addressMap[label] + 0xC00000;
if (buffer != null)
buffer.AddInt(pointer);
referenceAddress += 4;
}
else
{
byte value = Convert.ToByte(codeString, 16);
buffer.Add(value);
referenceAddress++;
}
}
}
public string GetCompressedString(byte[] rom, int address)
{
return compressedStrings[rom[address] - 0x15][rom[address + 1]];
}
public override string ToString()
{
return String.Format("[{0}]: {1}", String.Join(" ", Identifier.Select(b => b.ToString("X2")).ToArray()), Description);
}
#region JSON
public bool ShouldSerializeIsEnd()
{
return IsEnd;
}
public bool ShouldSerializeIsCompressedString()
{
return IsCompressedString;
}
public bool ShouldSerializeIsVariableLength()
{
return IsVariableLength;
}
public bool ShouldSerializeHasReferences()
{
return HasReferences;
}
public bool ShouldSerializeAbsoluteAddressing()
{
return AbsoluteAddressing;
}
public bool ShouldSerializeReferenceOffset()
{
return HasReferences;
}
public bool ShouldSerializeCountOffset()
{
return IsVariableLength;
}
#endregion
public int CompareTo(EbControlCode other)
{
int numToCheck = Math.Min(Identifier.Count, other.Identifier.Count);
for (int i = 0; i < numToCheck; i++)
{
if (Identifier[i] != other.Identifier[i])
{
return Identifier[i].CompareTo(other.Identifier[i]);
}
}
return 0;
}
public int CompareTo(object obj)
{
var other = obj as EbControlCode;
if (other == null)
throw new Exception("Cannot compare!");
return CompareTo(other);
}
}
}

View File

@ -8,9 +8,10 @@ namespace ScriptTool
{
class EbTextTables
{
public static MainStringRef[] ReadTptRefs(byte[] rom)
public static Tuple<MainStringRef[], MainStringRef[]> ReadTptRefs(byte[] rom)
{
var refs = new List<MainStringRef>();
var primaryRefs = new List<MainStringRef>();
var secondaryRefs = new List<MainStringRef>();
int address = 0xF8985;
int entries = 1584;
@ -19,20 +20,20 @@ namespace ScriptTool
{
int firstPointer = rom.ReadSnesPointer(address + 9);
if (firstPointer != 0)
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 9, OldPointer = firstPointer });
primaryRefs.Add(new MainStringRef { Index = i, PointerLocation = address + 9, OldPointer = firstPointer });
byte type = rom[address];
if (type != 2)
{
int secondPointer = rom.ReadSnesPointer(address + 13);
if (secondPointer != 0)
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 13, OldPointer = secondPointer });
secondaryRefs.Add(new MainStringRef { Index = i, PointerLocation = address + 13, OldPointer = secondPointer });
}
address += 17;
}
return refs.ToArray();
return Tuple.Create(primaryRefs.ToArray(), secondaryRefs.ToArray());
}
public static MainStringRef[] ReadBattleActionRefs(byte[] rom)

View File

@ -9,7 +9,6 @@ namespace ScriptTool
{
public class FixedStringCollection
{
[JsonConverter(typeof(JsonHexConverter))]
public int StringsLocation { get; set; }
public IList<int> TablePointers { get; set; }

View File

@ -9,10 +9,7 @@ namespace ScriptTool
{
public class FixedStringRef
{
[JsonConverter(typeof(JsonHexConverter))]
public int Index { get; set; }
[JsonConverter(typeof(JsonHexConverter))]
public int OldPointer { get; set; }
public string Old { get; set; }

View File

@ -8,8 +8,10 @@ namespace ScriptTool
{
public interface ICompiler
{
IList<string> ScanString(string str, bool scanCodesOnly);
IList<string> ScanString(string str, ref int referenceAddress, bool scanCodesOnly);
void CompileString(string str, IList<byte> buffer, ref int referenceAddress);
void ScanString(string str, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out IList<string> references, out ISet<IControlCode> controlCodes);
void ScanString(string str, ref int referenceAddress, IDictionary<byte, string> charLookup, bool scanCodesOnly,
out IList<string> references, out ISet<IControlCode> controlCodes);
void CompileString(string str, IList<byte> buffer, ref int referenceAddress, IDictionary<byte, string> charLookup);
}
}

View File

@ -9,11 +9,17 @@ namespace ScriptTool
public interface IControlCode
{
bool IsEnd { get; }
bool IsCompressedString { get; }
bool IsMatch(byte[] rom, int address);
bool IsMatch(string[] codeStrings);
bool IsValid(string[] codeStrings);
bool HasReferences { get; }
bool AbsoluteAddressing { get; }
int ComputeLength(byte[] rom, int address);
IList<int> GetReferences(byte[] rom, int address);
IList<CodeString> GetCodeStrings(byte[] rom, int address);
string GetCompressedString(byte[] rom, int address);
void Compile(string[] codeStrings, IList<byte> buffer, ref int referenceAddress, IDictionary<string, int> addressMap);
}
}

View File

@ -11,6 +11,5 @@ namespace ScriptTool
void ScanRange(byte[] rom, int startAddress, int endAddress);
string DecompileRange(byte[] rom, int startAddress, int endAddress, bool newLines);
string DecompileString(byte[] rom, int address, bool newLines);
string CharLookup(byte value);
}
}

View File

@ -1,43 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace ScriptTool
{
public class JsonHexConverter : JsonConverter
{
private static readonly Type[] allowedTypes = {
typeof(int),
typeof(uint),
typeof(byte),
typeof(sbyte),
typeof(short),
typeof(ushort),
typeof(long),
typeof(ulong)
};
public override bool CanConvert(Type objectType)
{
return allowedTypes.Contains(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Integer)
{
var hex = serializer.Deserialize(reader, objectType);
return hex;
}
throw new Exception("Unexpected token");
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteRawValue(String.Format("0x{0:X}", value));
}
}
}

View File

@ -8,11 +8,10 @@ using Newtonsoft.Json;
namespace ScriptTool
{
public class M12ControlCode : IControlCode
public class M12ControlCode : IControlCode, IComparable, IComparable<M12ControlCode>
{
public static IEnumerable<M12ControlCode> Codes { get; private set; }
public static IEnumerable<IControlCode> Codes { get; private set; }
[JsonConverter(typeof(JsonHexConverter))]
public byte Identifier { get; set; }
public string Description { get; set; }
public bool IsEnd { get; set; }
@ -21,6 +20,7 @@ namespace ScriptTool
public int ReferenceOffset { get; set; }
public bool HasReferences { get; set; }
public bool AbsoluteAddressing { get; set; }
public bool IsCompressedString { get { return false; } }
static M12ControlCode()
{
@ -39,8 +39,9 @@ namespace ScriptTool
if (codeStrings == null || codeStrings.Length < 2)
return false;
byte value1 = byte.Parse(codeStrings[0], System.Globalization.NumberStyles.HexNumber);
byte value2 = byte.Parse(codeStrings[1], System.Globalization.NumberStyles.HexNumber);
byte value1 = Convert.ToByte(codeStrings[0], 16);
byte value2 = Convert.ToByte(codeStrings[1], 16);
return value1 == Identifier && value2 == 0xFF;
}
@ -58,7 +59,7 @@ namespace ScriptTool
// Check that each codestring is a byte
for (int i = 2; i < codeStrings.Length; i++)
{
if (!M12Compiler.IsHexByte(codeStrings[i]))
if (!Compiler.IsHexByte(codeStrings[i]))
return false;
}
}
@ -71,7 +72,7 @@ namespace ScriptTool
// Check bytes before references
for (int i = 2; i < ReferenceOffset; i++)
{
if (!M12Compiler.IsHexByte(codeStrings[i]))
if (!Compiler.IsHexByte(codeStrings[i]))
return false;
}
@ -106,7 +107,7 @@ namespace ScriptTool
// Check bytes after references
for (int i = ReferenceOffset + (numReferences * 4); i < codeStrings.Length; i++)
{
if (!M12Compiler.IsHexByte(codeStrings[i]))
if (!Compiler.IsHexByte(codeStrings[i]))
return false;
}
}
@ -202,9 +203,65 @@ namespace ScriptTool
return codeStrings;
}
public void Compile(string[] codeStrings, IList<byte> buffer, ref int referenceAddress, IDictionary<string, int> addressMap)
{
foreach (var codeString in codeStrings)
{
if (codeString[0] == '_')
{
if (codeString[codeString.Length - 1] != '_')
throw new Exception("Reference has no closing underscore");
if (codeString.Length <= 2)
throw new Exception("Reference is empty");
string label = codeString.Substring(1, codeString.Length - 2);
int pointer = addressMap[label];
if (!AbsoluteAddressing)
{
pointer -= referenceAddress;
}
else
{
pointer |= 0x8000000;
}
if (buffer != null)
buffer.AddInt(pointer);
referenceAddress += 4;
}
else
{
byte value = Convert.ToByte(codeString, 16);
buffer.Add(value);
referenceAddress++;
}
}
}
public string GetCompressedString(byte[] rom, int address)
{
throw new InvalidOperationException("Code is not a compressed string");
}
public override string ToString()
{
return String.Format("[{0:X2} FF]: {1}", Identifier, Description);
}
public int CompareTo(M12ControlCode other)
{
return Identifier.CompareTo(other.Identifier);
}
public int CompareTo(object obj)
{
var other = obj as M12ControlCode;
if (other == null)
throw new Exception("Cannot compare!");
return CompareTo(other);
}
}
}

View File

@ -9,13 +9,8 @@ namespace ScriptTool
{
public class MainStringRef
{
[JsonConverter(typeof(JsonHexConverter))]
public int Index { get; set; }
[JsonConverter(typeof(JsonHexConverter))]
public int PointerLocation { get; set; }
[JsonConverter(typeof(JsonHexConverter))]
public int OldPointer { get; set; }
public string Label { get; set; }

View File

@ -9,10 +9,7 @@ namespace ScriptTool
{
public class MiscStringCollection
{
[JsonConverter(typeof(JsonHexConverter))]
public int OffsetTableLocation { get; set; }
[JsonConverter(typeof(JsonHexConverter))]
public int StringsLocation { get; set; }
public IList<MiscStringRef> StringRefs { get; set; }

View File

@ -9,13 +9,8 @@ namespace ScriptTool
{
public class MiscStringRef
{
[JsonConverter(typeof(JsonHexConverter))]
public int Index { get; set; }
[JsonConverter(typeof(JsonHexConverter))]
public int OffsetLocation { get; set; }
[JsonConverter(typeof(JsonHexConverter))]
public int OldPointer { get; set; }
public bool BasicMode { get; set; }

View File

@ -18,10 +18,14 @@ namespace ScriptTool
static byte[] m12Rom;
// Decompiler setup
static M12Decompiler m12Decompiler;
static Decompiler m12Decompiler;
static Decompiler ebDecompiler;
static IDictionary<byte, string> m12CharLookup;
static IDictionary<byte, string> ebCharLookup;
// Compiler setup
static M12Compiler m12Compiler;
static Compiler m12Compiler;
static StreamWriter IncludeFile;
static void Main(string[] args)
@ -33,9 +37,14 @@ namespace ScriptTool
return;
}
m12CharLookup = JsonConvert.DeserializeObject<Dictionary<byte, string>>(File.ReadAllText("m12-char-lookup.json"));
ebCharLookup = JsonConvert.DeserializeObject<Dictionary<byte, string>>(File.ReadAllText("eb-char-lookup.json"));
if (options.Command == CommandType.Decompile)
{
m12Decompiler = new M12Decompiler();
// Set up decompilers
m12Decompiler = new Decompiler(M12ControlCode.Codes, m12CharLookup, (rom, address) => rom[address + 1] == 0xFF);
ebDecompiler = new Decompiler(EbControlCode.Codes, ebCharLookup, (rom, address) => rom[address] < 0x20);
// Load ROMs
ebRom = File.ReadAllBytes(options.EbRom);
@ -51,13 +60,14 @@ namespace ScriptTool
// Decompile main string tables
if (options.DoMainText)
{
//DecompileEb();
DecompileEb();
DecompileM12();
}
}
else if (options.Command == CommandType.Compile)
{
m12Compiler = new M12Compiler();
// Set up compilers
m12Compiler = new Compiler(M12ControlCode.Codes, (rom, address) => rom[address + 1] == 0xFF);
using (IncludeFile = File.CreateText(Path.Combine(options.WorkingDirectory, "m12-includes.asm")))
{
@ -149,13 +159,14 @@ namespace ScriptTool
};
}
/*static void DecompileEb(byte[] ebRom, string workingDirectory)
static void DecompileEb()
{
var context = new DecompileContext();
// Pull all string refs from the ROM
var allRefs = new List<Tuple<string, MainStringRef[]>>();
allRefs.Add(Tuple.Create("eb-tpt", EbTextTables.ReadTptRefs(ebRom)));
var tptTuple = EbTextTables.ReadTptRefs(ebRom);
allRefs.Add(Tuple.Create("eb-tpt-primary", tptTuple.Item1));
allRefs.Add(Tuple.Create("eb-tpt-secondary", tptTuple.Item2));
allRefs.Add(Tuple.Create("eb-battle-actions", EbTextTables.ReadBattleActionRefs(ebRom)));
allRefs.Add(Tuple.Create("eb-prayers", EbTextTables.ReadPrayerRefs(ebRom)));
allRefs.Add(Tuple.Create("eb-item-help", EbTextTables.ReadItemHelpRefs(ebRom)));
@ -164,29 +175,43 @@ namespace ScriptTool
allRefs.Add(Tuple.Create("eb-enemy-encounters", EbTextTables.ReadEnemyTextRefs(ebRom)));
// Decompile
var allPointers = allRefs.SelectMany(rl => rl.Item2).Select(r => r.OldPointer).ToArray();
ebDecompiler.Decompile(ebRom, allPointers, context);
var allPointers = allRefs.SelectMany(rl => rl.Item2).Select(r => r.OldPointer);
ebDecompiler.LabelMap.AddRange(allPointers);
IList<int[]> textRanges = new List<int[]>();
textRanges.Add(new int[] { 0x50000, 0x5FFEC });
textRanges.Add(new int[] { 0x60000, 0x6FFE3 });
textRanges.Add(new int[] { 0x70000, 0x7FF40 });
textRanges.Add(new int[] { 0x80000, 0x8BC2D });
textRanges.Add(new int[] { 0x8D9ED, 0x8FFF3 });
textRanges.Add(new int[] { 0x90000, 0x9FF2F });
textRanges.Add(new int[] { 0x2F4E20, 0x2FA460 });
var strings = new List<string>();
foreach (var range in textRanges)
{
ebDecompiler.ScanRange(ebRom, range[0], range[1]);
}
foreach (var range in textRanges)
{
strings.Add(ebDecompiler.DecompileRange(ebRom, range[0], range[1], true));
}
// Update labels for all refs and write to JSON
foreach (var refList in allRefs)
{
foreach (var stringRef in refList.Item2)
stringRef.Label = context.LabelMap[stringRef.OldPointer];
stringRef.Label = ebDecompiler.LabelMap.Labels[stringRef.OldPointer];
File.WriteAllText(Path.Combine(workingDirectory, refList.Item1 + ".json"), JsonConvert.SerializeObject(refList.Item2, Formatting.Indented));
File.WriteAllText(Path.Combine(options.WorkingDirectory, refList.Item1 + ".json"),
JsonConvert.SerializeObject(refList.Item2, Formatting.Indented));
}
// Write the strings
File.WriteAllText(Path.Combine(workingDirectory, "eb-strings.txt"), String.Join(Environment.NewLine, context.Strings));
File.WriteAllText(Path.Combine(options.WorkingDirectory, "eb-strings.txt"), String.Join(Environment.NewLine, strings));
}
static void DecompileEbMisc(byte[] ebRom, string workingDirectory)
{
// Enemy names
var enemyNames = EbTextTables.ReadEnemyNames(ebRom);
DecompileFixedStringCollection(ebDecompiler, ebRom, workingDirectory, "eb-enemynames", enemyNames);
}*/
static void DecompileM12()
{
// Pull all string refs from the ROM
@ -314,14 +339,15 @@ namespace ScriptTool
string m12Strings = File.ReadAllText(Path.Combine(options.WorkingDirectory, "m12-strings-english.txt"));
// Compile
m12Compiler.ScanString(m12Strings, ref referenceAddress, false);
m12Compiler.ScanString(m12Strings, ref referenceAddress, ebCharLookup, false);
referenceAddress = baseAddress;
m12Compiler.CompileString(m12Strings, buffer, ref referenceAddress);
m12Compiler.CompileString(m12Strings, buffer, ref referenceAddress, ebCharLookup);
File.WriteAllBytes(Path.Combine(options.WorkingDirectory, "m12-main-strings.bin"), buffer.ToArray());
// Update labels
string[] labelFiles = {
"m12-tpt",
"m12-tpt-primary",
"m12-tpt-secondary",
"m12-psihelp",
"m12-battle-actions",
"m12-itemhelp",
@ -419,7 +445,7 @@ namespace ScriptTool
offsetFile.WriteLine(String.Format("org ${0:X}; dd ${1:X8}",
str.OffsetLocation | 0x8000000, referenceAddress - stringCollection.StringsLocation));
m12Compiler.CompileString(str.New, buffer, ref referenceAddress);
m12Compiler.CompileString(str.New, buffer, ref referenceAddress, ebCharLookup);
}
}
@ -459,7 +485,7 @@ namespace ScriptTool
foreach (var str in stringCollection.StringRefs.OrderBy(s => s.Index))
{
newPointers.Add(referenceAddress);
m12Compiler.CompileString(str.New, buffer, ref referenceAddress, stringCollection.EntryLength);
m12Compiler.CompileString(str.New, buffer, ref referenceAddress, ebCharLookup, stringCollection.EntryLength);
}
}

View File

@ -50,16 +50,16 @@
<Compile Include="CodeReference.cs" />
<Compile Include="CodeString.cs" />
<Compile Include="CommandOptions.cs" />
<Compile Include="EbControlCode.cs" />
<Compile Include="FixedStringCollection.cs" />
<Compile Include="ICompiler.cs" />
<Compile Include="IControlCode.cs" />
<Compile Include="IDecompiler.cs" />
<Compile Include="M12ControlCode.cs" />
<Compile Include="M12Compiler.cs" />
<Compile Include="M12Decompiler.cs" />
<Compile Include="Compiler.cs" />
<Compile Include="Decompiler.cs" />
<Compile Include="M12TextTables.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="JsonHexConverter.cs" />
<Compile Include="LabelMap.cs" />
<Compile Include="MiscStringCollection.cs" />
<Compile Include="FixedStringRef.cs" />
@ -71,21 +71,24 @@
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="eb-char-lookup.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="eb-codelist.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="m12-char-lookup.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="m12-codelist.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Content Include="eb-codelist.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="eb-compressed-strings.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="m12-text-table.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

View File

@ -0,0 +1,98 @@
{
"80": " ",
"81": "!",
"82": "\"",
"83": "#",
"84": "$",
"85": "%",
"86": "&",
"87": "'",
"88": "(",
"89": ")",
"90": "*",
"91": "+",
"92": ",",
"93": "-",
"94": ".",
"95": "/",
"96": "0",
"97": "1",
"98": "2",
"99": "3",
"100": "4",
"101": "5",
"102": "6",
"103": "7",
"104": "8",
"105": "9",
"106": ":",
"107": ";",
"108": "<",
"109": "=",
"110": ">",
"111": "?",
"112": "@",
"113": "A",
"114": "B",
"115": "C",
"116": "D",
"117": "E",
"118": "F",
"119": "G",
"120": "H",
"121": "I",
"122": "J",
"123": "K",
"124": "L",
"125": "M",
"126": "N",
"127": "O",
"128": "P",
"129": "Q",
"130": "R",
"131": "S",
"132": "T",
"133": "U",
"134": "V",
"135": "W",
"136": "X",
"137": "Y",
"138": "Z",
"139": "[8B]",
"140": "[8C]",
"141": "[8D]",
"142": "[8E]",
"143": "[8F]",
"144": "`",
"145": "a",
"146": "b",
"147": "c",
"148": "d",
"149": "e",
"150": "f",
"151": "g",
"152": "h",
"153": "i",
"154": "j",
"155": "k",
"156": "l",
"157": "m",
"158": "n",
"159": "o",
"160": "p",
"161": "q",
"162": "r",
"163": "s",
"164": "t",
"165": "u",
"166": "v",
"167": "w",
"168": "x",
"169": "y",
"170": "z",
"171": "{",
"172": "|",
"173": "}",
"174": "~",
"175": "\\"
}

File diff suppressed because it is too large Load Diff

View File

@ -1,216 +0,0 @@
00,"Line break";
01,"Start on Blank Line";
!02,"Signal end of block or string";
03,"Wait with prompt, brief pause in battle";
04 XX XX,"Toggle flag $XXXX on";
05 XX XX,"Toggle flag $XXXX off";
06 XX XX YY YY YY YY,"If flag $XXXX is set, jump to address $YYYYYYYY";
07 XX XX,"Set binary flag with the status of flag $XXXX";
08 XX XX XX XX,"Parse text at $XXXXXXXX and continue here";
*09,"Multiple-entry pointer table (Jump to address)";
!0A XX XX XX XX,"Jump to text at address $XXXXXXXX";
0B XX,"Set binary flag to true if number in memory == $XX";
0C XX,"Set binary flag to true if number in memory != $XX";
0D XX,"Copy from memory $XX into argumentative memory";
0E XX,"Input $XX into a memory bank";
0F,"Secondary memory +1";
10 XX,"Pause for ~0.02 sec. * $XX";
11,"Treats text displayed by [1C (07|0C) XX] as a menu";
12,"Clear current line of text";
13,"Wait without prompt";
14,"Wait with prompt in battle";
18 00,"Closes most recently used text window";
18 01 XX,"Open window";
18 02,"UNKNOWN";
18 03 XX,"Change parsing focus to window $XX";
18 04,"Close all windows";
18 05 XX YY,"Display text $XX pixels over and $YY lines down";
18 06,"Clear contents from current window";
18 07 XX XX XX XX YY,"Check for $XX inequality to memory";
18 08 XX,"UNKNOWN";
18 09 XX,"UNKNOWN";
18 0A,"Open wallet window and display current cash on hand";
18 0D XX YY,"Display Status window for Char$XX YY-01-parameter, 01,02 specific, 02 ?";
19 02,"Load a text string into memory (end with [02])"
19 04,"UNKNOWN";
19 05 XX YY ZZ,"Inflict ailment YY YY on character $XX";
19 10 XX,"Return the character number of the person in party position $XX"
19 11 XX,"Return One Letter from a Character's Name (see lexicon.txt)";
19 14,"UNKNOWN";
19 16 XX YY,"Return Byte YY of Character XX Status";
19 18 XX,"UNKNOWN";
19 19 XX YY,"Sets $YY(01-0e) in item menu of Char$XX into working memory";
19 1A XX,"UNKNOWN";
19 1B XX,"UNKNOWN";
19 1C XX YY,"UNKNOWN";
19 1D XX YY,"UNKNOWN";
19 1E,"UNKNOWN";
19 1F,"UNKNOWN";
19 20,"UNKNOWN";
19 21 XX,"UNKNOWN";
19 22 XX XX YY YY,"Store to memory the direction from character $XX to object $YY";
19 23 XX XX YY YY ZZ,"Store to memory the direction from TPT entry $XX to object $YY (ZZ unknown)";
19 24 XX XX YY YY ZZ,"Store to memory the direction from generated sprite $XX to object $YY (ZZ=00)";
19 25 XX,"UNKNOWN";
19 26 XX,"UNKNOWN";
19 27 XX,"UNKNOWN";
19 28 XX,"UNKNOWN";
1A 00,"UNKNOWN INCOMPLETE";
1A 01 WW WW WW WW XX XX XX XX YY YY YY YY ZZ ZZ ZZ ZZ,"Current Party Member Selection Menu";
1A 04,"UNKNOWN INCOMPLETE";
1A 05 XX YY,"Display the inventory of character YY in window XX";
1A 06 XX,"Displays shop window $XX";
1A 07,"Related to Escargo Express stored goods window";
1A 08,"UNKNOWN INCOMPLETE";
1A 09,"UNKNOWN INCOMPLETE";
1A 0A,"Open non-working phone window";
1A 0B,"Copy WRAM to Active Memory";
1B 00,"Copy all memory to storage";
1B 01,"Copy all storage to memory";
1B 02 XX XX XX XX,"If binary flag is set 0, jump to $XXXXXXXX";
1B 03 XX XX XX XX,"If binary flag is set 1, jump to $XXXXXXXX";
1B 04,"Swap working and argumentary memory";
1B 05,"Copy Active Memory to WRAM";
1B 06,"Copy WRAM to Active Memory";
1C 00 XX,"Text and window background color effects";
1C 01 XX,"Display statistical data value $XX";
1C 02 XX,"Display character name $XX";
1C 03 XX,"Display Text Character XX; 00 as argument";
1C 04,"Open party HP/PP status windows";
1C 05 XX,"Display item name $XX";
1C 06 XX,"Display teleport destination name $XX";
1C 07 XX,"Display $XX strings centered horizontally (see [19 02])";
1C 08 XX,"Display text graphic $XX";
1C 09 XX,"UNKNOWN";
1C 0A XX XX XX XX,"Displays $XXXXXXXX in decimal";
1C 0B XX XX XX XX,"Displays $XXXXXXXX in decimal as money";
1C 0C XX,"Display $XX strings vertically (see [19 02])";
1C 0D,"Display action user name";
1C 0E,"Display action target name";
1C 0F,"UNKNOWN INCOMPLETE;IN PROGRESS (Relates to Level-Up stats editor)";
1C 11 XX,"UNKNOWN";
1C 12 XX,"Print PSI name $XX";
1C 13 XX YY,"Display XX Amimation (YY is usually 00) See Animation code on forum";
1C 14 XX,"Say $XX pronoun";
1C 15 XX,"Say $XX pronoun";
1D 00 XX XX,"Add item $YY to character $XX's inventory and return $YY if successful";
1D 01 XX YY,"Remove item $YY from character $XX's inventory";
1D 02 XX,"Set binary flag true if character $XX does not have free space in their inventory";
1D 03 XX,"Set binary flag true if character $XX has free space in their inventory";
1D 04 XX YY,"Sets binary flag true if char $XX does not have item $YY";
1D 05 XX YY,"Sets binary flag true if char $XX has item $YY";
1D 06 XX XX XX XX,"Add $XX dollars to ATM balance";
1D 07 XX XX XX XX,"Remove $XX dollars from ATM balance";
1D 08 XX XX,"Add $XX dollars to wallet balance";
1D 09 XX XX,"Remove $XX dollars from wallet balance"
1D 0A XX,"Return price of item";
1D 0B XX,"Get one half of item $XX";
1D 0C XX XX,"UNKNOWN";
1D 0D XX YY YY,"Set binary flag true if character $XX has ailment YY YY";
1D 0E XX YY,"Add item $YY to character $XX's inventory and return number of items held";
1D 0F XX YY,"UNKNOWN";
1D 10 XX XX,"UNKNOWN";
1D 11 XX XX,"UNKNOWN";
1D 12 XX XX,"UNKNOWN";
1D 13 XX XX,"UNKNOWN";
1D 14 XX XX XX XX,"Sets binary flag true if the player currently holds $XX in the wallet";
1D 15 XX XX,"Multiply $XXXX by the number of characters in the party, and store in Working Memory";
1D 17 XX XX XX XX,"Sets binary flag true if the player currently holds $XX in the ATM";
1D 18 XX,"UNKNOWN";
1D 19 XX,"Sets binary flag true if there are $XX party members";
1D 20,"Check same user/target";
1D 21 XX,"Generate random number from 0 to $XX";
1D 22,"Set binary flag if current sector is Exit mouse-compatible";
1D 23 XX,"UNKNOWN";
1D 24 XX,"May relate to returning cash earned since last phone call to dad";
1E 00 XX YY,"Character $XX recovers HP by YY% of max";
1E 01 XX YY,"Character $XX loses HP by YY% of max";
1E 02 XX YY,"Character $XX recovers $YY HP";
1E 03 XX YY,"Character $XX loses $YY HP";
1E 04 XX YY,"Character $XX recovers PP by YY% of max";
1E 05 XX YY,"Character $XX loses PP by YY% of max";
1E 06 XX YY,"Character $XX recovers $YY PP";
1E 07 XX YY,"Character $XX loses $YY PP";
1E 08 XX YY,"Character $XX becomes level $YY";
1E 09 XX YY YY YY,"Character $XX gains $YYYYYY EXP";
1E 0A XX YY,"Boost IQ in character $XX by $YY";
1E 0B XX YY,"Boost Guts in character $XX by $YY";
1E 0C XX YY,"Boost Speed in character $XX by $YY";
1E 0D XX YY,"Boost Vitality in character $XX by $YY";
1E 0E XX YY,"Boost Luck in character $XX by $YY";
1F 00 XX YY,"Play music track $YY ($XX is unused)";
1F 01 00,"Stops music";
1F 02 XX,"Play sound effect $XX";
1F 03,"Return music setting to sector default";
1F 04 XX,"Toggles sound for text printing (?)";
1F 05,"Disallow Sector Boundaries to Change Music";
1F 06,"Allow Sector Boundaries to Change Music";
1F 07 XX,"Apply audio effect $XX";
1F 11 XX,"Add character $XX to party";
1F 12 XX,"Remove character $XX from party";
1F 13 XX YY,"Turn character $XX to direction $YY";
1F 14 XX,"UNKNOWN";
1F 15 XX XX YY YY ZZ,"Generate sprite $XXXX with movement pattern $YYYY using style $ZZ";
1F 16 XX XX YY,"Turn TPT entry $XXXX to direction $YY";
1F 17 XX XX YY YY ZZ,"Generate TPT entry $XXXX with movement pattern $YYYY using style $ZZ";
1F 18 XX XX XX XX XX XX XX,"UNKNOWN";
1F 19 XX XX XX XX XX XX XX,"UNKNOWN";
1F 1A XX XX YY,"Generate sprite $YY near TPT entry $XXXX";
1F 1B XX XX,"Delete 1F 1A sprite near TPT entry $XXXX";
1F 1C XX YY,"Generate sprite $YY near character $XX";
1F 1D XX,"Delete 1F 1C sprite near character $XX";
1F 1E XX XX YY,"Make TPT entry $XXXX disappear via style $YY";
1F 1F XX XX YY,"Delete 1F 15-generated sprite $XXXX via style $YY";
1F 20 XX YY,"PSI Teleport to destination $XX using method $YY";
1F 21 XX,"Teleport to 0x15EDAB teleport coordinate entry $XX";
1F 23 XX XX,"Trigger battle with 0x10D74C enemy group entry $XXXX";
1F 30,"Change to normal font";
1F 31,"Change to Mr. Saturn font";
1F 41 XX,"Call special event $XX";
1F 50,"Disable controller input";
1F 51,"Re-enable controller input";
1F 52 XX,"Number selector with XX digits";
1F 60 XX,"UNKNOWN";
1F 61,"Simultaneously commences all prepared movements";
1F 62 XX,"UNKNOWN";
1F 63 XX XX XX XX,"Jump to $XXXXXXXX after the next screen refresh";
1F 64,"Purge all NPCs from party";
1F 65,"Purge first NPC from party";
1F 66 XX YY ZZ ZZ ZZ ZZ,"Activate hotspot $XX with address $ZZZZZZZZ";
1F 67 XX,"Deactivate hotspot $XX";
1F 68,"Store current coordinates into memory";
1F 69,"Teleport to coordinates stored by 1F 68";
1F 71 XX YY,"Character $XX realizes special PSI $YY";
1F 81 XX XX,"Check If Character Can Use Item";
1F 83 XX XX,"Equip character XX with his or her YYth item";
1F 90,"UNKNOWN";
1F A0,"TPT entry being spoken to/checked faces downwards";
1F A1,"Change Direction of Current TPT Entry to Down";
1F A2,"UNKNOWN";
1F B0,"Save the game in the slot selected at the beginning";
*1F C0,"Multiple-entry pointer table (Reference address)";
1F D0 XX,"Attempt to Fix Items";
1F D1,"Returns a numeric value based on the proximity of a magic truffle TPT entry";
1F D2 XX,"Summon photographer to location $XX";
1F D3 XX,"Trigger timed event $XX from the 0x15F845 table";
1F E1 XX YY ZZ,"Change map palette to that of tileset $XX, pallet $YY at speed $ZZ";
1F E4 XX XX YY,"Change direction of 1F 15-generated sprite $XXXX to $YY";
1F E5 XX,"Lock player movement";
1F E6 XX XX,"Delay appearance of TPT entry $XXXX until end of text parsing";
1F E7 XX XX,"UNKNOWN";
1F E8 XX,"Restrict player movement if camera is focused on other sprite (XX is usually FF)";
1F E9 XX XX,"Restrict player movement until end of text block (use 1F 61 after)";
1F EA XX XX,"UNKNOWN";
1F EB XX YY,"Make character $XX disappear via style $YY";
1F EC XX YY,"Make character $XX appear via style $YY";
1F ED,"Your party will be teleported (in a glitchy way) on top of some sprite that is nearby when the text block is over if the camera switched to another sprite in the block of text";
1F EE XX XX,"UNKNOWN";
1F EF XX XX,"Focuses the camera to where [1f 15]-generated sprite xxxx is but doesn't follow it";
1F F0,"Activate bicycle";
1F F1 XX XX YY YY,"Apply movement pattern $YYYY to TPT entry $XXXX";
1F F2 XX XX YY YY,"Apply movement pattern $YYYY to sprite $XXXX";
1F F3 XX XX YY,"Generate sprite $YY near sprite $XXXX";
1F F4 XX XX,"Delete 1F F3 sprite near sprite $XXXX";
15 XX,"Use compressed string $XX from bank 0";
16 XX,"Use compressed string $XX from bank 1";
17 XX,"Use compressed string $XX from bank 2";

View File

@ -0,0 +1,232 @@
{
"0": "ぁ",
"1": "あ",
"2": "ぃ",
"3": "い",
"4": "ぅ",
"5": "う",
"6": "ぇ",
"7": "え",
"8": "ぉ",
"9": "お",
"10": "か",
"11": "が",
"12": "き",
"13": "ぎ",
"14": "く",
"15": "ぐ",
"16": "け",
"17": "げ",
"18": "こ",
"19": "ご",
"20": "さ",
"21": "ざ",
"22": "し",
"23": "じ",
"24": "す",
"25": "ず",
"26": "せ",
"27": "ぜ",
"28": "そ",
"29": "ぞ",
"30": "た",
"31": "だ",
"32": "ち",
"33": "ぢ",
"34": "っ",
"35": "つ",
"36": "づ",
"37": "て",
"38": "で",
"39": "と",
"40": "ど",
"41": "な",
"42": "に",
"43": "ぬ",
"44": "ね",
"45": "の",
"46": "は",
"47": "ば",
"48": "ぱ",
"49": "ひ",
"50": "び",
"51": "ぴ",
"52": "ふ",
"53": "ぶ",
"54": "ぷ",
"55": "へ",
"56": "べ",
"57": "ぺ",
"58": "ほ",
"59": "ぼ",
"60": "ぽ",
"61": "ま",
"62": "み",
"63": "む",
"64": "め",
"65": "も",
"66": "ゃ",
"67": "や",
"68": "ゅ",
"69": "ゆ",
"70": "ょ",
"71": "よ",
"72": "ら",
"73": "り",
"74": "る",
"75": "れ",
"76": "ろ",
"77": " ",
"78": "わ",
"79": " ",
"80": " ",
"81": "を",
"82": "ん",
"96": "ァ",
"97": "ア",
"98": "ィ",
"99": "イ",
"100": "ゥ",
"101": "ウ",
"102": "ェ",
"103": "エ",
"104": "ォ",
"105": "オ",
"106": "カ",
"107": "ガ",
"108": "キ",
"109": "ギ",
"110": "ク",
"111": "グ",
"112": "ケ",
"113": "ゲ",
"114": "コ",
"115": "ゴ",
"116": "サ",
"117": "ザ",
"118": "シ",
"119": "ジ",
"120": "ス",
"121": "ズ",
"122": "セ",
"123": "ゼ",
"124": "ソ",
"125": "ゾ",
"126": "タ",
"127": "ダ",
"128": "チ",
"129": "ヂ",
"130": "ッ",
"131": "ツ",
"132": "ヅ",
"133": "テ",
"134": "デ",
"135": "ト",
"136": "ド",
"137": "ナ",
"138": "ニ",
"139": "ヌ",
"140": "ネ",
"141": "",
"142": "ハ",
"143": "バ",
"144": "パ",
"145": "ヒ",
"146": "ビ",
"147": "ピ",
"148": "フ",
"149": "ブ",
"150": "プ",
"151": "ヘ",
"152": "ベ",
"153": "ペ",
"154": "ホ",
"155": "ボ",
"156": "ポ",
"157": "マ",
"158": "ミ",
"159": ".",
"160": "ム",
"161": "メ",
"162": "モ",
"163": "ャ",
"164": "ヤ",
"165": "ュ",
"166": "ユ",
"167": "ョ",
"168": "ヨ",
"169": "ラ",
"170": "リ",
"171": "ル",
"172": "レ",
"173": "ロ",
"174": " ",
"175": "ワ",
"176": " ",
"177": " ",
"178": "ヲ",
"179": "ン",
"192": "A",
"193": "B",
"194": "C",
"195": "D",
"196": "E",
"197": "F",
"198": "G",
"199": "H",
"200": "I",
"201": "J",
"202": "K",
"203": "L",
"204": "M",
"205": "N",
"206": "O",
"207": "P",
"208": "Q",
"209": "R",
"210": "S",
"211": "T",
"212": "U",
"213": "V",
"214": "W",
"215": "X",
"216": "Y",
"217": "Z",
"218": "α",
"219": "β",
"220": "γ",
"221": "Σ",
"222": "Ω",
"223": " ",
"224": "0",
"225": "1",
"226": "2",
"227": "3",
"228": "4",
"229": "5",
"230": "6",
"231": "7",
"232": "8",
"233": "9",
"234": "#",
"235": "!",
"236": "?",
"237": "/",
"238": ":",
"239": "-",
"240": "~",
"241": "・",
"242": "¨",
"243": "。",
"244": "「",
"245": "」",
"246": "(",
"247": ")",
"248": "♪",
"249": "◯",
"250": "$",
"251": "\"",
"252": "°",
"253": "◆",
"254": "Ê"
}

View File

@ -1,256 +0,0 @@
ぁ
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
.
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
INVALID
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
α
β
γ
Σ
Ω
0
1
2
3
4
5
6
7
8
9
#
!
?
/
:
~
·
··
(
)
$
"
°
(e)
CONTROL CODE

View File

@ -41,8 +41,13 @@
this.mainPanel = new System.Windows.Forms.Panel();
this.mainSplitContainer = new System.Windows.Forms.SplitContainer();
this.leftSplitContainer = new System.Windows.Forms.SplitContainer();
this.textBoxPanel = new System.Windows.Forms.Panel();
this.ebString = new System.Windows.Forms.TextBox();
this.m12String = new System.Windows.Forms.TextBox();
this.m12StringEnglish = new System.Windows.Forms.TextBox();
this.lineOpsPanel = new System.Windows.Forms.FlowLayoutPanel();
this.copyCodesButton = new System.Windows.Forms.Button();
this.codeSplitContainer = new System.Windows.Forms.SplitContainer();
this.codeList = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.referenceList = new System.Windows.Forms.ListBox();
this.label3 = new System.Windows.Forms.Label();
@ -52,12 +57,7 @@
this.statusBar = new System.Windows.Forms.StatusStrip();
this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.writeTimer = new System.Windows.Forms.Timer(this.components);
this.lineOpsPanel = new System.Windows.Forms.FlowLayoutPanel();
this.textBoxPanel = new System.Windows.Forms.Panel();
this.ebString = new System.Windows.Forms.TextBox();
this.m12String = new System.Windows.Forms.TextBox();
this.m12StringEnglish = new System.Windows.Forms.TextBox();
this.copyCodesButton = new System.Windows.Forms.Button();
this.codeList = new System.Windows.Forms.ListBox();
this.mainMenu.SuspendLayout();
this.topPanel.SuspendLayout();
this.mainPanel.SuspendLayout();
@ -68,14 +68,14 @@
((System.ComponentModel.ISupportInitialize)(this.leftSplitContainer)).BeginInit();
this.leftSplitContainer.Panel1.SuspendLayout();
this.leftSplitContainer.SuspendLayout();
this.textBoxPanel.SuspendLayout();
this.lineOpsPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.codeSplitContainer)).BeginInit();
this.codeSplitContainer.Panel1.SuspendLayout();
this.codeSplitContainer.Panel2.SuspendLayout();
this.codeSplitContainer.SuspendLayout();
this.gameSelectorPanel.SuspendLayout();
this.statusBar.SuspendLayout();
this.lineOpsPanel.SuspendLayout();
this.textBoxPanel.SuspendLayout();
this.SuspendLayout();
//
// mainMenu
@ -182,7 +182,7 @@
this.mainPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.mainPanel.Location = new System.Drawing.Point(0, 53);
this.mainPanel.Name = "mainPanel";
this.mainPanel.Size = new System.Drawing.Size(853, 540);
this.mainPanel.Size = new System.Drawing.Size(853, 667);
this.mainPanel.TabIndex = 11;
//
// mainSplitContainer
@ -204,7 +204,7 @@
this.mainSplitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control;
this.mainSplitContainer.Panel2.Controls.Add(this.codeSplitContainer);
this.mainSplitContainer.Panel2.Controls.Add(this.gameSelectorPanel);
this.mainSplitContainer.Size = new System.Drawing.Size(853, 540);
this.mainSplitContainer.Size = new System.Drawing.Size(853, 667);
this.mainSplitContainer.SplitterDistance = 627;
this.mainSplitContainer.TabIndex = 6;
//
@ -221,10 +221,78 @@
//
this.leftSplitContainer.Panel1.Controls.Add(this.textBoxPanel);
this.leftSplitContainer.Panel1.Controls.Add(this.lineOpsPanel);
this.leftSplitContainer.Size = new System.Drawing.Size(627, 540);
this.leftSplitContainer.SplitterDistance = 451;
this.leftSplitContainer.Size = new System.Drawing.Size(627, 667);
this.leftSplitContainer.SplitterDistance = 443;
this.leftSplitContainer.TabIndex = 5;
//
// textBoxPanel
//
this.textBoxPanel.AutoScroll = true;
this.textBoxPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.textBoxPanel.Controls.Add(this.ebString);
this.textBoxPanel.Controls.Add(this.m12String);
this.textBoxPanel.Controls.Add(this.m12StringEnglish);
this.textBoxPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.textBoxPanel.Location = new System.Drawing.Point(0, 0);
this.textBoxPanel.Name = "textBoxPanel";
this.textBoxPanel.Size = new System.Drawing.Size(623, 406);
this.textBoxPanel.TabIndex = 10;
//
// ebString
//
this.ebString.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.ebString.Location = new System.Drawing.Point(3, 4);
this.ebString.Multiline = true;
this.ebString.Name = "ebString";
this.ebString.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.ebString.Size = new System.Drawing.Size(613, 128);
this.ebString.TabIndex = 9;
//
// m12String
//
this.m12String.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.m12String.Location = new System.Drawing.Point(3, 138);
this.m12String.Multiline = true;
this.m12String.Name = "m12String";
this.m12String.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.m12String.Size = new System.Drawing.Size(613, 128);
this.m12String.TabIndex = 10;
//
// m12StringEnglish
//
this.m12StringEnglish.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.m12StringEnglish.Location = new System.Drawing.Point(3, 272);
this.m12StringEnglish.Multiline = true;
this.m12StringEnglish.Name = "m12StringEnglish";
this.m12StringEnglish.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.m12StringEnglish.Size = new System.Drawing.Size(613, 128);
this.m12StringEnglish.TabIndex = 11;
//
// lineOpsPanel
//
this.lineOpsPanel.AutoSize = true;
this.lineOpsPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.lineOpsPanel.Controls.Add(this.copyCodesButton);
this.lineOpsPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
this.lineOpsPanel.Location = new System.Drawing.Point(0, 406);
this.lineOpsPanel.Name = "lineOpsPanel";
this.lineOpsPanel.Size = new System.Drawing.Size(623, 33);
this.lineOpsPanel.TabIndex = 9;
//
// copyCodesButton
//
this.copyCodesButton.AutoSize = true;
this.copyCodesButton.Location = new System.Drawing.Point(3, 3);
this.copyCodesButton.Name = "copyCodesButton";
this.copyCodesButton.Size = new System.Drawing.Size(124, 23);
this.copyCodesButton.TabIndex = 0;
this.copyCodesButton.Text = "Copy codes and labels";
this.copyCodesButton.UseVisualStyleBackColor = true;
this.copyCodesButton.Click += new System.EventHandler(this.copyCodesButton_Click);
//
// codeSplitContainer
//
this.codeSplitContainer.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
@ -242,22 +310,10 @@
//
this.codeSplitContainer.Panel2.Controls.Add(this.referenceList);
this.codeSplitContainer.Panel2.Controls.Add(this.label3);
this.codeSplitContainer.Size = new System.Drawing.Size(222, 507);
this.codeSplitContainer.SplitterDistance = 233;
this.codeSplitContainer.Size = new System.Drawing.Size(222, 634);
this.codeSplitContainer.SplitterDistance = 292;
this.codeSplitContainer.TabIndex = 1;
//
// codeList
//
this.codeList.BackColor = System.Drawing.SystemColors.Window;
this.codeList.Dock = System.Windows.Forms.DockStyle.Fill;
this.codeList.Location = new System.Drawing.Point(0, 19);
this.codeList.Multiline = true;
this.codeList.Name = "codeList";
this.codeList.ReadOnly = true;
this.codeList.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.codeList.Size = new System.Drawing.Size(218, 210);
this.codeList.TabIndex = 1;
//
// label2
//
this.label2.AutoSize = true;
@ -274,9 +330,10 @@
//
this.referenceList.Dock = System.Windows.Forms.DockStyle.Fill;
this.referenceList.FormattingEnabled = true;
this.referenceList.HorizontalScrollbar = true;
this.referenceList.Location = new System.Drawing.Point(0, 19);
this.referenceList.Name = "referenceList";
this.referenceList.Size = new System.Drawing.Size(218, 247);
this.referenceList.Size = new System.Drawing.Size(218, 315);
this.referenceList.TabIndex = 2;
this.referenceList.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.referenceList_MouseDoubleClick);
//
@ -333,7 +390,7 @@
//
this.statusBar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.statusLabel});
this.statusBar.Location = new System.Drawing.Point(0, 593);
this.statusBar.Location = new System.Drawing.Point(0, 720);
this.statusBar.Name = "statusBar";
this.statusBar.Size = new System.Drawing.Size(853, 22);
this.statusBar.TabIndex = 7;
@ -350,79 +407,21 @@
this.writeTimer.Interval = 10000;
this.writeTimer.Tick += new System.EventHandler(this.writeTimer_Tick);
//
// lineOpsPanel
// codeList
//
this.lineOpsPanel.AutoSize = true;
this.lineOpsPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.lineOpsPanel.Controls.Add(this.copyCodesButton);
this.lineOpsPanel.Dock = System.Windows.Forms.DockStyle.Bottom;
this.lineOpsPanel.Location = new System.Drawing.Point(0, 414);
this.lineOpsPanel.Name = "lineOpsPanel";
this.lineOpsPanel.Size = new System.Drawing.Size(623, 33);
this.lineOpsPanel.TabIndex = 9;
//
// textBoxPanel
//
this.textBoxPanel.AutoScroll = true;
this.textBoxPanel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.textBoxPanel.Controls.Add(this.ebString);
this.textBoxPanel.Controls.Add(this.m12String);
this.textBoxPanel.Controls.Add(this.m12StringEnglish);
this.textBoxPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.textBoxPanel.Location = new System.Drawing.Point(0, 0);
this.textBoxPanel.Name = "textBoxPanel";
this.textBoxPanel.Size = new System.Drawing.Size(623, 414);
this.textBoxPanel.TabIndex = 10;
//
// ebString
//
this.ebString.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.ebString.Location = new System.Drawing.Point(3, 4);
this.ebString.Multiline = true;
this.ebString.Name = "ebString";
this.ebString.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.ebString.Size = new System.Drawing.Size(613, 128);
this.ebString.TabIndex = 9;
//
// m12String
//
this.m12String.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.m12String.Location = new System.Drawing.Point(3, 138);
this.m12String.Multiline = true;
this.m12String.Name = "m12String";
this.m12String.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.m12String.Size = new System.Drawing.Size(613, 128);
this.m12String.TabIndex = 10;
//
// m12StringEnglish
//
this.m12StringEnglish.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.m12StringEnglish.Location = new System.Drawing.Point(3, 272);
this.m12StringEnglish.Multiline = true;
this.m12StringEnglish.Name = "m12StringEnglish";
this.m12StringEnglish.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.m12StringEnglish.Size = new System.Drawing.Size(613, 128);
this.m12StringEnglish.TabIndex = 11;
//
// copyCodesButton
//
this.copyCodesButton.AutoSize = true;
this.copyCodesButton.Location = new System.Drawing.Point(3, 3);
this.copyCodesButton.Name = "copyCodesButton";
this.copyCodesButton.Size = new System.Drawing.Size(124, 23);
this.copyCodesButton.TabIndex = 0;
this.copyCodesButton.Text = "Copy codes and labels";
this.copyCodesButton.UseVisualStyleBackColor = true;
this.copyCodesButton.Click += new System.EventHandler(this.copyCodesButton_Click);
this.codeList.Dock = System.Windows.Forms.DockStyle.Fill;
this.codeList.FormattingEnabled = true;
this.codeList.HorizontalScrollbar = true;
this.codeList.Location = new System.Drawing.Point(0, 19);
this.codeList.Name = "codeList";
this.codeList.Size = new System.Drawing.Size(218, 269);
this.codeList.TabIndex = 3;
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(853, 615);
this.ClientSize = new System.Drawing.Size(853, 742);
this.Controls.Add(this.mainPanel);
this.Controls.Add(this.topPanel);
this.Controls.Add(this.mainMenu);
@ -446,6 +445,10 @@
this.leftSplitContainer.Panel1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.leftSplitContainer)).EndInit();
this.leftSplitContainer.ResumeLayout(false);
this.textBoxPanel.ResumeLayout(false);
this.textBoxPanel.PerformLayout();
this.lineOpsPanel.ResumeLayout(false);
this.lineOpsPanel.PerformLayout();
this.codeSplitContainer.Panel1.ResumeLayout(false);
this.codeSplitContainer.Panel1.PerformLayout();
this.codeSplitContainer.Panel2.ResumeLayout(false);
@ -455,10 +458,6 @@
this.gameSelectorPanel.ResumeLayout(false);
this.statusBar.ResumeLayout(false);
this.statusBar.PerformLayout();
this.lineOpsPanel.ResumeLayout(false);
this.lineOpsPanel.PerformLayout();
this.textBoxPanel.ResumeLayout(false);
this.textBoxPanel.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@ -479,7 +478,6 @@
private System.Windows.Forms.SplitContainer mainSplitContainer;
private System.Windows.Forms.SplitContainer leftSplitContainer;
private System.Windows.Forms.SplitContainer codeSplitContainer;
private System.Windows.Forms.TextBox codeList;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.ListBox referenceList;
private System.Windows.Forms.Label label3;
@ -495,6 +493,7 @@
private System.Windows.Forms.TextBox m12StringEnglish;
private System.Windows.Forms.FlowLayoutPanel lineOpsPanel;
private System.Windows.Forms.Button copyCodesButton;
private System.Windows.Forms.ListBox codeList;
}
}

View File

@ -17,8 +17,10 @@ namespace ScriptToolGui
{
// Static/const members
const string workingFolder = @"..\..\..\..\working";
static M12Compiler m12Compiler = new M12Compiler();
static Compiler m12Compiler = new Compiler(M12ControlCode.Codes, (rom, address) => rom[address + 1] == 0xFF);
static Compiler ebCompiler = new Compiler(EbControlCode.Codes, (rom, address) => rom[address] < 0x20);
static readonly Game[] validGames;
static IDictionary<byte, string> ebCharLookup;
// Lookups
IDictionary<Game, TextBox> textboxLookup;
@ -46,6 +48,7 @@ namespace ScriptToolGui
static MainForm()
{
validGames = new Game[] { Game.Eb, Game.M12, Game.M12English };
ebCharLookup = JsonConvert.DeserializeObject<Dictionary<byte, string>>(File.ReadAllText("eb-char-lookup.json"));
}
public MainForm()
@ -169,22 +172,32 @@ namespace ScriptToolGui
private void PopulateCodeList()
{
codeList.Items.Clear();
ISet<IControlCode> codes = null;
if (ebSelector.Checked)
ebCompiler.ScanString(ebString.Text, ebCharLookup, true, out codes);
else if (m12Selector.Checked)
m12Compiler.ScanString(m12String.Text, ebCharLookup, true, out codes);
var sorted = codes.Distinct().OrderBy(c => c).ToArray();
codeList.Items.AddRange(sorted.ToArray());
}
private void PopulateReferenceList()
{
referenceList.Items.Clear();
IList<string> references = null;
if (ebSelector.Checked)
{
ebCompiler.ScanString(ebString.Text, ebCharLookup, true, out references);
}
else if (m12Selector.Checked)
{
var references = m12Compiler.ScanString(m12String.Text, true).Distinct().OrderBy(r => r);
referenceList.Items.AddRange(references.ToArray());
}
m12Compiler.ScanString(m12String.Text, ebCharLookup, true, out references);
references = references.Distinct().OrderBy(r => r).ToList();
referenceList.Items.AddRange(references.ToArray());
}
private string GetString(Game game, string label)
@ -446,6 +459,7 @@ namespace ScriptToolGui
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
writeTimer.Enabled = false;
WriteChanges();
}

View File

@ -59,6 +59,12 @@
<Compile Include="NavigationEntry.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StringPreviewer.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="StringPreviewer.Designer.cs">
<DependentUpon>StringPreviewer.cs</DependentUpon>
</Compile>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>

View File

@ -0,0 +1,37 @@
namespace ScriptToolGui
{
partial class StringPreviewer
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
}
#endregion
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ScriptToolGui
{
public partial class StringPreviewer : UserControl
{
public StringPreviewer()
{
InitializeComponent();
}
}
}