mirror of
https://github.com/haven1433/HexManiacAdvance.git
synced 2026-05-31 20:42:43 -05:00
allow record segments to be pointers
Allow record segment formats to be pointers depending on the source value
This commit is contained in:
parent
35e361a673
commit
07608b0f9c
|
|
@ -72,9 +72,9 @@ data.maps.theme.popup, ,,,, ,,,, 0D4C54, [theme.mapnamepopu
|
|||
graphics.maps.names.popup.palettes, ,,,, ,,,, 0D4CA0, `ucp4:012345`
|
||||
graphics.maps.names.popup.background, ,,,, ,,,, 0D4CA4, `ucs4x10x18|graphics.maps.names.popup.palettes`
|
||||
graphics.maps.names.popup.outline, ,,,, ,,,, 0D4C58, `ucs4x6x30|graphics.maps.names.popup.palettes`
|
||||
data.maps.banks, 053324, 053324, 053344, 053344, , , , , , [maps<[map<[layout<[width:: height:: borderblock<[border:|h]4> blockmap<`blm`> blockdata1<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> attributes<> animation<>]1> blockdata2<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> attributes<> animation<>]1>]1> events<[objectCount.100 warpCount.100 scriptCount.100 signpostCount.100 objects<[id. graphics. unused:1 x:|z y:|z elevation.10 moveType. range:|t|x::|y:: trainerType: trainerRangeOrBerryID: script<`xse`> flag: unused:]/objectCount> warps<[x:|z y:|z elevation.10 warpID. map. bank.]/warpCount> scripts<[x:|z y:|z elevation:10 trigger: index:: script<`xse`>]/scriptCount> signposts<[x:|z y:|z elevation.10 kind. unused:1 arg::|h]/signpostCount>]1> mapscripts<[type. pointer<>]!00> connections<[count:: connections<[direction::mapdirections offset:: mapGroup. mapNum. unused:]/count>]1> music:songnames layoutID:data.maps.layouts+1 regionSectionID.data.maps.names cave. weather. mapType. unused. allowEscaping. showMapName. battleType.]1>]?>]34
|
||||
data.maps.banks, , , , , , , , , 084AA4, [maps<[map<[layout<[width:: height:: borderblock<[border:|h]4> blockmap<`blm`> blockdata1<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> attributes<> animation<>]1> blockdata2<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> attributes<> animation<>]1>]1> events<[objectCount.100 warpCount.100 scriptCount.100 signpostCount.100 objects<[id. graphics. unused:1 x:|z y:|z elevation.10 moveType. range:|t|x::|y:: trainerType: trainerRangeOrBerryID: script<`xse`> flag: unused:]/objectCount> warps<[x:|z y:|z elevation.10 warpID. map. bank.]/warpCount> scripts<[x:|z y:|z elevation:10 trigger: index:: script<`xse`>]/scriptCount> signposts<[x:|z y:|z elevation.10 kind. unused:1 arg::|h]/signpostCount>]1> mapscripts<[type. pointer<>]!00> connections<[count:: connections<[direction::mapdirections offset:: mapGroup. mapNum. unused:]/count>]1> music:songnames layoutID:data.maps.layouts+1 regionSectionID.data.maps.names cave. weather. mapType. unused: flags.|t|allowBiking.|allowEscaping.|allowRunning.|showMapName. battleType.]1>]?>]34
|
||||
data.maps.banks, , , , , 05524C, 05524C, 055260, 055260, , [maps<[map<[layout<[width:: height:: borderblock<> blockmap<`blm`> blockdata1<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> animation<> attributes<>]1> blockdata2<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> animation<> attributes<>]1> borderwidth. borderheight. unused:]1> events<[objectCount.100 warpCount.100 scriptCount.100 signpostCount.100 objects<[id. graphics. kind: x:|z y:|z elevation.10 moveType. range:|t|x::|y:: trainerType: trainerRangeOrBerryID: script<`xse`> flag: unused:]/objectCount> warps<[x:|z y:|z elevation.10 warpID. map. bank.]/warpCount> scripts<[x:|z y:|z elevation:10 trigger: index:: script<`xse`>]/scriptCount> signposts<[x:|z y:|z elevation.10 kind. unused:1 arg::|h]/signpostCount>]1> mapscripts<[type. pointer<>]!00> connections<[count:: connections<[direction::mapdirections offset:: mapGroup. mapNum. unused:]/count>]1> music:songnames layoutID:data.maps.layouts+1 regionSectionID.data.maps.names+88 cave. weather. mapType. allowBiking. flags.|t|allowEscaping.|allowRunning.|showMapName. floorNum. battleType.]1>]?>]43
|
||||
data.maps.banks, 053324, 053324, 053344, 053344, , , , , , [maps<[map<[layout<[width:: height:: borderblock<[border:|h]4> blockmap<`blm`> blockdata1<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> attributes<> animation<>]1> blockdata2<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> attributes<> animation<>]1>]1> events<[objectCount.100 warpCount.100 scriptCount.100 signpostCount.100 objects<[id. graphics. unused:1 x:|z y:|z elevation.10 moveType. range:|t|x::|y:: trainerType: trainerRangeOrBerryID: script<`xse`> flag: unused:]/objectCount> warps<[x:|z y:|z elevation.10 warpID. map. bank.]/warpCount> scripts<[x:|z y:|z elevation:10 trigger: index:: script<`xse`>]/scriptCount> signposts<[x:|z y:|z elevation.10 kind. unused:1 arg::|s=kind(0=<>|1=<>|2=<>|3=<>|4=<>)]/signpostCount>]1> mapscripts<[type. pointer<>]!00> connections<[count:: connections<[direction::mapdirections offset:: mapGroup. mapNum. unused:]/count>]1> music:songnames layoutID:data.maps.layouts+1 regionSectionID.data.maps.names cave. weather. mapType. unused. allowEscaping. showMapName. battleType.]1>]?>]34
|
||||
data.maps.banks, , , , , , , , , 084AA4, [maps<[map<[layout<[width:: height:: borderblock<[border:|h]4> blockmap<`blm`> blockdata1<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> attributes<> animation<>]1> blockdata2<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> attributes<> animation<>]1>]1> events<[objectCount.100 warpCount.100 scriptCount.100 signpostCount.100 objects<[id. graphics. unused:1 x:|z y:|z elevation.10 moveType. range:|t|x::|y:: trainerType: trainerRangeOrBerryID: script<`xse`> flag: unused:]/objectCount> warps<[x:|z y:|z elevation.10 warpID. map. bank.]/warpCount> scripts<[x:|z y:|z elevation:10 trigger: index:: script<`xse`>]/scriptCount> signposts<[x:|z y:|z elevation.10 kind. unused:1 arg::|s=kind(0=<>|1=<>|2=<>|3=<>|4=<>)]/signpostCount>]1> mapscripts<[type. pointer<>]!00> connections<[count:: connections<[direction::mapdirections offset:: mapGroup. mapNum. unused:]/count>]1> music:songnames layoutID:data.maps.layouts+1 regionSectionID.data.maps.names cave. weather. mapType. unused: flags.|t|allowBiking.|allowEscaping.|allowRunning.|showMapName. battleType.]1>]?>]34
|
||||
data.maps.banks, , , , , 05524C, 05524C, 055260, 055260, , [maps<[map<[layout<[width:: height:: borderblock<> blockmap<`blm`> blockdata1<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> animation<> attributes<>]1> blockdata2<[isCompressed. isSecondary. padding: tileset<> pal<`ucp4:0123456789ABCDEF`> blockset<> animation<> attributes<>]1> borderwidth. borderheight. unused:]1> events<[objectCount.100 warpCount.100 scriptCount.100 signpostCount.100 objects<[id. graphics. kind: x:|z y:|z elevation.10 moveType. range:|t|x::|y:: trainerType: trainerRangeOrBerryID: script<`xse`> flag: unused:]/objectCount> warps<[x:|z y:|z elevation.10 warpID. map. bank.]/warpCount> scripts<[x:|z y:|z elevation:10 trigger: index:: script<`xse`>]/scriptCount> signposts<[x:|z y:|z elevation.10 kind. unused:1 arg::|s=kind(0=<>|1=<>|2=<>|3=<>|4=<>)]/signpostCount>]1> mapscripts<[type. pointer<>]!00> connections<[count:: connections<[direction::mapdirections offset:: mapGroup. mapNum. unused:]/count>]1> music:songnames layoutID:data.maps.layouts+1 regionSectionID.data.maps.names+88 cave. weather. mapType. allowBiking. flags.|t|allowEscaping.|allowRunning.|showMapName. floorNum. battleType.]1>]?>]43
|
||||
data.maps.layouts, 05326C, 05326C, 05328C, 05328C, , , , , , [layout<>]332
|
||||
data.maps.layouts, , , , , 055194, 055194, 0551A8, 0551A8, , [layout<>]383
|
||||
data.maps.layouts, , , , , , , , , 0849CC, [layout<>]441
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using System.Linq;
|
|||
namespace HavenSoft.HexManiac.Core.Models.Map {
|
||||
|
||||
public record AllMapsModel(ModelTable Table) : IEnumerable<MapBankModel> {
|
||||
public static AllMapsModel Create(IDataModel model, Func<ModelDelta> tokenFactory) => new(model.GetTableModel("data.maps.banks", tokenFactory));
|
||||
public static AllMapsModel Create(IDataModel model, Func<ModelDelta> tokenFactory = null) => new(model.GetTableModel("data.maps.banks", tokenFactory));
|
||||
|
||||
public IEnumerator<MapBankModel> GetEnumerator() => Enumerate().GetEnumerator();
|
||||
|
||||
|
|
@ -118,6 +118,13 @@ namespace HavenSoft.HexManiac.Core.Models.Map {
|
|||
return warps.Select(obj => new WarpEventModel(obj)).ToList();
|
||||
}
|
||||
}
|
||||
public List<SignpostEventModel> Signposts {
|
||||
get {
|
||||
if (Element == null) return new();
|
||||
if (!Element.TryGetSubTable(Format.Signposts, out var signposts)) return new();
|
||||
return signposts.Select(sp => new SignpostEventModel(sp)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record BaseEventModel(ModelArrayElement Element) {
|
||||
|
|
@ -145,6 +152,11 @@ namespace HavenSoft.HexManiac.Core.Models.Map {
|
|||
public int Map => Element.GetValue("map");
|
||||
}
|
||||
|
||||
public record SignpostEventModel(ModelArrayElement Element) : BaseEventModel(Element) {
|
||||
public int Kind => Element.GetValue("kind");
|
||||
public int Arg => Element.GetValue("arg");
|
||||
}
|
||||
|
||||
public class Format {
|
||||
public static string RegionSection => "regionSectionID";
|
||||
public static string Events => "events";
|
||||
|
|
|
|||
|
|
@ -1133,16 +1133,32 @@ namespace HavenSoft.HexManiac.Core.Models {
|
|||
var shorterTable = Math.Min(arrayRun.ElementCount, previousTable?.ElementCount ?? arrayRun.ElementCount);
|
||||
// i loops over the different segments in the array
|
||||
for (int i = 0; i < arrayRun.ElementContent.Count; i++) {
|
||||
if (arrayRun.ElementContent[i].Type != ElementContentType.Pointer) { segmentOffset += arrayRun.ElementContent[i].Length; continue; }
|
||||
var segment = arrayRun.ElementContent[i];
|
||||
|
||||
// record segments _might_ be pointers... sometimes. Need to check every element
|
||||
if (segment is ArrayRunRecordSegment recordSeg) {
|
||||
for (int j = 0; j < elementCount; j++) {
|
||||
// segment=recordSeg.CreateConcrete(this,segmentOffset)
|
||||
var start = segmentOffset + arrayRun.ElementLength * j;
|
||||
segment = recordSeg.CreateConcrete(this, start);
|
||||
if (segment.Type == ElementContentType.Pointer) {
|
||||
if (formatMatches && shorterTable - parentOffset > j) continue; // we can skip this one
|
||||
changeAnchors(arrayRun.ElementContent[i], arrayRun.ElementContent, j, changeToken, start);
|
||||
}
|
||||
}
|
||||
segmentOffset += segment.Length;
|
||||
continue;
|
||||
}
|
||||
if (arrayRun.ElementContent[i].Type != ElementContentType.Pointer) { segmentOffset += segment.Length; continue; }
|
||||
// for a pointer segment, j loops over all the elements in the array
|
||||
var range = elementCount.Range();
|
||||
if (arrayRun.ElementContent[i] is ArrayRunPointerSegment pSeg && pSeg.InnerFormat.EndsWith("?")) range = range.Reverse();
|
||||
if (segment is ArrayRunPointerSegment pSeg && pSeg.InnerFormat.EndsWith("?")) range = range.Reverse();
|
||||
foreach (int j in range) {
|
||||
if (formatMatches && shorterTable - parentOffset > j) continue; // we can skip this one
|
||||
var start = segmentOffset + arrayRun.ElementLength * j;
|
||||
changeAnchors(arrayRun.ElementContent[i], arrayRun.ElementContent, j, changeToken, start);
|
||||
changeAnchors(segment, arrayRun.ElementContent, j, changeToken, start);
|
||||
}
|
||||
segmentOffset += arrayRun.ElementContent[i].Length;
|
||||
segmentOffset += segment.Length;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1300,6 +1316,7 @@ namespace HavenSoft.HexManiac.Core.Models {
|
|||
/// <param name="changeToken"></param>
|
||||
/// <param name="start"></param>
|
||||
private void AddPointerToAnchor(ArrayRunElementSegment segment, IReadOnlyList<ArrayRunElementSegment> segments, int parentIndex, ModelDelta changeToken, int start) {
|
||||
if (segment is ArrayRunRecordSegment recordSeg) segment = recordSeg.CreateConcrete(this, start);
|
||||
var destination = ReadPointer(start);
|
||||
if (destination < 0 || destination >= Count) return;
|
||||
var index = BinarySearch(destination);
|
||||
|
|
|
|||
|
|
@ -165,10 +165,35 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static ErrorInfo NotifyChildren(this ITableRun self, IDataModel model, ModelDelta token, int elementIndex, int segmentIndex) {
|
||||
private static void UpdateRecordType(ITableRun self, IDataModel model, ModelDelta token, int elementIndex, int segmentIndex, ArrayRunRecordSegment recordSegment, int previousValue) {
|
||||
var offset = self.ElementContent.Take(segmentIndex).Sum(seg => seg.Length);
|
||||
var sourceSegment = self.ElementContent[segmentIndex];
|
||||
var elementStart = self.Start + self.ElementLength * elementIndex;
|
||||
var newValue = model.ReadMultiByteValue(elementStart + offset, sourceSegment.Length);
|
||||
|
||||
if (previousValue == newValue) return;
|
||||
var previousConcrete = recordSegment.CreateConcrete(model.FormatRunFactory, model.TextConverter, previousValue);
|
||||
var newConcrete = recordSegment.CreateConcrete(model.FormatRunFactory, model.TextConverter, newValue);
|
||||
if ((previousConcrete.Type == ElementContentType.Pointer) == (newConcrete.Type == ElementContentType.Pointer)) return;
|
||||
var pointerOffset = self.ElementContent.Until(seg => seg == recordSegment).Sum(seg => seg.Length);
|
||||
var pointerDestination = model.ReadPointer(elementStart + pointerOffset);
|
||||
if (previousConcrete.Type == ElementContentType.Pointer) {
|
||||
// not a pointer anymore, remove format from destination
|
||||
model.ClearPointer(token, elementStart + pointerOffset, pointerDestination);
|
||||
}
|
||||
if (newConcrete.Type == ElementContentType.Pointer) {
|
||||
// now a pointer, add format to destination
|
||||
model.UpdateArrayPointer(token, newConcrete, self.ElementContent, elementIndex, elementStart + pointerOffset, pointerDestination);
|
||||
}
|
||||
}
|
||||
|
||||
public static ErrorInfo NotifyChildren(this ITableRun self, IDataModel model, ModelDelta token, int elementIndex, int segmentIndex, int previousValue = 0xDedBeef) {
|
||||
int offset = 0;
|
||||
var info = ErrorInfo.NoError;
|
||||
foreach (var segment in self.ElementContent) {
|
||||
if (previousValue != 0xDedBeef && segment is ArrayRunRecordSegment recordSegment && recordSegment.MatchField == self.ElementContent[segmentIndex].Name) {
|
||||
UpdateRecordType(self, model, token, elementIndex, segmentIndex, recordSegment, previousValue);
|
||||
}
|
||||
if (segment is ArrayRunPointerSegment pointerSegment) {
|
||||
var pointerSource = self.Start + elementIndex * self.ElementLength + offset;
|
||||
var destination = model.ReadPointer(pointerSource);
|
||||
|
|
|
|||
|
|
@ -377,7 +377,19 @@ namespace HavenSoft.HexManiac.Core.Models.Runs {
|
|||
if (matchFieldOffset == table.ElementLength) return defaultConcrete;
|
||||
var offsets = table.ConvertByteOffsetToArrayOffset(offset);
|
||||
var matchFieldValue = model.ReadMultiByteValue(table.Start + offsets.ElementIndex * table.ElementLength + matchFieldOffset, table.ElementContent[matchFieldIndex].Length);
|
||||
return CreateConcrete(model.FormatRunFactory, model.TextConverter, matchFieldValue);
|
||||
}
|
||||
|
||||
public ArrayRunElementSegment CreateConcrete(IFormatRunFactory formatRunFactory, ITextConverter textConverter, int matchFieldValue) {
|
||||
var defaultConcrete = new ArrayRunElementSegment(Name, ElementContentType.Integer, Length, TextConverter);
|
||||
if (!EnumForValue.TryGetValue(matchFieldValue, out var enumName)) return defaultConcrete;
|
||||
|
||||
if (enumName.StartsWith("<") && enumName.EndsWith(">")) {
|
||||
enumName = enumName.Substring(1, enumName.Length - 2);
|
||||
if (enumName.Length > 0) return new ArrayRunPointerSegment(formatRunFactory, Name, enumName);
|
||||
return new ArrayRunElementSegment(Name, ElementContentType.Pointer, 4, textConverter);
|
||||
}
|
||||
|
||||
return new ArrayRunEnumSegment(Name, Length, enumName);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2043,17 +2043,25 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Map {
|
|||
return list;
|
||||
}
|
||||
|
||||
public EventGroupModel EventGroup {
|
||||
get {
|
||||
if (allOverworldSprites == null) allOverworldSprites = RenderOWs(model);
|
||||
if (defaultOverworldSprite == null) defaultOverworldSprite = GetDefaultOW(model);
|
||||
var map = GetMapModel();
|
||||
var eventsTable = map.GetSubTable("events");
|
||||
if (eventsTable == null) return null;
|
||||
var eventElements = eventsTable[0];
|
||||
if (eventElements == null) return null;
|
||||
var events = new EventGroupModel(ViewPort.Tools.CodeTool.ScriptParser, GotoAddress, eventElements, allOverworldSprites, defaultOverworldSprite, BerryInfo, group, this.map);
|
||||
events.DataMoved += HandleEventDataMoved;
|
||||
return events;
|
||||
}
|
||||
}
|
||||
|
||||
private IReadOnlyList<IEventViewModel> GetEvents() {
|
||||
if (allOverworldSprites == null) allOverworldSprites = RenderOWs(model);
|
||||
if (defaultOverworldSprite == null) defaultOverworldSprite = GetDefaultOW(model);
|
||||
var map = GetMapModel();
|
||||
var results = new List<IEventViewModel>();
|
||||
var eventsTable = map.GetSubTable("events");
|
||||
if (eventsTable == null) return results;
|
||||
var eventElements = eventsTable[0];
|
||||
if (eventElements == null) return results;
|
||||
var events = new EventGroupModel(ViewPort.Tools.CodeTool.ScriptParser, GotoAddress, eventElements, allOverworldSprites, defaultOverworldSprite, BerryInfo, group, this.map);
|
||||
events.DataMoved += HandleEventDataMoved;
|
||||
var events = EventGroup;
|
||||
if (events == null) return results;
|
||||
results.AddRange(events.Objects);
|
||||
results.AddRange(events.Warps);
|
||||
results.AddRange(events.Scripts);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using HavenSoft.HexManiac.Core.Models;
|
||||
using HavenSoft.HexManiac.Core.Models.Code;
|
||||
using HavenSoft.HexManiac.Core.Models.Map;
|
||||
using HavenSoft.HexManiac.Core.Models.Runs;
|
||||
using HavenSoft.HexManiac.Core.Models.Runs.Sprites;
|
||||
using HavenSoft.HexManiac.Core.ViewModels.DataFormats;
|
||||
|
|
@ -939,6 +940,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
|
||||
public IDataModel Model { get; }
|
||||
public IDataModel ModelFor(Point p) => Model;
|
||||
public AllMapsModel Maps => AllMapsModel.Create(Model, () => CurrentChange);
|
||||
|
||||
public bool FormattedDataIsSelected {
|
||||
get {
|
||||
|
|
|
|||
|
|
@ -510,6 +510,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Visitors {
|
|||
return;
|
||||
}
|
||||
}
|
||||
var previousValue = Model.ReadMultiByteValue(integer.Source, integer.Length);
|
||||
Model.WriteMultiByteValue(integer.Source, integer.Length, CurrentChange, result);
|
||||
if (result >= Math.Pow(2L, integer.Length * 8)) ErrorText = $"Warning: number was too big to fit in the available space.";
|
||||
int runIndex = integer.Source - run.Start;
|
||||
|
|
@ -519,7 +520,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Visitors {
|
|||
}
|
||||
if (run is ITableRun tableRun) {
|
||||
var offset = tableRun.ConvertByteOffsetToArrayOffset(integer.Source);
|
||||
var info = tableRun.NotifyChildren(Model, CurrentChange, offset.ElementIndex, offset.SegmentIndex);
|
||||
var info = tableRun.NotifyChildren(Model, CurrentChange, offset.ElementIndex, offset.SegmentIndex, previousValue);
|
||||
scroll.DataLength = Model.Count;
|
||||
if (info != null && info.IsWarning) MessageText = info.ErrorMessage;
|
||||
}
|
||||
|
|
@ -1040,6 +1041,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.Visitors {
|
|||
private void UpdateArrayPointer(ITableRun run, int pointerDestination) {
|
||||
var offsets = run.ConvertByteOffsetToArrayOffset(memoryLocation);
|
||||
var segment = run.ElementContent[offsets.SegmentIndex];
|
||||
if (segment is ArrayRunRecordSegment recordSeg) segment = recordSeg.CreateConcrete(Model, offsets.SegmentStart);
|
||||
if (segment is ArrayRunPointerSegment pointerSegment) {
|
||||
if (!pointerSegment.DestinationDataMatchesPointerFormat(Model, CurrentChange, offsets.SegmentStart, pointerDestination, run.ElementContent, -1)) {
|
||||
ErrorText = $"This pointer must point to {pointerSegment.InnerFormat} data.";
|
||||
|
|
|
|||
|
|
@ -1384,6 +1384,94 @@ namespace HavenSoft.HexManiac.Tests {
|
|||
Assert.Equal(3, child.ElementCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TableWithPointerRecord_GetConcrete_ReturnsPointerFormat() {
|
||||
ViewPort.Edit("^parent[arg:: target::|s=arg(2=<>)]2 ");
|
||||
|
||||
ViewPort.Edit("2 ");
|
||||
var table = Model.GetTable("parent");
|
||||
var raw = (ArrayRunRecordSegment)table.ElementContent[1];
|
||||
var segment = raw.CreateConcrete(Model, 4);
|
||||
|
||||
Assert.Equal(ElementContentType.Pointer, segment.Type);
|
||||
Assert.IsType<Pointer>(ViewPort[ViewPort.ConvertAddressToViewPoint(4)].Format);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TableWithPointerRecord_DestinationKnowsAboutRecord() {
|
||||
ViewPort.Edit("^parent[target::|s=arg(0=<>) arg::]1 ");
|
||||
ViewPort.Edit("<100>");
|
||||
Model.ResolveConflicts();
|
||||
var source = Model.GetNextRun(0x100).PointerSources.Single();
|
||||
Assert.Equal(0, source);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordPointer_BecomesPointer_PointerAddedToExistingAnchor() {
|
||||
SetFullModel(0xFF);
|
||||
"00 00 00 00 00 01 00 08".ToByteArray().WriteInto(Model.RawData, 0);
|
||||
ViewPort.Edit("^parent[arg:: target::|s=arg(2=<>)]1 @080 <100>");
|
||||
|
||||
ViewPort.Edit("@000 2 ");
|
||||
|
||||
Assert.Equal(2, Model.GetNextRun(0x100).PointerSources.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordPointer_BecomesPointer_CreateNewAnchor() {
|
||||
SetFullModel(0xFF);
|
||||
"00 00 00 00 00 01 00 08".ToByteArray().WriteInto(Model.RawData, 0);
|
||||
ViewPort.Edit("^parent[arg:: target::|s=arg(2=<>)]1 ");
|
||||
|
||||
ViewPort.Edit("@000 2 ");
|
||||
|
||||
Assert.Equal(4, Model.GetNextRun(0x100).PointerSources.Single());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordPointer_CreateAsPointer_CreateNewAnchor() {
|
||||
SetFullModel(0xFF);
|
||||
"02 00 00 00 00 01 00 08".ToByteArray().WriteInto(Model.RawData, 0);
|
||||
|
||||
ViewPort.Edit("@000 ^parent[arg:: target::|s=arg(2=<>)]1 ");
|
||||
|
||||
Assert.Equal(4, Model.GetNextRun(0x100).PointerSources.Single());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordPointer_CreateAsPointer_PointerAddedToExistingAnchor() {
|
||||
SetFullModel(0xFF);
|
||||
"02 00 00 00 00 01 00 08".ToByteArray().WriteInto(Model.RawData, 0);
|
||||
|
||||
ViewPort.Edit("@080 <100> @000 ^parent[arg:: target::|s=arg(2=<>)]1 ");
|
||||
|
||||
Assert.Equal(2, Model.GetNextRun(0x100).PointerSources.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordPointer_CeaseBeingPointer_PointerRemovedFromExistingAnchor() {
|
||||
SetFullModel(0xFF);
|
||||
"02 00 00 00 00 01 00 08".ToByteArray().WriteInto(Model.RawData, 0);
|
||||
ViewPort.Edit("@080 <100> @000 ^parent[arg:: target::|s=arg(2=<>)]1 ");
|
||||
|
||||
ViewPort.Edit("@000 0 ");
|
||||
|
||||
Assert.Single(Model.GetNextRun(0x100).PointerSources);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordPointerToText_RepointText_UpdateRecord() {
|
||||
SetFullModel(0xFF);
|
||||
"00 00 00 00 00 00 00 00".ToByteArray().WriteInto(Model.RawData, 0);
|
||||
ViewPort.Edit("^parent[arg:: target::|s=arg(2=<\"\">)]1 2 <100> @100 Hello\" @108 dead");
|
||||
|
||||
// cause the repoint
|
||||
ViewPort.Edit("@100 Hello World!");
|
||||
|
||||
var destination = Model.ReadPointer(4);
|
||||
Assert.NotEqual(0x100, destination);
|
||||
}
|
||||
|
||||
private void ArrangeTrainerPokemonTeamData(byte structType, byte pokemonCount, int trainerCount) {
|
||||
CreateTextTable(HardcodeTablesModel.PokemonNameTable, 0x180, "ABCDEFGHIJKLMNOP".Select(c => c.ToString()).ToArray());
|
||||
CreateTextTable(HardcodeTablesModel.MoveNamesTable, 0x1B0, "qrstuvwxyz".Select(c => c.ToString()).ToArray());
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user