mirror of
https://github.com/haven1433/HexManiacAdvance.git
synced 2026-05-31 20:42:43 -05:00
additional macros
support for out-of-order macro commands also allows for arguments to be applied multiple times
This commit is contained in:
parent
76f1977fb8
commit
6874768ffc
|
|
@ -518,13 +518,16 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
|||
private static readonly IReadOnlyList<byte> emptyByteList = new byte[0];
|
||||
private readonly List<string> documentation = new List<string>();
|
||||
|
||||
private bool hasShortForm;
|
||||
private readonly Dictionary<int, int> shortIndexFromLongIndex = new();
|
||||
|
||||
public IReadOnlyList<IScriptArg> Args { get; }
|
||||
public IReadOnlyList<byte> LineCode => emptyByteList;
|
||||
public IReadOnlyList<string> Documentation => documentation;
|
||||
public string LineCommand { get; }
|
||||
public bool IsEndingCommand => false;
|
||||
public bool IsValid { get; } = true;
|
||||
public string Usage { get; }
|
||||
public string Usage { get; private set; }
|
||||
|
||||
public static bool IsMacroLine(string engineLine) {
|
||||
engineLine = engineLine.Trim();
|
||||
|
|
@ -539,7 +542,10 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
|||
var docSplit = engineLine.Split(new[] { '#' }, 2);
|
||||
if (docSplit.Length > 1) documentation.Add('#' + docSplit[1]);
|
||||
engineLine = docSplit[0].Trim();
|
||||
Usage = " ".Join(engineLine.Split(' ').Where(token => token.Length != 2 || !token.TryParseHex(out _)));
|
||||
ExtractShortformInfo(ref engineLine);
|
||||
if (!hasShortForm) {
|
||||
Usage = " ".Join(engineLine.Split(' ').Where(token => token.Length != 2 || !token.TryParseHex(out _)));
|
||||
}
|
||||
|
||||
var tokens = engineLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var args = new List<IScriptArg>();
|
||||
|
|
@ -559,6 +565,29 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
|||
Args = args;
|
||||
}
|
||||
|
||||
private void ExtractShortformInfo(ref string engineLine) {
|
||||
if (!engineLine.Contains("->")) return;
|
||||
var parts = engineLine.Split("->");
|
||||
if (parts.Length != 2) return;
|
||||
engineLine = parts[1];
|
||||
var shortTokens = parts[0].Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
var longTokens = parts[1].Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (shortTokens[0] != longTokens[0]) return;
|
||||
shortTokens = shortTokens.Skip(1).ToArray();
|
||||
longTokens = longTokens.Skip(1).ToArray();
|
||||
|
||||
// for each entry in long, it shows up somewhere in short
|
||||
// entries in long can appear multiple times
|
||||
for (int i = 0; i < longTokens.Length; i++) {
|
||||
var index = shortTokens.IndexOf(longTokens[i]);
|
||||
if (index == -1) continue;
|
||||
shortIndexFromLongIndex.Add(i, index);
|
||||
}
|
||||
|
||||
hasShortForm = true;
|
||||
Usage = parts[0];
|
||||
}
|
||||
|
||||
public bool MatchesGame(string game) => true;
|
||||
public int CompiledByteLength(IDataModel model, int start) {
|
||||
var length = LineCode.Count;
|
||||
|
|
@ -593,13 +622,19 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
|||
public string Decompile(IDataModel data, int start) {
|
||||
var builder = new StringBuilder(LineCommand);
|
||||
var streamContent = new List<string>();
|
||||
var args = new List<string>();
|
||||
foreach (var arg in Args) {
|
||||
if (arg is ScriptArg sarg) {
|
||||
builder.Append(" ");
|
||||
sarg.Build(false, data, start, builder, streamContent);
|
||||
var tempBuilder = new StringBuilder();
|
||||
sarg.Build(false, data, start, tempBuilder, streamContent);
|
||||
args.Add(tempBuilder.ToString());
|
||||
}
|
||||
start += arg.Length(data, start);
|
||||
}
|
||||
if (args.Count > 0) {
|
||||
builder.Append(" ");
|
||||
builder.Append(" ".Join(ConvertLongFormToShortForm(args.ToArray())));
|
||||
}
|
||||
foreach (var content in streamContent) {
|
||||
builder.AppendLine();
|
||||
builder.AppendLine("{");
|
||||
|
|
@ -612,23 +647,27 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
|||
public bool CanCompile(string line) {
|
||||
var tokens = ScriptLine.Tokenize(line);
|
||||
if (tokens[0] != LineCommand) return false;
|
||||
return tokens.Length == Args.Where(arg => arg is ScriptArg).Count() + 1;
|
||||
var args = tokens.Skip(1).ToArray();
|
||||
args = ConvertShortFormToLongForm(args);
|
||||
return args.Length == Args.Where(arg => arg is ScriptArg).Count();
|
||||
}
|
||||
|
||||
public string Compile(IDataModel model, int start, string scriptLine, LabelLibrary labels, out byte[] result) {
|
||||
result = null;
|
||||
var tokens = ScriptLine.Tokenize(scriptLine);
|
||||
if (tokens[0] != LineCommand) throw new ArgumentException($"Command {LineCommand} was expected, but received {tokens[0]} instead.");
|
||||
var args = tokens.Skip(1).ToArray();
|
||||
args = ConvertShortFormToLongForm(args);
|
||||
var commandText = LineCommand;
|
||||
var specifiedArgs = Args.Where(arg => arg is ScriptArg).Count();
|
||||
if (specifiedArgs != tokens.Length - 1) {
|
||||
return $"Command {commandText} expects {specifiedArgs} arguments, but received {tokens.Length - 1} instead.";
|
||||
if (specifiedArgs != args.Length) {
|
||||
return $"Command {commandText} expects {specifiedArgs} arguments, but received {args.Length} instead.";
|
||||
}
|
||||
var results = new List<byte>();
|
||||
var specifiedArgIndex = 0;
|
||||
for (int i = 0; i < Args.Count; i++) {
|
||||
if (Args[i] is ScriptArg scriptArg) {
|
||||
var token = tokens[1 + specifiedArgIndex];
|
||||
var token = args[specifiedArgIndex];
|
||||
var message = scriptArg.Build(model, token, results, labels);
|
||||
if (message != null) return message;
|
||||
specifiedArgIndex += 1;
|
||||
|
|
@ -641,6 +680,29 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
|||
}
|
||||
|
||||
public void AddDocumentation(string doc) => documentation.Add(doc);
|
||||
|
||||
private string[] ConvertShortFormToLongForm(string[] args) {
|
||||
if (!hasShortForm) return args;
|
||||
// build long-form args from this short form
|
||||
var longForm = new List<string>();
|
||||
for (int i = 0; i < Args.Count; i++) {
|
||||
if (Args[i] is SilentMatchArg) continue;
|
||||
var shortIndex = shortIndexFromLongIndex[i];
|
||||
if (shortIndex < args.Length) longForm.Add(args[shortIndex]);
|
||||
}
|
||||
return longForm.ToArray();
|
||||
}
|
||||
|
||||
private string[] ConvertLongFormToShortForm(string[] args) {
|
||||
if (!hasShortForm) return args;
|
||||
var shortForm = new Dictionary<int, string>();
|
||||
for (int i = 0; i < Args.Count; i++) {
|
||||
if (Args[i] is SilentMatchArg) continue;
|
||||
var shortIndex = shortIndexFromLongIndex[i];
|
||||
shortForm[shortIndex] = args[shortForm.Count];
|
||||
}
|
||||
return shortForm.Count.Range(i => shortForm[i]).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public enum ExpectedPointerType {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ wild.battle B6 species:data.pokemon.names level. item:data.items.stats B7
|
|||
give.item 1A 00 80 item:data.items.stats 1A 01 80 count: 09 01
|
||||
msgbox.item 0F 00 msg<""> 1A 00 80 item:data.items.stats 1A 01 80 count: 1A 02 80 song:songnames 09 09 # shows a message about a received item,
|
||||
# followed by a standard 'put away' message.
|
||||
msgbox.fanfare 31 song:songnames 67 ptr<""> 66 32
|
||||
register.matchcall trainer:data.trainers.stats -> register.matchcall 16 04 80 trainer:data.trainers.stats 25 EA 01 1A 00 80 trainer:data.trainers.stats 09 08
|
||||
|
||||
|
||||
00 nop # does nothing
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user