Added ScriptTool
This commit is contained in:
parent
acfe5ddb8e
commit
52900e9c50
|
@ -0,0 +1,22 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 2013
|
||||||
|
VisualStudioVersion = 12.0.31101.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptTool", "ScriptTool\ScriptTool.csproj", "{CA5C95AE-2CD2-47E3-B5AE-FE6136808AC4}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{CA5C95AE-2CD2-47E3-B5AE-FE6136808AC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CA5C95AE-2CD2-47E3-B5AE-FE6136808AC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CA5C95AE-2CD2-47E3-B5AE-FE6136808AC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CA5C95AE-2CD2-47E3-B5AE-FE6136808AC4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class CommandOptions
|
||||||
|
{
|
||||||
|
public string WorkingDirectory { get; set; }
|
||||||
|
public CommandType Command { get; set; }
|
||||||
|
public bool DoMiscText { get; set; }
|
||||||
|
public bool DoMainText { get; set; }
|
||||||
|
public string EbRom { get; set; }
|
||||||
|
public string M12Rom { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CommandType
|
||||||
|
{
|
||||||
|
Compile,
|
||||||
|
Decompile
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class ControlCode
|
||||||
|
{
|
||||||
|
public IList<byte> Identifier { get; private set; }
|
||||||
|
public bool End { get; set; }
|
||||||
|
public bool Multiple { get; set; }
|
||||||
|
public int Length { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
const string HexChars = "0123456789ABCDEFabcdef";
|
||||||
|
|
||||||
|
public ControlCode()
|
||||||
|
{
|
||||||
|
Identifier = new List<byte>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Match(byte[] rom, int address)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Identifier.Count; i++)
|
||||||
|
if (rom[address + i] != Identifier[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool BeginsWith(params byte[] bytes)
|
||||||
|
{
|
||||||
|
if (bytes.Length > Identifier.Count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var first = Identifier.Take(bytes.Length);
|
||||||
|
if (!first.SequenceEqual(bytes))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IList<ControlCode> LoadEbControlCodes(string path)
|
||||||
|
{
|
||||||
|
var codeList = new List<ControlCode>();
|
||||||
|
string[] lines = File.ReadAllLines(path);
|
||||||
|
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
var code = new ControlCode();
|
||||||
|
string def = line.Substring(0, line.IndexOf(','));
|
||||||
|
string desc = line.Substring(line.IndexOf(',') + 1);
|
||||||
|
code.Description = desc.Substring(1, desc.Length - 3);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (def.StartsWith("!"))
|
||||||
|
{
|
||||||
|
code.End = true;
|
||||||
|
def = def.Substring(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def.StartsWith("*"))
|
||||||
|
{
|
||||||
|
code.Multiple = true;
|
||||||
|
def = def.Substring(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] defs = def.Split(' ');
|
||||||
|
for (int i = 0; i < defs.Length; i++)
|
||||||
|
{
|
||||||
|
if (!HexChars.Contains(defs[i][0]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
code.Identifier.Add(byte.Parse(defs[i], System.Globalization.NumberStyles.HexNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code.Multiple)
|
||||||
|
code.Length = -1;
|
||||||
|
else
|
||||||
|
code.Length = defs.Length;
|
||||||
|
|
||||||
|
codeList.Add(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IList<ControlCode> LoadM12ControlCodes(string path)
|
||||||
|
{
|
||||||
|
var codeList = new List<ControlCode>();
|
||||||
|
string[] lines = File.ReadAllLines(path);
|
||||||
|
|
||||||
|
foreach (var line in lines)
|
||||||
|
{
|
||||||
|
var code = new ControlCode();
|
||||||
|
string def = line.Substring(0, line.IndexOf(','));
|
||||||
|
string desc = line.Substring(line.IndexOf(',') + 1);
|
||||||
|
code.Description = desc;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (def.StartsWith("!"))
|
||||||
|
{
|
||||||
|
code.End = true;
|
||||||
|
def = def.Substring(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def.StartsWith("*"))
|
||||||
|
{
|
||||||
|
code.Multiple = true;
|
||||||
|
def = def.Substring(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] defs = def.Split(' ');
|
||||||
|
code.Identifier.Add(byte.Parse(defs[0], System.Globalization.NumberStyles.HexNumber));
|
||||||
|
code.Identifier.Add(0xFF);
|
||||||
|
|
||||||
|
if (code.Multiple)
|
||||||
|
code.Length = -1;
|
||||||
|
else
|
||||||
|
code.Length = defs.Length;
|
||||||
|
|
||||||
|
codeList.Add(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class DecompileContext
|
||||||
|
{
|
||||||
|
public LabelMap LabelMap { get; private set; }
|
||||||
|
public IList<string> Strings { get; private set; }
|
||||||
|
|
||||||
|
public DecompileContext()
|
||||||
|
{
|
||||||
|
LabelMap = new LabelMap();
|
||||||
|
Strings = new List<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,324 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class EbTextDecompiler
|
||||||
|
{
|
||||||
|
private IList<ControlCode> _controlCodes;
|
||||||
|
public IList<ControlCode> ControlCodes
|
||||||
|
{
|
||||||
|
get { return _controlCodes; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
// Grab the jump table codes
|
||||||
|
foreach (var code in value)
|
||||||
|
{
|
||||||
|
if (code.BeginsWith(9))
|
||||||
|
jumpTableReturn = code;
|
||||||
|
|
||||||
|
if (code.BeginsWith(0x1f, 0xc0))
|
||||||
|
jumpTableNoReturn = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
_controlCodes = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ControlCode jumpTableReturn;
|
||||||
|
private ControlCode jumpTableNoReturn;
|
||||||
|
|
||||||
|
private const string charMapEb = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZØØØØØ`abcdefghijklmnopqrstuvwxyz{|}~\\";
|
||||||
|
|
||||||
|
private static string[][] compressedStringsEb;
|
||||||
|
private static IList<int[]> textRanges = new List<int[]>();
|
||||||
|
|
||||||
|
static EbTextDecompiler()
|
||||||
|
{
|
||||||
|
// Load compressed strings
|
||||||
|
compressedStringsEb = new string[3][];
|
||||||
|
string[] stringsFromFile = File.ReadAllLines(@"eb-compressed-strings.txt");
|
||||||
|
compressedStringsEb[0] = stringsFromFile.Take(0x100).ToArray();
|
||||||
|
compressedStringsEb[1] = stringsFromFile.Skip(0x100).Take(0x100).ToArray();
|
||||||
|
compressedStringsEb[2] = stringsFromFile.Skip(0x200).Take(0x100).ToArray();
|
||||||
|
|
||||||
|
// Load text ranges
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Decompile(byte[] rom, int[] addresses, DecompileContext context)
|
||||||
|
{
|
||||||
|
if (ControlCodes == null)
|
||||||
|
throw new Exception("Codelist is null");
|
||||||
|
|
||||||
|
// First pass -- define labels
|
||||||
|
foreach (var address in addresses)
|
||||||
|
context.LabelMap.Append(address);
|
||||||
|
|
||||||
|
foreach(var range in textRanges)
|
||||||
|
ScanAt(rom, range[0], range[1], context, ScanMode.FirstPass);
|
||||||
|
|
||||||
|
// Second pass -- decompile the strings
|
||||||
|
foreach (var range in textRanges)
|
||||||
|
ScanAt(rom, range[0], range[1], context, ScanMode.SecondPass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScanAt(byte[] rom, int startAddress, int endAddress, DecompileContext context, ScanMode mode, bool newLines = true)
|
||||||
|
{
|
||||||
|
bool ended = false;
|
||||||
|
bool foundMatch = false;
|
||||||
|
bool prev1902 = false;
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
int address = startAddress;
|
||||||
|
|
||||||
|
if (address == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Null pointer");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == ScanMode.FirstPass)
|
||||||
|
{
|
||||||
|
context.LabelMap.Append(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!ended)
|
||||||
|
{
|
||||||
|
// Check for label definition
|
||||||
|
if (mode == ScanMode.SecondPass && context.LabelMap.Labels.ContainsKey(address))
|
||||||
|
{
|
||||||
|
sb.Append("^" + context.LabelMap[address] + "^");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for control codes
|
||||||
|
|
||||||
|
// No codes begin with a value above 0x1F, so check for that first
|
||||||
|
if (rom[address] < 0x20)
|
||||||
|
{
|
||||||
|
// Loop through each control code until we find a match
|
||||||
|
foundMatch = false;
|
||||||
|
foreach (var code in ControlCodes)
|
||||||
|
{
|
||||||
|
if (code.Match(rom, address))
|
||||||
|
{
|
||||||
|
foundMatch = true;
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass && !IsCompressedCode(code))
|
||||||
|
{
|
||||||
|
// Output the start of the code block
|
||||||
|
sb.Append('[');
|
||||||
|
|
||||||
|
// Output the identifier bytes
|
||||||
|
sb.Append(String.Join(" ", code.Identifier.Select(b => b.ToString("X2")).ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the identifier bytes
|
||||||
|
address += code.Identifier.Count;
|
||||||
|
|
||||||
|
// Found a match -- check if it's variable-length
|
||||||
|
if (code.Multiple)
|
||||||
|
{
|
||||||
|
if (code.BeginsWith(9) ||
|
||||||
|
code.BeginsWith(0x1F, 0xC0))
|
||||||
|
{
|
||||||
|
int count = rom[address++];
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(count.ToString("X2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
int jump = rom.ReadSnesPointer(address);
|
||||||
|
address += 4;
|
||||||
|
|
||||||
|
context.LabelMap.Append(jump);
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass)
|
||||||
|
{
|
||||||
|
sb.Append(" _");
|
||||||
|
sb.Append(context.LabelMap[jump]);
|
||||||
|
sb.Append('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Check if it references any other addresses -- scan those too
|
||||||
|
if (code.BeginsWith(8) ||
|
||||||
|
code.BeginsWith(0xA) ||
|
||||||
|
code.BeginsWith(0x1B, 0x02) ||
|
||||||
|
code.BeginsWith(0x1B, 0x03) ||
|
||||||
|
code.BeginsWith(0x1F, 0x63))
|
||||||
|
{
|
||||||
|
// Single address at next byte
|
||||||
|
int jump = rom.ReadSnesPointer(address);
|
||||||
|
|
||||||
|
context.LabelMap.Append(jump);
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass)
|
||||||
|
{
|
||||||
|
sb.Append(" _");
|
||||||
|
sb.Append(context.LabelMap[jump]);
|
||||||
|
sb.Append('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (code.BeginsWith(0x1F, 0x66) ||
|
||||||
|
code.BeginsWith(6))
|
||||||
|
{
|
||||||
|
// Skip two bytes; single address afterwards
|
||||||
|
int jump = rom.ReadSnesPointer(address + 2);
|
||||||
|
|
||||||
|
context.LabelMap.Append(jump);
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(rom[address].ToString("X2"));
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(rom[address + 1].ToString("X2"));
|
||||||
|
|
||||||
|
sb.Append(" _");
|
||||||
|
sb.Append(context.LabelMap[jump]);
|
||||||
|
sb.Append('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (
|
||||||
|
code.BeginsWith(0x1F, 0x18) ||
|
||||||
|
code.BeginsWith(0x1F, 0x19))
|
||||||
|
{
|
||||||
|
// Check
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (mode == ScanMode.SecondPass &&
|
||||||
|
(code.BeginsWith(0x15) ||
|
||||||
|
code.BeginsWith(0x16) ||
|
||||||
|
code.BeginsWith(0x17)))
|
||||||
|
{
|
||||||
|
// Check for compressed codes
|
||||||
|
int bank = code.Identifier[0] - 0x15;
|
||||||
|
int index = rom[address];
|
||||||
|
sb.Append(compressedStringsEb[bank][index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Regular control code -- output the rest of the bytes
|
||||||
|
if (mode == ScanMode.SecondPass)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (code.Length - code.Identifier.Count); i++)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(rom[address + i].ToString("X2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the rest of the bytes
|
||||||
|
address += code.Length - code.Identifier.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass && !IsCompressedCode(code))
|
||||||
|
{
|
||||||
|
// Output the end of the code block
|
||||||
|
sb.Append(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
// End the block if necessary
|
||||||
|
if (address >= endAddress)
|
||||||
|
{
|
||||||
|
ended = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert a newline after each end code for readibility
|
||||||
|
if (mode == ScanMode.SecondPass && code.End && !prev1902)
|
||||||
|
{
|
||||||
|
sb.AppendLine();
|
||||||
|
/*sb.Append('(');
|
||||||
|
sb.Append(address.ToString("X"));
|
||||||
|
sb.Append(')');*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're in a menu string
|
||||||
|
if (code.BeginsWith(0x19, 0x02))
|
||||||
|
prev1902 = true;
|
||||||
|
else
|
||||||
|
prev1902 = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundMatch)
|
||||||
|
{
|
||||||
|
// Bad!
|
||||||
|
throw new Exception("Found unknown control code");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// It's not a control code -- just skip it
|
||||||
|
if (mode == ScanMode.SecondPass)
|
||||||
|
sb.Append(CharLookup(rom[address]));
|
||||||
|
|
||||||
|
address++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass)
|
||||||
|
context.Strings.Add(sb.ToString());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CharLookup(byte value)
|
||||||
|
{
|
||||||
|
if (value >= 0x8B && value <= 0x8F)
|
||||||
|
{
|
||||||
|
// Greek letters -- output hex literals instead
|
||||||
|
return "[" + value.ToString("X2") + "]";
|
||||||
|
}
|
||||||
|
else if (value == 0xAF)
|
||||||
|
{
|
||||||
|
// Musical note -- output \ instead of the garbage char that normally would get outputted
|
||||||
|
return "\\";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return charMapEb[value - 0x50].ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsCompressedCode(ControlCode code)
|
||||||
|
{
|
||||||
|
if (code.Identifier[0] == 0x15 || code.Identifier[0] == 0x16 ||
|
||||||
|
code.Identifier[0] == 0x17)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ScanMode
|
||||||
|
{
|
||||||
|
FirstPass,
|
||||||
|
SecondPass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class EbTextTables
|
||||||
|
{
|
||||||
|
public static MainStringRef[] ReadTptRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<MainStringRef>();
|
||||||
|
|
||||||
|
int address = 0xF8985;
|
||||||
|
int entries = 1584;
|
||||||
|
|
||||||
|
for (int i = 0; i < entries; i++)
|
||||||
|
{
|
||||||
|
int firstPointer = rom.ReadSnesPointer(address + 9);
|
||||||
|
if (firstPointer != 0)
|
||||||
|
refs.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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
address += 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MainStringRef[] ReadBattleActionRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<MainStringRef>();
|
||||||
|
int address = 0x157B68;
|
||||||
|
for (int i = 0; i < 318; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadSnesPointer(address + 4);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 4, OldPointer = pointer });
|
||||||
|
address += 12;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MainStringRef[] ReadPrayerRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<MainStringRef>();
|
||||||
|
int address = 0x4A309;
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadSnesPointer(address);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address, OldPointer = pointer });
|
||||||
|
address += 4;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MainStringRef[] ReadItemHelpRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<MainStringRef>();
|
||||||
|
int address = 0x155000;
|
||||||
|
for (int i = 0; i < 254; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadSnesPointer(address + 0x23);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 0x23, OldPointer = pointer });
|
||||||
|
address += 39;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MainStringRef[] ReadPsiHelpRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<MainStringRef>();
|
||||||
|
int address = 0x158A50;
|
||||||
|
for (int i = 0; i < 53; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadSnesPointer(address + 11);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 11, OldPointer = pointer });
|
||||||
|
address += 15;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MainStringRef[] ReadPhoneRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<MainStringRef>();
|
||||||
|
int address = 0x157AAE;
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadSnesPointer(address + 0x1B);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 0x1B, OldPointer = pointer });
|
||||||
|
address += 31;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MainStringRef[] ReadEnemyTextRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<MainStringRef>();
|
||||||
|
int address = 0x159589;
|
||||||
|
for (int i = 0; i < 231; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadSnesPointer(address + 0x2D);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 0x2D, OldPointer = pointer });
|
||||||
|
|
||||||
|
pointer = rom.ReadSnesPointer(address + 0x31);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 0x31, OldPointer = pointer });
|
||||||
|
|
||||||
|
address += 94;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
public static int ReadInt(this byte[] rom, int address)
|
||||||
|
{
|
||||||
|
int value = rom[address] |
|
||||||
|
(rom[address + 1] << 8) |
|
||||||
|
(rom[address + 2] << 16) |
|
||||||
|
(rom[address + 3] << 24);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ReadSnesPointer(this byte[] rom, int address)
|
||||||
|
{
|
||||||
|
int offset = rom.ReadInt(address);
|
||||||
|
if (offset == 0) return 0;
|
||||||
|
return offset - 0xC00000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ReadGbaPointer(this byte[] rom, int address)
|
||||||
|
{
|
||||||
|
int offset = rom.ReadInt(address);
|
||||||
|
if (offset == 0) return 0;
|
||||||
|
return offset & 0x1FFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class FixedStringCollection
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(JsonHexConverter))]
|
||||||
|
public int StringsLocation { get; set; }
|
||||||
|
|
||||||
|
public int NumEntries { get; set; }
|
||||||
|
public int EntryLength { get; set; }
|
||||||
|
public IList<FixedStringRef> StringRefs { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
public string New { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class LabelMap
|
||||||
|
{
|
||||||
|
public IDictionary<int, string> Labels { get; private set; }
|
||||||
|
private int counter = 0;
|
||||||
|
|
||||||
|
public LabelMap()
|
||||||
|
{
|
||||||
|
Labels = new Dictionary<int, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string this[int address]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Labels[address];
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Labels[address] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Append(int address)
|
||||||
|
{
|
||||||
|
if (!Labels.ContainsKey(address))
|
||||||
|
{
|
||||||
|
string newLabel = String.Concat("L", counter.ToString());
|
||||||
|
Labels.Add(address, newLabel);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
Labels.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,306 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class M12TextDecompiler
|
||||||
|
{
|
||||||
|
public IList<ControlCode> ControlCodes { get; set; }
|
||||||
|
private static string[] charMap;
|
||||||
|
private static IList<int[]> textRanges = new List<int[]>();
|
||||||
|
private static DecompileContext staticContext = new DecompileContext();
|
||||||
|
|
||||||
|
static M12TextDecompiler()
|
||||||
|
{
|
||||||
|
// Load strings
|
||||||
|
charMap = File.ReadAllLines("m12-text-table.txt");
|
||||||
|
|
||||||
|
// Load text ranges
|
||||||
|
textRanges.Add(new int[] { 0x3697F, 0x8C4B0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Decompile(byte[] rom, int[] addresses, DecompileContext context)
|
||||||
|
{
|
||||||
|
if (ControlCodes == null)
|
||||||
|
throw new Exception("Codelist is null");
|
||||||
|
|
||||||
|
// First pass -- define labels
|
||||||
|
foreach (var address in addresses)
|
||||||
|
context.LabelMap.Append(address);
|
||||||
|
|
||||||
|
foreach(var range in textRanges)
|
||||||
|
ScanAt(rom, range[0], range[1], context, ScanMode.FirstPass, false, false, false);
|
||||||
|
|
||||||
|
// Second pass -- decompile the strings
|
||||||
|
foreach (var range in textRanges)
|
||||||
|
ScanAt(rom, range[0], range[1], context, ScanMode.SecondPass, false, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ReadString(byte[] rom, int address, int endAddress, bool basicMode)
|
||||||
|
{
|
||||||
|
return ScanAt(rom, address, endAddress, null, ScanMode.ReadOnce, true, basicMode, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ScanAt(byte[] rom, int startAddress, int endAddress, DecompileContext context,
|
||||||
|
ScanMode mode, bool stopOnEnd, bool basicMode, bool newLines)
|
||||||
|
{
|
||||||
|
bool ended = false;
|
||||||
|
bool foundMatch = false;
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
int address = startAddress;
|
||||||
|
|
||||||
|
if (address == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Null pointer");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == ScanMode.FirstPass)
|
||||||
|
{
|
||||||
|
context.LabelMap.Append(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!ended)
|
||||||
|
{
|
||||||
|
// Check for label definition
|
||||||
|
if (mode == ScanMode.SecondPass && context.LabelMap.Labels.ContainsKey(address))
|
||||||
|
{
|
||||||
|
sb.Append("^" + context.LabelMap[address] + "^");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for control codes (unless it's in basic mode)
|
||||||
|
|
||||||
|
// No codes begin with a value above 0x1F, so check for that first
|
||||||
|
if (rom[address + 1] == 0xFF && (!basicMode || (basicMode && (rom[address] == 0))))
|
||||||
|
{
|
||||||
|
// Loop through each control code until we find a match
|
||||||
|
foundMatch = false;
|
||||||
|
foreach (var code in ControlCodes)
|
||||||
|
{
|
||||||
|
if (code.Match(rom, address))
|
||||||
|
{
|
||||||
|
foundMatch = true;
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
// Output the start of the code block
|
||||||
|
sb.Append('[');
|
||||||
|
|
||||||
|
// Output the identifier bytes
|
||||||
|
sb.Append(String.Join(" ", code.Identifier.Select(b => b.ToString("X2")).ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the identifier bytes
|
||||||
|
address += code.Identifier.Count;
|
||||||
|
|
||||||
|
// Found a match -- check if it's variable-length
|
||||||
|
if (code.Multiple)
|
||||||
|
{
|
||||||
|
if (code.BeginsWith(0x95) ||
|
||||||
|
code.BeginsWith(0xBD))
|
||||||
|
{
|
||||||
|
int count = rom[address++];
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(count.ToString("X2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
int jump = rom.ReadInt(address);
|
||||||
|
jump += address;
|
||||||
|
|
||||||
|
address += 4;
|
||||||
|
|
||||||
|
context.LabelMap.Append(jump);
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
sb.Append(" _");
|
||||||
|
sb.Append(context.LabelMap[jump]);
|
||||||
|
sb.Append('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Check if it references any other addresses -- scan those too
|
||||||
|
if (code.BeginsWith(0x04) ||
|
||||||
|
code.BeginsWith(0x05) ||
|
||||||
|
code.BeginsWith(0x80) ||
|
||||||
|
code.BeginsWith(0x81) ||
|
||||||
|
code.BeginsWith(0x82) ||
|
||||||
|
code.BeginsWith(0x86))
|
||||||
|
{
|
||||||
|
// Single relative address at next byte
|
||||||
|
int jump = rom.ReadInt(address);
|
||||||
|
jump += address;
|
||||||
|
|
||||||
|
context.LabelMap.Append(jump);
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
sb.Append(" _");
|
||||||
|
sb.Append(context.LabelMap[jump]);
|
||||||
|
sb.Append('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (code.BeginsWith(0x1C))
|
||||||
|
{
|
||||||
|
// Skip two bytes; single relative address afterwards
|
||||||
|
int jump = rom.ReadInt(address + 2);
|
||||||
|
jump += address + 2;
|
||||||
|
|
||||||
|
context.LabelMap.Append(jump);
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(rom[address].ToString("X2"));
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(rom[address + 1].ToString("X2"));
|
||||||
|
|
||||||
|
sb.Append(" _");
|
||||||
|
sb.Append(context.LabelMap[jump]);
|
||||||
|
sb.Append('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (code.BeginsWith(0x9D))
|
||||||
|
{
|
||||||
|
// Skip two bytes; single absolute address afterwards
|
||||||
|
int jump = rom.ReadGbaPointer(address + 2);
|
||||||
|
|
||||||
|
context.LabelMap.Append(jump);
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(rom[address].ToString("X2"));
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(rom[address + 1].ToString("X2"));
|
||||||
|
|
||||||
|
sb.Append(" _");
|
||||||
|
sb.Append(context.LabelMap[jump]);
|
||||||
|
sb.Append('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (code.BeginsWith(0xA2))
|
||||||
|
{
|
||||||
|
// Single absolute address at next byte
|
||||||
|
int jump = rom.ReadGbaPointer(address);
|
||||||
|
|
||||||
|
context.LabelMap.Append(jump);
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
sb.Append(" _");
|
||||||
|
sb.Append(context.LabelMap[jump]);
|
||||||
|
sb.Append('_');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Regular control code -- output the rest of the bytes
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (code.Length - code.Identifier.Count); i++)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(rom[address + i].ToString("X2"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the rest of the bytes
|
||||||
|
address += code.Length - code.Identifier.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
// Output the end of the code block
|
||||||
|
sb.Append(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
// End the block if necessary
|
||||||
|
if (stopOnEnd && code.End)
|
||||||
|
{
|
||||||
|
ended = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert a newline after each end code for readibility
|
||||||
|
if (newLines && (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce) && code.End)
|
||||||
|
{
|
||||||
|
sb.AppendLine();
|
||||||
|
/*sb.Append('(');
|
||||||
|
sb.Append(address.ToString("X"));
|
||||||
|
sb.Append(')');*/
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundMatch)
|
||||||
|
{
|
||||||
|
// Bad!
|
||||||
|
throw new Exception("Found unknown control code");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// It's not a control code -- just skip it
|
||||||
|
if (mode == ScanMode.SecondPass || mode == ScanMode.ReadOnce)
|
||||||
|
{
|
||||||
|
if (!basicMode || (basicMode && (rom[address] != 0xFF)))
|
||||||
|
sb.Append(CharLookup(rom[address]));
|
||||||
|
}
|
||||||
|
|
||||||
|
address++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((endAddress != -1) && (address >= endAddress))
|
||||||
|
ended = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == ScanMode.SecondPass)
|
||||||
|
context.Strings.Add(sb.ToString());
|
||||||
|
|
||||||
|
else if (mode == ScanMode.ReadOnce)
|
||||||
|
return sb.ToString();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CharLookup(byte value)
|
||||||
|
{
|
||||||
|
if ((value >= 83 && value <= 95) ||
|
||||||
|
(value >= 180 && value <= 191) ||
|
||||||
|
value == 255)
|
||||||
|
{
|
||||||
|
// Invalid
|
||||||
|
throw new Exception("Invalid character");
|
||||||
|
}
|
||||||
|
|
||||||
|
return charMap[value];
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ScanMode
|
||||||
|
{
|
||||||
|
FirstPass,
|
||||||
|
SecondPass,
|
||||||
|
ReadOnce
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,233 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class M12TextTables
|
||||||
|
{
|
||||||
|
private static int[] StupidIndices =
|
||||||
|
{
|
||||||
|
0xB9, 0xBF, 0xC0, 0x164, 0x169,
|
||||||
|
0x16D, 0x16F, 0x171, 0x1B0, 0x1B1,
|
||||||
|
0x1B3, 0x1C1, 0x233, 0x239, 0x247,
|
||||||
|
0x286, 0x2AD, 0x2AE, 0x2AF, 0x2E7,
|
||||||
|
0x30A, 0x318, 0x3E1, 0x458, 0x45D,
|
||||||
|
0x48C, 0x48D, 0x514, 0x515, 0x516,
|
||||||
|
0x57D
|
||||||
|
};
|
||||||
|
|
||||||
|
public static MainStringRef[] ReadTptRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<MainStringRef>();
|
||||||
|
|
||||||
|
int address = 0x8EB14;
|
||||||
|
int entries = 1584;
|
||||||
|
|
||||||
|
for (int i = 0; i < entries; i++)
|
||||||
|
{
|
||||||
|
if (StupidIndices.Contains(i))
|
||||||
|
{
|
||||||
|
int firstPointer = rom.ReadGbaPointer(address + 9);
|
||||||
|
if (firstPointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 9, OldPointer = firstPointer });
|
||||||
|
|
||||||
|
byte type = rom[address];
|
||||||
|
if (type != 2)
|
||||||
|
{
|
||||||
|
int secondPointer = rom.ReadGbaPointer(address + 13);
|
||||||
|
if (secondPointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 13, OldPointer = secondPointer });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int firstPointer = rom.ReadGbaPointer(address + 12);
|
||||||
|
if (firstPointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 12, OldPointer = firstPointer });
|
||||||
|
|
||||||
|
byte type = rom[address];
|
||||||
|
if (type != 2)
|
||||||
|
{
|
||||||
|
int secondPointer = rom.ReadGbaPointer(address + 16);
|
||||||
|
if (secondPointer != 0)
|
||||||
|
refs.Add(new MainStringRef { Index = i, PointerLocation = address + 16, OldPointer = secondPointer });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
address += 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*public static StringRef[] ReadBattleActionRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<StringRef>();
|
||||||
|
int address = 0x157B68;
|
||||||
|
for (int i = 0; i < 318; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadPointer(address + 4);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new StringRef { Index = i, PointerLocation = address + 4, OldPointer = pointer });
|
||||||
|
address += 12;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringRef[] ReadPrayerRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<StringRef>();
|
||||||
|
int address = 0x4A309;
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadPointer(address);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new StringRef { Index = i, PointerLocation = address, OldPointer = pointer });
|
||||||
|
address += 4;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringRef[] ReadItemHelpRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<StringRef>();
|
||||||
|
int address = 0x155000;
|
||||||
|
for (int i = 0; i < 254; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadPointer(address + 0x23);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new StringRef { Index = i, PointerLocation = address + 0x23, OldPointer = pointer });
|
||||||
|
address += 39;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringRef[] ReadPsiHelpRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<StringRef>();
|
||||||
|
int address = 0x158A50;
|
||||||
|
for (int i = 0; i < 53; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadPointer(address + 11);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new StringRef { Index = i, PointerLocation = address + 11, OldPointer = pointer });
|
||||||
|
address += 15;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringRef[] ReadPhoneRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<StringRef>();
|
||||||
|
int address = 0x157AAE;
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadPointer(address + 0x1B);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new StringRef { Index = i, PointerLocation = address + 0x1B, OldPointer = pointer });
|
||||||
|
address += 31;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringRef[] ReadEnemyTextRefs(byte[] rom)
|
||||||
|
{
|
||||||
|
var refs = new List<StringRef>();
|
||||||
|
int address = 0x159589;
|
||||||
|
for (int i = 0; i < 231; i++)
|
||||||
|
{
|
||||||
|
int pointer = rom.ReadPointer(address + 0x2D);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new StringRef { Index = i, PointerLocation = address + 0x2D, OldPointer = pointer });
|
||||||
|
|
||||||
|
pointer = rom.ReadPointer(address + 0x31);
|
||||||
|
if (pointer != 0)
|
||||||
|
refs.Add(new StringRef { Index = i, PointerLocation = address + 0x31, OldPointer = pointer });
|
||||||
|
|
||||||
|
address += 94;
|
||||||
|
}
|
||||||
|
return refs.ToArray();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public static MiscStringCollection ReadPointerTable(byte[] rom, int tableAddress, int stringsAddress)
|
||||||
|
{
|
||||||
|
var refs = new List<MiscStringRef>();
|
||||||
|
int entries = rom.ReadInt(tableAddress);
|
||||||
|
|
||||||
|
int currentTableAddress = tableAddress;
|
||||||
|
currentTableAddress += 4;
|
||||||
|
|
||||||
|
for (int i = 0; i < entries; i++)
|
||||||
|
{
|
||||||
|
int offset = rom.ReadInt(currentTableAddress);
|
||||||
|
refs.Add(new MiscStringRef
|
||||||
|
{
|
||||||
|
OffsetLocation = currentTableAddress,
|
||||||
|
OldPointer = offset + stringsAddress,
|
||||||
|
Index = i
|
||||||
|
});
|
||||||
|
currentTableAddress += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MiscStringCollection
|
||||||
|
{
|
||||||
|
OffsetTableLocation = tableAddress,
|
||||||
|
StringsLocation = stringsAddress,
|
||||||
|
StringRefs = refs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FixedStringCollection ReadFixedStringTable(byte[] rom, int stringsAddress, int numEntries, int entryLength)
|
||||||
|
{
|
||||||
|
var refs = new List<FixedStringRef>();
|
||||||
|
int currentStringAddress = stringsAddress;
|
||||||
|
|
||||||
|
for(int i=0;i<numEntries;i++)
|
||||||
|
{
|
||||||
|
refs.Add(new FixedStringRef
|
||||||
|
{
|
||||||
|
OldPointer = currentStringAddress,
|
||||||
|
Index = i
|
||||||
|
});
|
||||||
|
currentStringAddress += entryLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FixedStringCollection
|
||||||
|
{
|
||||||
|
StringsLocation = stringsAddress,
|
||||||
|
NumEntries = numEntries,
|
||||||
|
EntryLength = entryLength,
|
||||||
|
StringRefs = refs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MiscStringCollection ReadItemNames(byte[] rom)
|
||||||
|
{
|
||||||
|
return ReadPointerTable(rom, 0xB1AF94, 0xB1A694);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MiscStringCollection ReadMenuChoices(byte[] rom)
|
||||||
|
{
|
||||||
|
return ReadPointerTable(rom, 0xB19A64, 0xB198B4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MiscStringCollection ReadMiscText(byte[] rom)
|
||||||
|
{
|
||||||
|
var miscStrings = ReadPointerTable(rom, 0xB17EE4, 0xB17424);
|
||||||
|
|
||||||
|
// Flag basic mode refs
|
||||||
|
for (int i = 0x4A; i <= 0x55; i++)
|
||||||
|
miscStrings.StringRefs[i].BasicMode = true;
|
||||||
|
|
||||||
|
return miscStrings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FixedStringCollection ReadPsiNames(byte[] rom)
|
||||||
|
{
|
||||||
|
return ReadFixedStringTable(rom, 0xB1B916, 0x12, 0xD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class MiscStringCollection
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(JsonHexConverter))]
|
||||||
|
public int OffsetTableLocation { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(JsonHexConverter))]
|
||||||
|
public int StringsLocation { get; set; }
|
||||||
|
|
||||||
|
public IList<MiscStringRef> StringRefs { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
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; }
|
||||||
|
public string Old { get; set; }
|
||||||
|
public string New { get; set; }
|
||||||
|
|
||||||
|
public bool ShouldSerializeBasicMode()
|
||||||
|
{
|
||||||
|
return BasicMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,250 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace ScriptTool
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static IList<ControlCode> EbControlCodes = new List<ControlCode>();
|
||||||
|
static IList<ControlCode> M12ControlCodes = new List<ControlCode>();
|
||||||
|
|
||||||
|
// Decompiler setup
|
||||||
|
static EbTextDecompiler ebDecompiler;
|
||||||
|
static M12TextDecompiler m12Decompiler;
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
CommandOptions options = ParseCommandLine(args);
|
||||||
|
if (options == null)
|
||||||
|
{
|
||||||
|
Usage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadControlCodes();
|
||||||
|
|
||||||
|
if (options.Command == CommandType.Decompile)
|
||||||
|
{
|
||||||
|
ebDecompiler = new EbTextDecompiler() { ControlCodes = EbControlCodes };
|
||||||
|
m12Decompiler = new M12TextDecompiler() { ControlCodes = M12ControlCodes };
|
||||||
|
|
||||||
|
// Load ROMs
|
||||||
|
byte[] ebRom = File.ReadAllBytes(options.EbRom);
|
||||||
|
byte[] m12Rom = File.ReadAllBytes(options.M12Rom);
|
||||||
|
|
||||||
|
// Decompile misc string tables
|
||||||
|
if (options.DoMiscText)
|
||||||
|
{
|
||||||
|
DecompileEbMisc(ebRom, options.WorkingDirectory);
|
||||||
|
DecompileM12Misc(m12Rom, options.WorkingDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decompile main string tables
|
||||||
|
if (options.DoMainText)
|
||||||
|
{
|
||||||
|
DecompileEb(ebRom, options.WorkingDirectory);
|
||||||
|
DecompileM12(m12Rom, options.WorkingDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (options.Command == CommandType.Compile)
|
||||||
|
{
|
||||||
|
// TBD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Usage()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Usage:");
|
||||||
|
Console.WriteLine(" ScriptTool.exe [-decompile or -compile] [-misc] [-main] workingdirectory [ebrom m12rom]");;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CommandOptions ParseCommandLine(string[] args)
|
||||||
|
{
|
||||||
|
var argList = new List<string>(args);
|
||||||
|
|
||||||
|
// Check for decompile switch
|
||||||
|
CommandType command;
|
||||||
|
if (argList.Contains("-decompile") && !argList.Contains("-compile"))
|
||||||
|
{
|
||||||
|
command = CommandType.Decompile;
|
||||||
|
argList.Remove("-decompile");
|
||||||
|
}
|
||||||
|
else if (argList.Contains("-compile") && !argList.Contains("-decompile"))
|
||||||
|
{
|
||||||
|
command = CommandType.Compile;
|
||||||
|
argList.Remove("-compile");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for main and misc flags
|
||||||
|
bool doMain = false;
|
||||||
|
bool doMisc = false;
|
||||||
|
if (argList.Contains("-main"))
|
||||||
|
{
|
||||||
|
doMain = true;
|
||||||
|
argList.Remove("-main");
|
||||||
|
}
|
||||||
|
if (argList.Contains("-misc"))
|
||||||
|
{
|
||||||
|
doMisc = true;
|
||||||
|
argList.Remove("-misc");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for working directory
|
||||||
|
if (argList.Count < 1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
string working = argList[0];
|
||||||
|
if (!Directory.Exists(working))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Check for ROM paths
|
||||||
|
string ebRom = null;
|
||||||
|
string m12Rom = null;
|
||||||
|
if (command == CommandType.Decompile && argList.Count == 3)
|
||||||
|
{
|
||||||
|
ebRom = argList[1];
|
||||||
|
m12Rom = argList[2];
|
||||||
|
if (!File.Exists(ebRom) || !File.Exists(m12Rom))
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CommandOptions
|
||||||
|
{
|
||||||
|
WorkingDirectory = working,
|
||||||
|
EbRom = ebRom,
|
||||||
|
M12Rom = m12Rom,
|
||||||
|
Command = command,
|
||||||
|
DoMainText = doMain,
|
||||||
|
DoMiscText = doMisc
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LoadControlCodes()
|
||||||
|
{
|
||||||
|
EbControlCodes = ControlCode.LoadEbControlCodes("eb-codelist.txt");
|
||||||
|
M12ControlCodes = ControlCode.LoadM12ControlCodes("m12-codelist.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DecompileEb(byte[] ebRom, string workingDirectory)
|
||||||
|
{
|
||||||
|
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)));
|
||||||
|
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)));
|
||||||
|
allRefs.Add(Tuple.Create("eb-psi-help", EbTextTables.ReadPsiHelpRefs(ebRom)));
|
||||||
|
allRefs.Add(Tuple.Create("eb-phone", EbTextTables.ReadPhoneRefs(ebRom)));
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
File.WriteAllText(Path.Combine(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));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DecompileEbMisc(byte[] ebRom, string workingDirectory)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DecompileM12(byte[] m12Rom, string workingDirectory)
|
||||||
|
{
|
||||||
|
|
||||||
|
var context = new DecompileContext();
|
||||||
|
|
||||||
|
// Pull all string refs from the ROM
|
||||||
|
var allRefs = new List<Tuple<string, MainStringRef[]>>();
|
||||||
|
allRefs.Add(Tuple.Create("m12-tpt", M12TextTables.ReadTptRefs(m12Rom)));
|
||||||
|
|
||||||
|
// Decompile
|
||||||
|
var allPointers = allRefs.SelectMany(rl => rl.Item2).Select(r => r.OldPointer).ToArray();
|
||||||
|
m12Decompiler.Decompile(m12Rom, allPointers, context);
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
File.WriteAllText(Path.Combine(workingDirectory, refList.Item1 + ".json"), JsonConvert.SerializeObject(refList.Item2, Formatting.Indented));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the strings
|
||||||
|
File.WriteAllText(Path.Combine(workingDirectory, "m12-strings.txt"), String.Join(Environment.NewLine, context.Strings));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DecompileM12Misc(byte[] m12Rom, string workingDirectory)
|
||||||
|
{
|
||||||
|
// Item names
|
||||||
|
var itemNames = M12TextTables.ReadItemNames(m12Rom);
|
||||||
|
DecompileM12MiscStringCollection(m12Rom, workingDirectory, "m12-itemnames", itemNames);
|
||||||
|
|
||||||
|
// Menu choices
|
||||||
|
var menuChoices = M12TextTables.ReadMenuChoices(m12Rom);
|
||||||
|
DecompileM12MiscStringCollection(m12Rom, workingDirectory, "m12-menuchoices", menuChoices);
|
||||||
|
|
||||||
|
// Misc text
|
||||||
|
var miscText = M12TextTables.ReadMiscText(m12Rom);
|
||||||
|
DecompileM12MiscStringCollection(m12Rom, workingDirectory, "m12-misctext", miscText);
|
||||||
|
|
||||||
|
// PSI names
|
||||||
|
var psiNames = M12TextTables.ReadPsiNames(m12Rom);
|
||||||
|
DecompileM12FixedStringCollection(m12Rom, workingDirectory, "m12-psinames", psiNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DecompileM12MiscStringCollection(byte[] rom, string workingDirectory, string name, MiscStringCollection miscStringCollection)
|
||||||
|
{
|
||||||
|
// Decompile the strings
|
||||||
|
foreach (var miscStringRef in miscStringCollection.StringRefs)
|
||||||
|
{
|
||||||
|
miscStringRef.Old =
|
||||||
|
miscStringRef.New =
|
||||||
|
m12Decompiler.ReadString(rom, miscStringRef.OldPointer, -1, miscStringRef.BasicMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write JSON
|
||||||
|
File.WriteAllText(Path.Combine(workingDirectory, name + ".json"), JsonConvert.SerializeObject(miscStringCollection, Formatting.Indented));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DecompileM12FixedStringCollection(byte[] rom, string workingDirectory, string name, FixedStringCollection fixedStringCollection)
|
||||||
|
{
|
||||||
|
// Decompile the strings
|
||||||
|
foreach (var fixedStringRef in fixedStringCollection.StringRefs)
|
||||||
|
{
|
||||||
|
fixedStringRef.Old =
|
||||||
|
fixedStringRef.New =
|
||||||
|
m12Decompiler.ReadString(rom, fixedStringRef.OldPointer,
|
||||||
|
fixedStringRef.OldPointer + fixedStringCollection.EntryLength,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write JSON
|
||||||
|
File.WriteAllText(Path.Combine(workingDirectory, name + ".json"), JsonConvert.SerializeObject(fixedStringCollection, Formatting.Indented));
|
||||||
|
}
|
||||||
|
|
||||||
|
//static void CompileM12Misc()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("ScriptTool")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("ScriptTool")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("04d88ce9-e4a3-457b-9f74-959ddf16f81d")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{CA5C95AE-2CD2-47E3-B5AE-FE6136808AC4}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>ScriptTool</RootNamespace>
|
||||||
|
<AssemblyName>ScriptTool</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="CommandOptions.cs" />
|
||||||
|
<Compile Include="ControlCode.cs" />
|
||||||
|
<Compile Include="DecompileContext.cs" />
|
||||||
|
<Compile Include="FixedStringCollection.cs" />
|
||||||
|
<Compile Include="M12TextTables.cs" />
|
||||||
|
<Compile Include="M12TextDecompiler.cs" />
|
||||||
|
<Compile Include="EbTextDecompiler.cs" />
|
||||||
|
<Compile Include="Extensions.cs" />
|
||||||
|
<Compile Include="JsonHexConverter.cs" />
|
||||||
|
<Compile Include="LabelMap.cs" />
|
||||||
|
<Compile Include="MiscStringCollection.cs" />
|
||||||
|
<Compile Include="FixedStringRef.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="EbTextTables.cs" />
|
||||||
|
<Compile Include="MiscStringRef.cs" />
|
||||||
|
<Compile Include="MainStringRef.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<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-codelist.txt">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="m12-text-table.txt">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,216 @@
|
||||||
|
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";
|
|
@ -0,0 +1,768 @@
|
||||||
|
|
||||||
|
in the
|
||||||
|
that
|
||||||
|
...
|
||||||
|
and
|
||||||
|
this
|
||||||
|
to the
|
||||||
|
about
|
||||||
|
just
|
||||||
|
of the
|
||||||
|
something
|
||||||
|
going to
|
||||||
|
to
|
||||||
|
you have
|
||||||
|
your
|
||||||
|
for
|
||||||
|
you're
|
||||||
|
@You
|
||||||
|
really
|
||||||
|
don't
|
||||||
|
@The
|
||||||
|
e the
|
||||||
|
e you
|
||||||
|
...
|
||||||
|
the
|
||||||
|
will
|
||||||
|
...Brick Road
|
||||||
|
ing
|
||||||
|
some
|
||||||
|
|
||||||
|
@Do you want to
|
||||||
|
like
|
||||||
|
ou don't have
|
||||||
|
is
|
||||||
|
you
|
||||||
|
you
|
||||||
|
anything else
|
||||||
|
the
|
||||||
|
you want to
|
||||||
|
for the
|
||||||
|
friend
|
||||||
|
at the
|
||||||
|
ould you like
|
||||||
|
from
|
||||||
|
would
|
||||||
|
he Runaway Five
|
||||||
|
with
|
||||||
|
want to
|
||||||
|
@If you
|
||||||
|
you don't
|
||||||
|
s the
|
||||||
|
ed to
|
||||||
|
e...
|
||||||
|
something
|
||||||
|
t the
|
||||||
|
@...
|
||||||
|
@Please
|
||||||
|
's
|
||||||
|
of your
|
||||||
|
@It's
|
||||||
|
@Thank you
|
||||||
|
@I
|
||||||
|
here.
|
||||||
|
in
|
||||||
|
@Do you
|
||||||
|
I'll
|
||||||
|
have
|
||||||
|
e of
|
||||||
|
d you
|
||||||
|
@I'm
|
||||||
|
me to
|
||||||
|
@I don't
|
||||||
|
@Well,
|
||||||
|
@This is
|
||||||
|
ed the
|
||||||
|
@You're
|
||||||
|
for a
|
||||||
|
anything
|
||||||
|
ing
|
||||||
|
of
|
||||||
|
you should
|
||||||
|
I
|
||||||
|
from the
|
||||||
|
s...
|
||||||
|
it's
|
||||||
|
time
|
||||||
|
e to
|
||||||
|
ed
|
||||||
|
e of the
|
||||||
|
to you
|
||||||
|
n't you
|
||||||
|
again
|
||||||
|
for you.
|
||||||
|
other
|
||||||
|
ation
|
||||||
|
little
|
||||||
|
ing to
|
||||||
|
can't
|
||||||
|
much
|
||||||
|
someone
|
||||||
|
on the
|
||||||
|
looks like
|
||||||
|
don't you
|
||||||
|
very
|
||||||
|
the
|
||||||
|
can
|
||||||
|
you
|
||||||
|
that you
|
||||||
|
it
|
||||||
|
you want
|
||||||
|
ou can't
|
||||||
|
able to
|
||||||
|
already
|
||||||
|
give you
|
||||||
|
understand
|
||||||
|
|
||||||
|
my
|
||||||
|
you can
|
||||||
|
that
|
||||||
|
what
|
||||||
|
here's
|
||||||
|
there
|
||||||
|
n the
|
||||||
|
@What
|
||||||
|
Thank you
|
||||||
|
I can't
|
||||||
|
one
|
||||||
|
@The
|
||||||
|
thought
|
||||||
|
not
|
||||||
|
You should
|
||||||
|
ou know
|
||||||
|
has
|
||||||
|
back
|
||||||
|
of
|
||||||
|
ve been
|
||||||
|
I'm
|
||||||
|
there
|
||||||
|
with you
|
||||||
|
@I heard
|
||||||
|
in
|
||||||
|
here
|
||||||
|
Fourside
|
||||||
|
I wonder
|
||||||
|
to
|
||||||
|
could
|
||||||
|
think
|
||||||
|
out
|
||||||
|
good
|
||||||
|
the
|
||||||
|
You
|
||||||
|
too much
|
||||||
|
ome back
|
||||||
|
t...
|
||||||
|
here
|
||||||
|
thing
|
||||||
|
come
|
||||||
|
ly
|
||||||
|
ent
|
||||||
|
strong
|
||||||
|
money.
|
||||||
|
@I'll
|
||||||
|
an
|
||||||
|
ou must
|
||||||
|
are you
|
||||||
|
with the
|
||||||
|
on your
|
||||||
|
too many
|
||||||
|
you.
|
||||||
|
know
|
||||||
|
to be
|
||||||
|
around
|
||||||
|
if you
|
||||||
|
@Are you
|
||||||
|
ome again
|
||||||
|
e and
|
||||||
|
more
|
||||||
|
think
|
||||||
|
e your
|
||||||
|
@Don't
|
||||||
|
nd the
|
||||||
|
t to
|
||||||
|
rea
|
||||||
|
he
|
||||||
|
me
|
||||||
|
strange
|
||||||
|
for you
|
||||||
|
ight
|
||||||
|
a
|
||||||
|
be
|
||||||
|
ther
|
||||||
|
all
|
||||||
|
cannot
|
||||||
|
here is
|
||||||
|
You have
|
||||||
|
Monotoli
|
||||||
|
was
|
||||||
|
ll you
|
||||||
|
hat
|
||||||
|
, but
|
||||||
|
stuff
|
||||||
|
eep
|
||||||
|
it
|
||||||
|
didn't
|
||||||
|
like th
|
||||||
|
ll right
|
||||||
|
should
|
||||||
|
over
|
||||||
|
@Oh,
|
||||||
|
hear
|
||||||
|
every
|
||||||
|
I'm not
|
||||||
|
about t
|
||||||
|
zombies
|
||||||
|
damage
|
||||||
|
his is
|
||||||
|
all
|
||||||
|
some
|
||||||
|
@It
|
||||||
|
attack
|
||||||
|
right
|
||||||
|
ally
|
||||||
|
orry
|
||||||
|
ess
|
||||||
|
er
|
||||||
|
@That's
|
||||||
|
carry it
|
||||||
|
ake
|
||||||
|
t was
|
||||||
|
, the
|
||||||
|
n you
|
||||||
|
sn't
|
||||||
|
help
|
||||||
|
king
|
||||||
|
ear
|
||||||
|
ing the
|
||||||
|
It's
|
||||||
|
very
|
||||||
|
talking
|
||||||
|
ou've
|
||||||
|
that's
|
||||||
|
to me
|
||||||
|
@Hello
|
||||||
|
enemy
|
||||||
|
you are
|
||||||
|
by
|
||||||
|
IBNT
|
||||||
|
ight
|
||||||
|
on't
|
||||||
|
est
|
||||||
|
ick
|
||||||
|
power
|
||||||
|
s that
|
||||||
|
s are
|
||||||
|
call
|
||||||
|
t is
|
||||||
|
is
|
||||||
|
age
|
||||||
|
, and
|
||||||
|
great
|
||||||
|
@Thanks
|
||||||
|
people
|
||||||
|
ter
|
||||||
|
not
|
||||||
|
ill
|
||||||
|
ness
|
||||||
|
@This
|
||||||
|
into
|
||||||
|
ha
|
||||||
|
I can
|
||||||
|
t your
|
||||||
|
before
|
||||||
|
things
|
||||||
|
tion
|
||||||
|
for
|
||||||
|
be
|
||||||
|
this
|
||||||
|
Happy
|
||||||
|
You
|
||||||
|
out
|
||||||
|
enough
|
||||||
|
I'm
|
||||||
|
@You
|
||||||
|
go
|
||||||
|
for
|
||||||
|
all th
|
||||||
|
though
|
||||||
|
ing you
|
||||||
|
e you
|
||||||
|
ring
|
||||||
|
one
|
||||||
|
get
|
||||||
|
t you
|
||||||
|
@I'm s
|
||||||
|
the s
|
||||||
|
e's
|
||||||
|
port
|
||||||
|
d...
|
||||||
|
out
|
||||||
|
@What
|
||||||
|
get
|
||||||
|
I have
|
||||||
|
looking
|
||||||
|
n this
|
||||||
|
of my
|
||||||
|
have a
|
||||||
|
ent
|
||||||
|
do
|
||||||
|
d of
|
||||||
|
ting
|
||||||
|
ncrease
|
||||||
|
Twoson
|
||||||
|
through
|
||||||
|
s your
|
||||||
|
ou'll
|
||||||
|
place
|
||||||
|
right
|
||||||
|
Onett
|
||||||
|
|
||||||
|
our
|
||||||
|
too
|
||||||
|
ater
|
||||||
|
be
|
||||||
|
ain
|
||||||
|
ing.
|
||||||
|
take
|
||||||
|
e is
|
||||||
|
the
|
||||||
|
please
|
||||||
|
do you
|
||||||
|
need
|
||||||
|
use
|
||||||
|
now.
|
||||||
|
got
|
||||||
|
|
||||||
|
and
|
||||||
|
ning
|
||||||
|
sta
|
||||||
|
the t
|
||||||
|
I was
|
||||||
|
y the
|
||||||
|
his
|
||||||
|
appe
|
||||||
|
con
|
||||||
|
ho
|
||||||
|
hat's
|
||||||
|
Threed
|
||||||
|
get
|
||||||
|
s of
|
||||||
|
inter
|
||||||
|
talk
|
||||||
|
man
|
||||||
|
day
|
||||||
|
ove
|
||||||
|
ha ha
|
||||||
|
inally
|
||||||
|
monkey
|
||||||
|
s and
|
||||||
|
ate
|
||||||
|
see
|
||||||
|
town
|
||||||
|
side
|
||||||
|
y to
|
||||||
|
ever
|
||||||
|
equip
|
||||||
|
than
|
||||||
|
who
|
||||||
|
long
|
||||||
|
care
|
||||||
|
room
|
||||||
|
e are
|
||||||
|
ard
|
||||||
|
end
|
||||||
|
, you
|
||||||
|
the b
|
||||||
|
I know
|
||||||
|
think
|
||||||
|
s you
|
||||||
|
time
|
||||||
|
ment
|
||||||
|
so
|
||||||
|
!
|
||||||
|
I've
|
||||||
|
ell
|
||||||
|
wa
|
||||||
|
ious
|
||||||
|
reat
|
||||||
|
live
|
||||||
|
ange
|
||||||
|
we
|
||||||
|
ble
|
||||||
|
@.....
|
||||||
|
ecover
|
||||||
|
only
|
||||||
|
thing
|
||||||
|
er...
|
||||||
|
Mr.
|
||||||
|
ough
|
||||||
|
now
|
||||||
|
I
|
||||||
|
wor
|
||||||
|
to
|
||||||
|
ed.
|
||||||
|
I
|
||||||
|
're
|
||||||
|
give
|
||||||
|
ing a
|
||||||
|
return
|
||||||
|
better
|
||||||
|
ince
|
||||||
|
well
|
||||||
|
one
|
||||||
|
still
|
||||||
|
ying
|
||||||
|
me...
|
||||||
|
sta
|
||||||
|
ust
|
||||||
|
per
|
||||||
|
lease
|
||||||
|
ling
|
||||||
|
point
|
||||||
|
ect
|
||||||
|
ast
|
||||||
|
pretty
|
||||||
|
Giygas
|
||||||
|
ecause
|
||||||
|
member
|
||||||
|
carry
|
||||||
|
used
|
||||||
|
elieve
|
||||||
|
money
|
||||||
|
pres
|
||||||
|
way
|
||||||
|
di
|
||||||
|
even
|
||||||
|
ound
|
||||||
|
s to
|
||||||
|
ting
|
||||||
|
ted
|
||||||
|
oing
|
||||||
|
and
|
||||||
|
ine
|
||||||
|
T
|
||||||
|
sure
|
||||||
|
on
|
||||||
|
@...I
|
||||||
|
while
|
||||||
|
@but
|
||||||
|
@We
|
||||||
|
ice
|
||||||
|
se
|
||||||
|
ive
|
||||||
|
rea
|
||||||
|
com
|
||||||
|
est
|
||||||
|
have
|
||||||
|
but
|
||||||
|
away
|
||||||
|
here
|
||||||
|
must
|
||||||
|
but
|
||||||
|
want
|
||||||
|
ready
|
||||||
|
I'm
|
||||||
|
carr
|
||||||
|
my
|
||||||
|
ay...
|
||||||
|
are
|
||||||
|
@Hey,
|
||||||
|
world
|
||||||
|
ing a
|
||||||
|
happ
|
||||||
|
seem
|
||||||
|
his
|
||||||
|
nder
|
||||||
|
se
|
||||||
|
ant
|
||||||
|
item
|
||||||
|
@But
|
||||||
|
sho
|
||||||
|
in a
|
||||||
|
made
|
||||||
|
night
|
||||||
|
et's
|
||||||
|
like
|
||||||
|
The
|
||||||
|
che
|
||||||
|
de
|
||||||
|
ful
|
||||||
|
hat
|
||||||
|
and
|
||||||
|
self
|
||||||
|
ould
|
||||||
|
@No
|
||||||
|
car
|
||||||
|
tr
|
||||||
|
good
|
||||||
|
stor
|
||||||
|
ombie
|
||||||
|
@Oh
|
||||||
|
@It
|
||||||
|
s a
|
||||||
|
vent
|
||||||
|
ant
|
||||||
|
so
|
||||||
|
olla
|
||||||
|
ree
|
||||||
|
Your
|
||||||
|
make
|
||||||
|
work
|
||||||
|
power
|
||||||
|
home
|
||||||
|
also
|
||||||
|
ance
|
||||||
|
@How
|
||||||
|
h...
|
||||||
|
@If
|
||||||
|
ple
|
||||||
|
buy
|
||||||
|
e,
|
||||||
|
n't
|
||||||
|
oke
|
||||||
|
n't
|
||||||
|
more
|
||||||
|
Good
|
||||||
|
t a
|
||||||
|
all
|
||||||
|
take
|
||||||
|
round
|
||||||
|
when
|
||||||
|
name
|
||||||
|
being
|
||||||
|
attle
|
||||||
|
ite
|
||||||
|
ack
|
||||||
|
y...
|
||||||
|
@Whe
|
||||||
|
with
|
||||||
|
al
|
||||||
|
have
|
||||||
|
look
|
||||||
|
t of
|
||||||
|
aster
|
||||||
|
a lo
|
||||||
|
feel
|
||||||
|
here
|
||||||
|
count
|
||||||
|
monst
|
||||||
|
now
|
||||||
|
ark
|
||||||
|
ous
|
||||||
|
'll
|
||||||
|
bus
|
||||||
|
head
|
||||||
|
any
|
||||||
|
t you
|
||||||
|
erson
|
||||||
|
after
|
||||||
|
ummer
|
||||||
|
hard
|
||||||
|
ful
|
||||||
|
ever
|
||||||
|
kid
|
||||||
|
a b
|
||||||
|
kay
|
||||||
|
tra
|
||||||
|
pla
|
||||||
|
ook
|
||||||
|
ome
|
||||||
|
eat
|
||||||
|
@Wel
|
||||||
|
off
|
||||||
|
turn
|
||||||
|
I am
|
||||||
|
oney
|
||||||
|
any
|
||||||
|
ave
|
||||||
|
any
|
||||||
|
enem
|
||||||
|
con
|
||||||
|
me
|
||||||
|
red
|
||||||
|
en
|
||||||
|
bo
|
||||||
|
re
|
||||||
|
ell
|
||||||
|
sell
|
||||||
|
what
|
||||||
|
next
|
||||||
|
ure
|
||||||
|
bu
|
||||||
|
pro
|
||||||
|
on
|
||||||
|
res
|
||||||
|
es
|
||||||
|
lo
|
||||||
|
our
|
||||||
|
use
|
||||||
|
iste
|
||||||
|
ood
|
||||||
|
no
|
||||||
|
ope
|
||||||
|
ock
|
||||||
|
row
|
||||||
|
@He
|
||||||
|
how
|
||||||
|
may
|
||||||
|
as
|
||||||
|
stor
|
||||||
|
are
|
||||||
|
ost
|
||||||
|
mean
|
||||||
|
We
|
||||||
|
He
|
||||||
|
@An
|
||||||
|
it
|
||||||
|
in
|
||||||
|
ound
|
||||||
|
one.
|
||||||
|
come
|
||||||
|
blue
|
||||||
|
way,
|
||||||
|
or
|
||||||
|
mo
|
||||||
|
.
|
||||||
|
each
|
||||||
|
some
|
||||||
|
@(Th
|
||||||
|
otel
|
||||||
|
hand
|
||||||
|
came
|
||||||
|
ca
|
||||||
|
ame
|
||||||
|
@Hey
|
||||||
|
een
|
||||||
|
spec
|
||||||
|
red
|
||||||
|
ing!
|
||||||
|
...
|
||||||
|
hose
|
||||||
|
ind
|
||||||
|
ice
|
||||||
|
ver
|
||||||
|
W
|
||||||
|
min
|
||||||
|
et
|
||||||
|
on
|
||||||
|
ace
|
||||||
|
er.
|
||||||
|
are
|
||||||
|
nter
|
||||||
|
o...
|
||||||
|
were
|
||||||
|
help
|
||||||
|
old
|
||||||
|
it.
|
||||||
|
hear
|
||||||
|
stop
|
||||||
|
look
|
||||||
|
com
|
||||||
|
@Do
|
||||||
|
her
|
||||||
|
pro
|
||||||
|
chin
|
||||||
|
ble
|
||||||
|
e a
|
||||||
|
girl
|
||||||
|
luck
|
||||||
|
B
|
||||||
|
act
|
||||||
|
ike
|
||||||
|
down
|
||||||
|
part
|
||||||
|
see
|
||||||
|
use
|
||||||
|
uch
|
||||||
|
from
|
||||||
|
just
|
||||||
|
llow
|
||||||
|
@Her
|
||||||
|
at
|
||||||
|
@So,
|
||||||
|
ye
|
||||||
|
ser
|
||||||
|
ying
|
||||||
|
ring
|
||||||
|
eave
|
||||||
|
big
|
||||||
|
ried
|
||||||
|
was
|
||||||
|
say
|
||||||
|
su
|
||||||
|
her
|
||||||
|
it.
|
||||||
|
Man
|
||||||
|
kin
|
||||||
|
up
|
||||||
|
ers
|
||||||
|
@Why
|
||||||
|
p...
|
||||||
|
cour
|
||||||
|
him
|
||||||
|
agic
|
||||||
|
any
|
||||||
|
fin
|
||||||
|
eal
|
||||||
|
he
|
||||||
|
ide
|
||||||
|
oor
|
||||||
|
ity
|
||||||
|
got
|
||||||
|
ens
|
||||||
|
ish
|
||||||
|
ive
|
||||||
|
sa
|
||||||
|
oon
|
||||||
|
fee
|
||||||
|
s a
|
||||||
|
nce
|
||||||
|
D
|
||||||
|
uck
|
||||||
|
ass
|
||||||
|
man
|
||||||
|
a p
|
||||||
|
@(I
|
||||||
|
@Wh
|
||||||
|
gu
|
||||||
|
(
|
||||||
|
bus
|
||||||
|
los
|
||||||
|
ts
|
||||||
|
ba
|
||||||
|
S
|
||||||
|
if
|
||||||
|
@Ha
|
||||||
|
ma
|
||||||
|
unn
|
||||||
|
ay
|
||||||
|
ner
|
||||||
|
@A
|
||||||
|
or
|
||||||
|
stu
|
||||||
|
ust
|
||||||
|
kya
|
||||||
|
shi
|
||||||
|
pos
|
||||||
|
A
|
||||||
|
int
|
||||||
|
le
|
||||||
|
ary
|
||||||
|
ven
|
||||||
|
ch
|
||||||
|
own
|
||||||
|
hu
|
||||||
|
@My
|
||||||
|
@So
|
||||||
|
sp
|
||||||
|
sh
|
||||||
|
wan
|
||||||
|
ool
|
||||||
|
Y
|
||||||
|
old
|
||||||
|
eas
|
||||||
|
, I
|
||||||
|
iki
|
||||||
|
@Ky
|
||||||
|
@Ye
|
||||||
|
spi
|
|
@ -0,0 +1,198 @@
|
||||||
|
!00 FF,End (02)
|
||||||
|
01 FF,New line (00)
|
||||||
|
02 FF,Prompt + new line (03 00)
|
||||||
|
03 FF XX XX,Display menu string set {0:X}
|
||||||
|
04 FF XX XX XX XX,Jump to offset {0:X} if first choice selected
|
||||||
|
05 FF XX XX XX XX,Jump to offset {0:X} if second choice selected
|
||||||
|
08 FF XX XX,Set flag {0:X} (04)
|
||||||
|
09 FF XX XX,Unset flag {0:X} (05)
|
||||||
|
0C FF,Party leader's name
|
||||||
|
0D FF,Ness' name (1C 02 01 or 1C 01 08)
|
||||||
|
0E FF,Paula's name (1C 02 02)
|
||||||
|
0F FF,Jeff's name (1C 02 03)
|
||||||
|
10 FF,Poo's name (1C 02 04)
|
||||||
|
11 FF,Favorite food (1C 01 04)
|
||||||
|
12 FF,Favorite thing (1C 01 05)
|
||||||
|
14 FF XX XX,Teleport to entry {0:X} (1F 21)
|
||||||
|
15 FF,King's name (1C 02 07)
|
||||||
|
!18 FF XX XX,Unknown
|
||||||
|
1A FF XX XX,Display string {0:X}? (Appears after 90 FF)
|
||||||
|
1B FF XX XX,Pause for {0:X} frames (10)
|
||||||
|
1C FF XX XX YY YY YY YY,If flag {0:X} is set, jump to offset {1:X} and return (06)
|
||||||
|
1D FF,Wait without prompt (13)
|
||||||
|
1E FF XX XX,Return one letter from a character's name (19 11)
|
||||||
|
1F FF XX XX,Display text character {0:X} (1C 03)
|
||||||
|
20 FF,Display SMAAASH!! graphics (1C 08 01)
|
||||||
|
21 FF,Display YOU WIN! graphics (1C 08 02)
|
||||||
|
22 FF,Unknown
|
||||||
|
23 FF,Display cash in ATM (1C 01 07)
|
||||||
|
24 FF,Display character 1 defense (1C 01 12)
|
||||||
|
25 FF,Display character 2 defense (1C 01 28)
|
||||||
|
26 FF,Display character 3 defense (1C 01 3E)
|
||||||
|
27 FF,Display character 4 defense (1C 01 54)
|
||||||
|
28 FF,Display character 1 offense (1C 01 11)
|
||||||
|
29 FF,Display character 2 offense (1C 01 27)
|
||||||
|
2A FF,Display character 3 offense (1C 01 3D)
|
||||||
|
2B FF,Display character 4 offense (1C 01 53)
|
||||||
|
2D FF,Display PSI name? (1C 12 00)
|
||||||
|
2E FF,Show main text window (18 01 01)
|
||||||
|
5F FF XX,Set the current rendering location to {0:X} (custom code)
|
||||||
|
60 FF XX,Add {0:X} pixels to the current rendering location (custom code)
|
||||||
|
61 FF XX XX,Toggles sound for text printing (?) (1F 04)
|
||||||
|
62 FF,Display inventory? (?)
|
||||||
|
63 FF,Display cash on hand (1C 01 06)
|
||||||
|
64 FF,Call special event (value pushed with FC FF?) (1F 41)
|
||||||
|
65 FF,Purge all NPCs from party (1F 64)
|
||||||
|
66 FF,Unknown (19 1E)
|
||||||
|
67 FF,Unknown (19 28)
|
||||||
|
68 FF,Clear main text window (sometimes used in place of 18 01 01)
|
||||||
|
69 FF,Open party HP/PP status windows (1C 04)
|
||||||
|
6A FF XX XX,Set binary flag if number in memory != {0:X} (0C)
|
||||||
|
6B FF XX XX,Apply audio effect {0:X} (1F 07)
|
||||||
|
6C FF XX XX YY YY,Sets binary flag true if character {0:X} does not have item {1:X} (1D 04)
|
||||||
|
6D FF XX XX YY YY,Remove item {1:X} from character {0:X}'s inventory (1D 01)
|
||||||
|
6E FF XX XX,Deactivate hotspot {0:X} (1F 67)
|
||||||
|
6F FF XX XX YY YY,Boost vitality in character {0:X} by {1:X} (1E 0D, values match)
|
||||||
|
70 FF XX XX YY YY,Boost speed in character {0:X} by {1:X} (1E 0C, values match)
|
||||||
|
71 FF XX XX YY YY,Boost guts in character {0:X} by {1:X} (1E 0B, values match)
|
||||||
|
72 FF XX XX YY YY,Boost IQ in character {0:X} by {1:X} (1E 0A, values match)
|
||||||
|
73 FF XX XX YY YY,Boost luck in character {0:X} by {1:X} (1E 0E, values match)
|
||||||
|
74 FF,Stop music (1F 01 00)
|
||||||
|
75 FF,Unknown (?)
|
||||||
|
76 FF XX XX,Show window flavor menu? Argument seems to tell it which string to start with (so a value of 1 will skip the first flavor and show the remaining 6)
|
||||||
|
77 FF XX XX,Unknown (1D 18, values match)
|
||||||
|
78 FF XX XX YY YY,Unknown (19 1D, values match)
|
||||||
|
79 FF XX XX YY YY,Unknown (19 1C, values match)
|
||||||
|
7A FF XX XX,Unknown (19 1A, values match)
|
||||||
|
7B FF,Change to Mr. Saturn font (1F 31)
|
||||||
|
7C FF,Change to normal font (1F 30)
|
||||||
|
7D FF,Activate bicycle (1F F0)
|
||||||
|
7E FF XX XX,Unknown (19 26)
|
||||||
|
7F FF,Save the game in the slot selected at the beginning (1F B0)
|
||||||
|
!80 FF XX XX XX XX,Jump to offset {0:X} and don't return (0A)
|
||||||
|
81 FF XX XX XX XX,If binary flag is set, jump to offset {0:X} and return (1B 03)
|
||||||
|
82 FF XX XX XX XX,If binary flag is unset, jump to offset {0:X} and return (1B 02)
|
||||||
|
83 FF XX XX,Set binary flag to status of flag {0:X} (07)
|
||||||
|
84 FF XX XX YY YY ZZ ZZ,Generate TPT entry {0:X} with movement pattern {1:X} using style {2:X} (1F 17)
|
||||||
|
85 FF XX XX YY YY,Make TPT entry {0:X} disappear via style {1:X} (1F 1E)
|
||||||
|
86 FF XX XX XX XX,Jump to offset {0:X} and return (08)
|
||||||
|
87 FF,Swap working and argumentary memory (1B 04)
|
||||||
|
88 FF,Copy all memory to storage (1B 00)
|
||||||
|
89 FF,Copy all storage to memory (1B 01)
|
||||||
|
8A FF,Copy active memory to working memory (1B 05)
|
||||||
|
8B FF,Copy working memory to active memory (1B 06)
|
||||||
|
8C FF,Unknown (1F A2)
|
||||||
|
8D FF XX XX,Load character number in party position {0:X} (19 10)
|
||||||
|
8E FF,TPT entry being spoken to/checked faces downwards (1F A0)
|
||||||
|
8F FF,Change direction of current TPT entry to down (1F A1)
|
||||||
|
90 FF XX,Load character/item name {0:X} into memory (?)
|
||||||
|
91 FF XX,Set binary flag if character {0:X} has free space in their inventory (1D 03)
|
||||||
|
92 FF XX YY YY,Set binary flag true if character {0:X} has ailment {1:X} (corresponds exactly to 1D 0D XX YY YY)
|
||||||
|
93 FF XX YY,Add item {1:X} to character {0:X}'s inventory and return number of items held (1D 0E)
|
||||||
|
94 FF XX,Display shop window {0:X} (1A 06)
|
||||||
|
*95 FF,Jump table with return (09)
|
||||||
|
96 FF XX,Set binary flag if there are {0:X} party members (1D 19)
|
||||||
|
97 FF XX,Set binary flag if character {0:X} does not have free space in their inventory (1D 02)
|
||||||
|
98 FF XX,Return price of item {0:X} (1D 0A)
|
||||||
|
99 FF XX XX XX XX,Sets binary flag if the player currently holds {0:X} in the wallet (1D 14)
|
||||||
|
9A FF XX XX,Set binary flag if number in memory == {0:X} (0B)
|
||||||
|
9B FF XX XX XX XX,Remove {0:X} dollars from wallet (1D 09)
|
||||||
|
9C FF,Open wallet window and display current cash on hand (18 0A)
|
||||||
|
9D FF XX YY ZZ ZZ ZZ ZZ,Activate hotspot {0:X} with address ${2:X} (1F 66)
|
||||||
|
9E FF,Simultaneously commences all prepared movements (1F 61)
|
||||||
|
9F FF,Display action user name (1C 0D)
|
||||||
|
A0 FF XX XX YY YY ZZ ZZ,Generate sprite {0:X} with movement pattern {1:X} using style {2:X} (1F 15)
|
||||||
|
A1 FF XX XX YY YY,Apply movement pattern {1:X} to TPT entry {0:X} (1F F1)
|
||||||
|
A2 FF XX XX XX XX,After finishing this text block, close all other windows, jump to offset {0:X} and don't return (?)
|
||||||
|
A3 FF XX XX,Restrict player movement until end of text block (1F E9, use 9E FF after)
|
||||||
|
A4 FF XX XX,Delay appearance of TPT entry {0:X} until end of text parsing (1F E6)
|
||||||
|
A5 FF XX XX YY YY,Delete A0 FF-generated sprite {0:X} via style {1:X} (1F 1F)
|
||||||
|
A6 FF XX XX YY YY,Apply movement pattern {1:X} to sprite {0:X} (1F F2)
|
||||||
|
A7 FF XX XX,Trigger battle with enemy group entry {0:X} (1F 23)
|
||||||
|
A8 FF XX,Copy from memory {0:X} into argumentative memory (0D)
|
||||||
|
A9 FF XX XX,Unknown (1F EA, values don't match)
|
||||||
|
AA FF XX XX,Unknown (1F E7, values don't match)
|
||||||
|
AB FF XX YY,Copies item {1:X} from character {0:X}'s inventory into working memory (19 19)
|
||||||
|
AC FF,Unknown (1C 0F)
|
||||||
|
AD FF,Display action target name (1C 0E)
|
||||||
|
AE FF XX,Add character {0:X} to party (1F 11)
|
||||||
|
AF FF XX,Remove character {0:X} from party (1F 12)
|
||||||
|
B0 FF XX XX YY YY,Generate sprite {1:X} near TPT entry {0:X} (1F 1A)
|
||||||
|
B1 FF XX XX YY YY,Generate sprite {1:X} near sprite {0:X} (1F F3)
|
||||||
|
B2 FF XX XX YY YY,Generate sprite {1:X} near character {0:X} (1F 1C)
|
||||||
|
B3 FF XX XX,Delete B0 FF sprite near TPT entry {0:X} (1F 1B)
|
||||||
|
B4 FF XX XX,Delete B1 FF sprite near sprite {0:X} (1F F4)
|
||||||
|
B5 FF XX XX,Delete B2 FF sprite near character {0:X} (1F 1D)
|
||||||
|
B6 FF XX YY,Display the inventory of character {1:X} in window {0:X} (1A 05, values match)
|
||||||
|
B7 FF XX,Return half-price of item {0:X} (1D 0B)
|
||||||
|
B8 FF XX,Load {0:X} into memory as a decimal string (related to 1C 0A)
|
||||||
|
B9 FF XX XX YY YY,Unknown (1D 0F)
|
||||||
|
BA FF XX XX XX XX,Add {0:X} dollars to wallet (1D 08)
|
||||||
|
BB FF XX,Multiply {0:X} by the number of characters in the party, and store in working memory (1D 15)
|
||||||
|
BC FF XX XX,Input {0:X} into memory bank (0E)
|
||||||
|
*BD FF,Jump table with return (1F C0)
|
||||||
|
BE FF XX XX YY YY,Set binary flag if character {0:X} has item {1:X} (1D 05)
|
||||||
|
BF FF,Unknown (19 20)
|
||||||
|
C0 FF,Increment secondary memory (0F)
|
||||||
|
C1 FF,Unknown (19 1F)
|
||||||
|
C2 FF,Unknown, appears before 1A FF 05 00 (1C 11 69)
|
||||||
|
C3 FF XX XX YY YY,Store to memory the direction from character {0:X} to object {1:X} (19 22)
|
||||||
|
C4 FF XX YY,Play music {1:X} (1F 00)
|
||||||
|
C5 FF,Return music to sector default (1F 03)
|
||||||
|
C6 FF,Close all windows (18 04)
|
||||||
|
C7 FF,Close most recently-used window (18 00)
|
||||||
|
C8 FF XX XX,Number selector with {0:X} digits (1F 52)
|
||||||
|
C9 FF XX XX,Focuses the camera to where A0 FF-generated sprite {0:X} is but doesn't follow it (1F EF)
|
||||||
|
CA FF,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 ED)
|
||||||
|
CB FF XX XX YY YY,Make character {0:X} disappear via style {1:X} (1F EB)
|
||||||
|
CC FF XX XX YY YY,Make character {0:X} appear via style {1:X} (1F EC)
|
||||||
|
CD FF XX XX YY YY ZZ ZZ,Change map palette to that of tileset {0:X}, palette {1:X} at speed {2:X} (1F E1)
|
||||||
|
CE FF XX XX YY YY,Turn TPT entry {0:X} to direction {1:X} (1F 16)
|
||||||
|
CF FF XX XX,Trigger timed event {0:X} (1F D3)
|
||||||
|
D0 FF XX XX XX XX,Sets binary flag true if the player currently holds {0:X} in the ATM (1D 17)
|
||||||
|
D1 FF XX XX XX XX,Add {0:X} dollars to ATM balance (1D 06)
|
||||||
|
D3 FF XX XX,Remove {0:X} dollars from ATM balance? (1D 07)
|
||||||
|
D4 FF XX XX,Play sound effect {0:X} (1F 02)
|
||||||
|
D5 FF XX XX,Unknown (1D 23, value matches)
|
||||||
|
D6 FF XX XX YY YY,Unknown (1D 11, value matches)
|
||||||
|
D7 FF XX XX YY YY,Equip character {0:X} with their {1:X}'th item (1F 83)
|
||||||
|
D8 FF XX XX YY YY,Turn character {0:X} to direction {1:X} (1F 13)
|
||||||
|
D9 FF XX XX,Unknown (1F 14 XX)
|
||||||
|
DA FF XX XX YY YY,Unknown (occurs after A0 FF and DC FF)
|
||||||
|
DB FF XX XX YY YY ZZ ZZ,Store to memory the direction from TPT entry {0:X} to object {1:X} (ZZ unknown) (19 23)
|
||||||
|
DC FF XX XX YY YY ZZ ZZ,Unknown (sandwiched between DA FF codes?)
|
||||||
|
DD FF XX XX XX XX YY YY YY YY,Check for {0:X} inequality to memory (18 07)
|
||||||
|
DE FF,Unknown (?)
|
||||||
|
DF FF,Open non-working phone window (1A 0A)
|
||||||
|
E0 FF XX XX,May relate to returning cash earned since last phone call to dad (1D 24, value matches)
|
||||||
|
E1 FF XX XX,Unknown (19 18, value matches)
|
||||||
|
E2 FF XX XX,Summon photographer to location {0:X} (1F D2)
|
||||||
|
E3 FF,Unknown (19 21 00)
|
||||||
|
E4 FF,Unknown (19 25 00)
|
||||||
|
E5 FF,Check same user/target (1D 20)
|
||||||
|
E6 FF XX XX,Unknown (1F EE, value matches)
|
||||||
|
E7 FF XX XX,Show Mach Pizza window? Different arguments yield different menu strings (02 = full A menu, 03 = A menu sans PSI, and more)
|
||||||
|
E8 FF XX XX YY YY,Character {0:X} realizes special PSI {1:X} (1F 71)
|
||||||
|
E9 FF XX XX YY YY YY YY,Character {0:X} gains {1:X} EXP (1E 09)
|
||||||
|
EA FF XX XX,Lock player movement (1F E5, value matches)
|
||||||
|
EB FF XX XX,Restrict player movement if camera is focused on other sprite (XX is usually FF) (1F E8)
|
||||||
|
EC FF,Display party select menu? (1A 01)
|
||||||
|
ED FF XX XX YY YY,Return byte {1:X} of character {0:X} status (19 16, values match)
|
||||||
|
EE FF XX XX YY YY ZZ ZZ,Inflict ailment {1:X} on character {0:X} (ZZ might possibly be the value to set? 0 for off, 1 for on) (YY and ZZ flipped w.r.t EB) (19 05)
|
||||||
|
EF FF XX XX YY YY,PSI Teleport to destination {0:X} using method {1:X} (1F 20, values match)
|
||||||
|
F0 FF XX XX YY YY,Display animation {0:X} (YY is usually 00) (1C 13)
|
||||||
|
F1 FF,Show Escargo Express window? ([18 02][1A 07][18 03 0D][18 00][18 03 01][01])
|
||||||
|
F2 FF XX XX XX XX,Unknown (1D 13, values match)
|
||||||
|
F3 FF XX XX XX XX,Unknown (1D 12, values match)
|
||||||
|
F4 FF XX XX YY YY,Unknown (1D 0C, values match)
|
||||||
|
F5 FF,Unknown (19 14)
|
||||||
|
F6 FF XX XX,Generate random number from 0 to {0:X} (1D 21)
|
||||||
|
F7 FF XX XX YY YY,Character {0:X} recovers HP by {1:X} of max (1E 00)
|
||||||
|
F8 FF XX XX YY YY,Character {0:X} recovers PP by {1:X} of max (1E 04)
|
||||||
|
F9 FF XX XX YY YY,Character {0:X} recovers HP by {1:X} of max (not sure of the difference with F7 FF) (1E 00)
|
||||||
|
FA FF XX XX YY YY,Character {0:X} recovers PP by {1:X} of max (not sure of the difference with F8 FF) (1E 04)
|
||||||
|
FB FF XX XX,Attempt to fix items (1F D0)
|
||||||
|
FC FF XX XX,Unknown; load some kind of value into memory? Observed: [FC FF 06 00] [64 FF] == [1F 41 06]
|
||||||
|
FD FF,Set binary flag if current sector is Exit mouse-compatible (1D 22)
|
||||||
|
FE FF,Store current coordinates into memory (1F 68)
|
||||||
|
FF FF,Returns a numeric value based on the proximity of a magic truffle TPT entry (1F D1)
|
|
@ -0,0 +1,256 @@
|
||||||
|
ぁ
|
||||||
|
あ
|
||||||
|
ぃ
|
||||||
|
い
|
||||||
|
ぅ
|
||||||
|
う
|
||||||
|
ぇ
|
||||||
|
え
|
||||||
|
ぉ
|
||||||
|
お
|
||||||
|
か
|
||||||
|
が
|
||||||
|
き
|
||||||
|
ぎ
|
||||||
|
く
|
||||||
|
ぐ
|
||||||
|
け
|
||||||
|
げ
|
||||||
|
こ
|
||||||
|
ご
|
||||||
|
さ
|
||||||
|
ざ
|
||||||
|
し
|
||||||
|
じ
|
||||||
|
す
|
||||||
|
ず
|
||||||
|
せ
|
||||||
|
ぜ
|
||||||
|
そ
|
||||||
|
ぞ
|
||||||
|
た
|
||||||
|
だ
|
||||||
|
ち
|
||||||
|
ぢ
|
||||||
|
っ
|
||||||
|
つ
|
||||||
|
づ
|
||||||
|
て
|
||||||
|
で
|
||||||
|
と
|
||||||
|
ど
|
||||||
|
な
|
||||||
|
に
|
||||||
|
ぬ
|
||||||
|
ね
|
||||||
|
の
|
||||||
|
は
|
||||||
|
ば
|
||||||
|
ぱ
|
||||||
|
ひ
|
||||||
|
び
|
||||||
|
ぴ
|
||||||
|
ふ
|
||||||
|
ぶ
|
||||||
|
ぷ
|
||||||
|
へ
|
||||||
|
べ
|
||||||
|
ぺ
|
||||||
|
ほ
|
||||||
|
ぼ
|
||||||
|
ぽ
|
||||||
|
ま
|
||||||
|
み
|
||||||
|
む
|
||||||
|
め
|
||||||
|
も
|
||||||
|
ゃ
|
||||||
|
や
|
||||||
|
ゅ
|
||||||
|
ゆ
|
||||||
|
ょ
|
||||||
|
よ
|
||||||
|
ら
|
||||||
|
り
|
||||||
|
る
|
||||||
|
れ
|
||||||
|
ろ
|
||||||
|
|
||||||
|
わ
|
||||||
|
|
||||||
|
|
||||||
|
を
|
||||||
|
ん
|
||||||
|
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
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net451" />
|
||||||
|
</packages>
|
Loading…
Reference in New Issue