mirror of
https://github.com/haven1433/HexManiacAdvance.git
synced 2026-10-01 20:56:36 -05:00
add stream content recursively for scripts
This should make <auto> able to work even when there are scripts that point to scripts, as the content will appear after the last attached script.
This commit is contained in:
@@ -753,7 +753,7 @@ namespace HavenSoft.HexManiac.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
public Func<IScriptStartRun, int> GetScriptLength;
|
||||
int IDataModel.GetScriptLength(IScriptStartRun run) => GetScriptLength?.Invoke(run) ?? default;
|
||||
public Func<IScriptStartRun, IDictionary<int, int>, int> GetScriptLength;
|
||||
int IDataModel.GetScriptLength(IScriptStartRun run, IDictionary<int, int> destinationLengths) => GetScriptLength?.Invoke(run, destinationLengths) ?? default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
||||
|
||||
public ScriptParser(IReadOnlyList<IScriptLine> engine, byte endToken) => (this.engine, this.endToken) = (engine, endToken);
|
||||
|
||||
public int GetScriptSegmentLength(IDataModel model, int address) => engine.GetScriptSegmentLength(model, address);
|
||||
public int GetScriptSegmentLength(IDataModel model, int address) => engine.GetScriptSegmentLength(model, address, new Dictionary<int, int>());
|
||||
|
||||
public string Parse(IDataModel data, int start, int length) {
|
||||
var builder = new StringBuilder();
|
||||
@@ -493,13 +493,13 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
||||
return string.Join(Environment.NewLine, candidates.Select(line => line.Usage));
|
||||
}
|
||||
|
||||
public static int GetArgLength(IDataModel model, IScriptArg arg, int start) {
|
||||
public static int GetArgLength(IDataModel model, IScriptArg arg, int start, IDictionary<int, int> destinationLengths) {
|
||||
if (arg.Type == ArgType.Pointer && arg.PointerType != ExpectedPointerType.Unknown) {
|
||||
var destination = model.ReadPointer(start);
|
||||
if (destination >= 0 && destination < model.Count) {
|
||||
var run = model.GetNextRun(destination);
|
||||
if (run is IScriptStartRun scriptStart && scriptStart.Start == destination && scriptStart.Start > start) {
|
||||
return model.GetScriptLength(scriptStart);
|
||||
return model.GetScriptLength(scriptStart, destinationLengths);
|
||||
} else if (run.Start == destination) {
|
||||
// we only want to add this run's length as part of the script if:
|
||||
// (1) the run has no name
|
||||
@@ -665,7 +665,7 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
||||
public int CompiledByteLength(IDataModel model, int start, IDictionary<int, int> destinationLengths) {
|
||||
var length = LineCode.Count;
|
||||
foreach (var arg in Args) {
|
||||
var argLength = ScriptParser.GetArgLength(model, arg, start + length);
|
||||
var argLength = ScriptParser.GetArgLength(model, arg, start + length, destinationLengths);
|
||||
if (argLength > 0) destinationLengths[model.ReadPointer(start + length)] = argLength;
|
||||
length += arg.Length(default, -1);
|
||||
}
|
||||
@@ -807,7 +807,7 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
||||
public int CompiledByteLength(IDataModel model, int start, IDictionary<int, int> destinationLengths) {
|
||||
var length = LineCode.Count;
|
||||
foreach (var arg in Args) {
|
||||
var argLength = ScriptParser.GetArgLength(model, arg, start + length);
|
||||
var argLength = ScriptParser.GetArgLength(model, arg, start + length, destinationLengths);
|
||||
if (argLength > 0) destinationLengths[model.ReadPointer(start + length)] = argLength;
|
||||
length += arg.Length(model, start + length);
|
||||
}
|
||||
@@ -1301,16 +1301,15 @@ namespace HavenSoft.HexManiac.Core.Models.Code {
|
||||
return (ScriptLine)self.FirstOrDefault(option => option is ScriptLine && option.Matches(data, start));
|
||||
}
|
||||
|
||||
public static int GetScriptSegmentLength(this IReadOnlyList<IScriptLine> self, IDataModel model, int address) {
|
||||
public static int GetScriptSegmentLength(this IReadOnlyList<IScriptLine> self, IDataModel model, int address, IDictionary<int, int> destinationLengths) {
|
||||
int length = 0;
|
||||
var destinations = new Dictionary<int, int>();
|
||||
while (true) {
|
||||
var line = self.GetMatchingLine(model, address + length);
|
||||
if (line == null) break;
|
||||
length += line.CompiledByteLength(model, address + length, destinations);
|
||||
length += line.CompiledByteLength(model, address + length, destinationLengths);
|
||||
if (line.IsEndingCommand) break;
|
||||
}
|
||||
while (destinations.TryGetValue(address + length, out int argLength)) {
|
||||
while (destinationLengths.TryGetValue(address + length, out int argLength)) {
|
||||
length += argLength;
|
||||
}
|
||||
return length;
|
||||
|
||||
@@ -33,6 +33,7 @@ msgbox.item 0F 00 msg<""> 1A 00 80 item:data.items.stats 1A 01 80 count: 1A
|
||||
# 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
|
||||
if.compare variable: condition.script_compare value: pointer<`xse`> -> if.compare 21 variable: value: 06 condition.script_compare pointer<`xse`>
|
||||
|
||||
|
||||
00 nop # does nothing
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace HavenSoft.HexManiac.Core.Models {
|
||||
bool WriteValue(ModelDelta changeToken, int address, int value);
|
||||
int ReadPointer(int address);
|
||||
int ReadValue(int address);
|
||||
int GetScriptLength(IScriptStartRun run);
|
||||
int GetScriptLength(IScriptStartRun run, IDictionary<int, int> destinationLengths);
|
||||
|
||||
SortedSpan<int> GetUnmappedSourcesToAnchor(string anchor);
|
||||
void SetUnmappedConstant(ModelDelta changeToken, string name, int value);
|
||||
@@ -294,7 +294,7 @@ namespace HavenSoft.HexManiac.Core.Models {
|
||||
|
||||
public abstract void ClearPointer(ModelDelta currentChange, int source, int destination);
|
||||
|
||||
public virtual int GetScriptLength(IScriptStartRun run) => 1;
|
||||
public virtual int GetScriptLength(IScriptStartRun run, IDictionary<int, int> destinationLengths) => 1;
|
||||
|
||||
public int ReadValue(int index) => BitConverter.ToInt32(RawData, index);
|
||||
|
||||
|
||||
@@ -1553,19 +1553,19 @@ namespace HavenSoft.HexManiac.Core.Models {
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetScriptLength(IScriptStartRun run) {
|
||||
public override int GetScriptLength(IScriptStartRun run, IDictionary<int, int> destinationLengths) {
|
||||
IReadOnlyList<IScriptLine> lines = null;
|
||||
if (run is XSERun) lines = singletons.ScriptLines;
|
||||
if (run is BSERun) lines = singletons.BattleScriptLines;
|
||||
if (run is ASERun) lines = singletons.AnimationScriptLines;
|
||||
if (run is TSERun) lines = singletons.BattleAIScriptLines;
|
||||
return Math.Max(1, lines.GetScriptSegmentLength(this, run.Start));
|
||||
return Math.Max(1, lines.GetScriptSegmentLength(this, run.Start, destinationLengths));
|
||||
}
|
||||
|
||||
public override T RelocateForExpansion<T>(ModelDelta changeToken, T run, int minimumLength) {
|
||||
int currentLength = run.Length;
|
||||
if (run is IScriptStartRun scriptStart) {
|
||||
currentLength = GetScriptLength(scriptStart);
|
||||
currentLength = GetScriptLength(scriptStart, new Dictionary<int, int>());
|
||||
}
|
||||
if (minimumLength <= currentLength) return run;
|
||||
if (CanSafelyUse(run.Start + currentLength, run.Start + minimumLength)) return run;
|
||||
|
||||
@@ -505,6 +505,38 @@ applymovement 0 <auto>
|
||||
Assert.Contains("<auto>", script);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScriptWithTextAfterBranch_Decompile_IncludedInLength() {
|
||||
EventScript = @"
|
||||
lock
|
||||
msgbox.yesno <auto>
|
||||
{
|
||||
Is the answer yes?
|
||||
}
|
||||
if.compare 0x800D = 1 <yes>
|
||||
if.compare 0x800D = 0 <no>
|
||||
release
|
||||
end
|
||||
yes:
|
||||
msgbox.default <auto>
|
||||
{
|
||||
You said yes!
|
||||
}
|
||||
release
|
||||
end
|
||||
no:
|
||||
msgbox.default <auto>
|
||||
{
|
||||
You said no!
|
||||
}
|
||||
release
|
||||
end";
|
||||
|
||||
var length = Tool.ScriptParser.FindLength(Model, 0);
|
||||
|
||||
Assert.Equal(99, length);
|
||||
}
|
||||
|
||||
// TODO test that we get an error (not an exception) if we do auto on an unformatted pointer
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user