Skip to content

Commit

Permalink
Add dialogue opcode parsing (#68)
Browse files Browse the repository at this point in the history
* add currently known dialogue opcodes

* add more textbox opcodes, document additional potential opcodes

* add unknown opcodes for parsing

* get all maps to not throw errors when parsing dialogue section opcodes

* start trying to implement ui rendering for opcodes

* use observablecollection for lists of opcodes, add basic rendering of opcodes

* add styling to opcode tree

* add highlight opcodes, add unknown opcode 0x16

* adjust opcode returns

* fix opcode 10 mapid, fix some stream read functions

* implement handling for base element index searching for listbox items

* add in scnr file path parsing
  • Loading branch information
krogenth authored Jan 13, 2024
1 parent 594f563 commit 2973d98
Show file tree
Hide file tree
Showing 64 changed files with 2,483 additions and 89 deletions.
2 changes: 2 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
<PackageVersion Include="CommunityToolkit.Diagnostics" Version="8.2.1" />
<PackageVersion Include="Pfim" Version="0.11.2" />

<PackageVersion Include="NVorbis" Version="0.10.5" />

<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageVersion Include="NUnit" Version="3.13.3" />
Expand Down
31 changes: 21 additions & 10 deletions documentation/Data File Details.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,27 @@
.MDT FILES {

CODES DETAILS
0x05 XX YY XX = script number? YY = character id
0x08 XX YY ZZ XX = ???, YY = ???(noticed either 0x21 or 0x41), ZZ = ???(only been 0x01)
0x0B ??? 2 parameters most likely(seen in 2000.mdt at 0x1AB71), according to old notes, this handles camera changes
0x11 XX [] adds item to inventory, XX = ???
0x03 ??? Seems to have 3 parameters
0x04 ??? Seems to have 1 parameter
0x05 XX YY XX = script number? YY = character id
0x06 ??? Unsure on parameter count
0x08 XX YY ZZ XX = ???, YY = ???(noticed either 0x21 or 0x41), ZZ = ???(only been 0x01)
0x09 ??? Seems to have 4 parameters
0x10 Unsure on parameter count
0x0B ??? 2 parameters most likely(seen in 2000.mdt at 0x1AB71), according to old notes, this handles camera changes
0x11 XX [] adds item to inventory, XX = ???
0x14 ??? Unsure on parameter count
0x15 ??? Unsure, may be 4 parameters?
0x17 XX [YY ZZ] Box stuff
XX = 00 Remove textbox? Used at end of dialogues
XX = 01 Create textbox? Used at beginning of dialogues
XX = 00 Remove textbox? Used at end of dialogues
XX = 01 Create textbox? Used at beginning of dialogues
XX = 20 Create sub textbox(textbox that appears top-right of current textbox)
XX = 40 Create options textbox(user interaction required)
XX = 80, YY ZZ Create overword textbox, YY = length of textbox, ZZ = height of textbox
0x18 00 XX changes character portrait, XX = character portrait offset
0x1A next page
0x1D FF XX pause(frame/tick?)
0x1F next line
0x18 00 XX changes character portrait, XX = character portrait offset
0x1A next page
0x1D FF XX pause(frame/tick?)
0x1F next line

Likely Codes
0x02
Expand All @@ -78,6 +87,8 @@
0x1B 1 byte
0x?? 0x70

Codes likely span from 0x01 to 0x1F, all ASCII values before text.


0x0000 - Header Length(always 0x200)

Expand Down
13 changes: 10 additions & 3 deletions src/G2DataGUI.Common/Data/Maps/Map.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using G2DataGUI.Common.Paths;

namespace G2DataGUI.Common.Data.Maps;

Expand All @@ -20,16 +22,18 @@ public class Map

public string MapName { get; set; } = "";
public string FileLocation { get; set; } = "";
public string Filename { get; set; } = "";
public string ScnrFileLocation { get; set; } = "";
public string FileName { get; set; } = "";

public static Map ReadMap(FileStream reader, string filepath)
{
Map map = new()
{
Header = MapHeader.ReadMapHeader(reader),
FileLocation = filepath,
Filename = Path.GetFileNameWithoutExtension(filepath),
FileName = Path.GetFileNameWithoutExtension(filepath),
};
map.ScnrFileLocation = map.ScnrFilePath();

reader.Seek(map.Header.OffsetMapEntries, SeekOrigin.Begin);
for (var index = 0; index < map.Header.NumMapEntries; index++)
Expand Down Expand Up @@ -190,4 +194,7 @@ private void ReadMapName()
}
}
}

private string ScnrFilePath() =>
$"{Version.Instance.RootTextDirectory}\\en\\scnr\\{FileName}.scn";
}
46 changes: 36 additions & 10 deletions src/G2DataGUI.Common/Data/Maps/MapDialogue.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
using System.Collections.Generic;
using System.IO;
using G2DataGUI.Common.Data.Maps.MapDialogueOpcodes;
using G2DataGUI.IO.Streams;
using System.Linq;
using System.Collections.ObjectModel;

namespace G2DataGUI.Common.Data.Maps;
public class MapDialogue
{
public MapDialogueHeader Header { get; set; }
public List<byte[]> DialogueSections { get; set; } = new();
public ObservableCollection<ObservableCollection<IMapDialogueOpcode>> DialogueSectionOpcodes { get; set; } = new();

public static MapDialogue ReadMapDialogue(Stream reader, uint dialogueSectionLength)
{
Expand All @@ -15,16 +19,38 @@ public static MapDialogue ReadMapDialogue(Stream reader, uint dialogueSectionLen
Header = MapDialogueHeader.ReadMapDialogueHeader(reader),
};

var dialogueStartPosition = reader.Position;
for (var index = 1; index < dialogue.Header.Offsets.Count; index++)
{
var length = (index == dialogue.Header.Offsets.Count - 1) ?
(dialogueSectionLength - dialogue.Header.HeaderLength - (dialogue.Header.Offsets[index - 1].Offset * 8)) :
(dialogue.Header.Offsets[index].Offset - dialogue.Header.Offsets[index - 1].Offset) * 8;
reader.Seek(dialogueStartPosition + (dialogue.Header.Offsets[index - 1].Offset * 8), SeekOrigin.Begin);
dialogue.DialogueSections.Add(reader.ReadRawByteArray((uint)length));
}
var dialogueStartPosition = reader.Position;
for (var index = 1; index < dialogue.Header.Offsets.Count; index++)
{
dialogue.DialogueSectionOpcodes.Add(new ObservableCollection<IMapDialogueOpcode>());
var length = (index == dialogue.Header.Offsets.Count - 1) ?
(dialogueSectionLength - dialogue.Header.HeaderLength - (dialogue.Header.Offsets[index - 1].Offset * 8)) :
(dialogue.Header.Offsets[index].Offset - dialogue.Header.Offsets[index - 1].Offset) * 8;
using MemoryStream memReader = new();

// write section to memory stream to force cutoff from overrunning opcodes
memReader.Write(reader.ReadRawByteArray((uint)length));
memReader.Seek(0, SeekOrigin.Begin);
while (memReader.Position < memReader.Length)
{
var opcode = IMapDialogueOpcode.ParseNextOpcode(memReader);
if (opcode != null)
{
dialogue.DialogueSectionOpcodes.Last().Add(opcode);
}
}
}

reader.Seek(dialogueStartPosition, SeekOrigin.Begin);
for (var index = 1; index < dialogue.Header.Offsets.Count; index++)
{
var length = (index == dialogue.Header.Offsets.Count - 1) ?
(dialogueSectionLength - dialogue.Header.HeaderLength - (dialogue.Header.Offsets[index - 1].Offset * 8)) :
(dialogue.Header.Offsets[index].Offset - dialogue.Header.Offsets[index - 1].Offset) * 8;
reader.Seek(dialogueStartPosition + (dialogue.Header.Offsets[index - 1].Offset * 8), SeekOrigin.Begin);
dialogue.DialogueSections.Add(reader.ReadRawByteArray((uint)length));
}

return dialogue;
return dialogue;
}
}
2 changes: 1 addition & 1 deletion src/G2DataGUI.Common/Data/Maps/MapDialogueHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ public static MapDialogueOffset ReadMapDialogueOffset(Stream reader)
};
return offset;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.IO;
using G2DataGUI.IO.Streams;

namespace G2DataGUI.Common.Data.Maps.MapDialogueOpcodes;

public class CameraMoveOpcode : IMapDialogueOpcode, IMapDialogueOpcodeReader
{
public DialogueOpcode Opcode { get; set; } = DialogueOpcode.CameraMove;
public byte Unknown1 { get; set; }
public byte Unknown2 { get; set; }

public static IMapDialogueOpcode ReadOpcode(Stream reader)
{
return new CameraMoveOpcode()
{
Unknown1 = reader.ReadRawByte(),
Unknown2 = reader.ReadRawByte(),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.IO;
using G2DataGUI.IO.Streams;

namespace G2DataGUI.Common.Data.Maps.MapDialogueOpcodes;

public class CharacterPortaitOpcode : IMapDialogueOpcode, IMapDialogueOpcodeReader
{
public DialogueOpcode Opcode { get; set; } = DialogueOpcode.CharacterPortait;

/// <summary>
/// Appears to always be 0x00
/// </summary>
public byte Unknown1 { get; set; } = 0x00;

public byte PortaitOffset { get; set; }

public static IMapDialogueOpcode ReadOpcode(Stream reader)
{
return new CharacterPortaitOpcode()
{
Unknown1 = reader.ReadRawByte(),
PortaitOffset = reader.ReadRawByte(),
};
}
}
129 changes: 129 additions & 0 deletions src/G2DataGUI.Common/Data/Maps/MapDialogueOpcodes/DialogueOpcodes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
namespace G2DataGUI.Common.Data.Maps.MapDialogueOpcodes;

public enum DialogueOpcode : byte
{
/// <summary>
/// Not sure how to handle text
/// so considering this a No Op
/// opcode, to house the text itself
/// </summary>
Text = 0x00,

/// <summary>
/// Completely unsure, likely 3 parameters
/// </summary>
Unknown03 = 0x03,

/// <summary>
/// Completely unknown, likely 1 parameter
/// </summary>
Unknown04 = 0x04,

/// <summary>
/// Seems to define a call to a script
/// within the Map's script list
/// </summary>
ScriptCall = 0x05,

/// <summary>
/// Completely unknown, may be 4 parameters
/// </summary>
Unknown06 = 0x06,

/// <summary>
/// Completely unknown, may be 1 or 4 parameters
/// </summary>
Unknown07 = 0x07,

/// <summary>
/// Completely unknown, likely 2 parameters
/// </summary>
Unknown08 = 0x08,

/// <summary>
/// Completely unknown, may be 4 parameters
/// </summary>
Unknown09 = 0x09,

/// <summary>
/// Seems to deal with camera movement
/// </summary>
CameraMove = 0x0B,

/// <summary>
/// Completely unknown, seems to have 1 parameter
/// </summary>
Unknown0C = 0x0C,

/// <summary>
/// Completely unknown, seems to have 2 parameters
/// </summary>
Unknown0D = 0x0D,

/// <summary>
/// Completely unknown, no clue on parameters(1 parameter?).
/// See Map 1000, section 8, offset 0x24.
/// Also see Map 1000, section 10, offset 0x1F.
/// </summary>
Unknown10 = 0x10,

/// <summary>
/// Adds items to inventory
/// </summary>
ItemAquire = 0x11,

/// <summary>
/// Completely unknown, no clue on parameters
/// </summary>
Unknown14 = 0x14,

/// <summary>
/// Completely unknown, likely 4 parameters
/// </summary>
Unknown15 = 0x15,

/// <summary>
/// Completely unknown, exists with tutorial guy dialogue...
/// </summary>
Unknown16 = 0x16,

/// <summary>
/// Defines a action around textboxes
/// </summary>
TextBox = 0x17,

/// <summary>
/// Defines which character protrait to display
/// </summary>
CharacterPortait = 0x18,

/// <summary>
/// Clears/Next pages within the textbox
/// </summary>
NextPage = 0x1A,

/// <summary>
/// Completely unknown, appears to have no parameters
/// </summary>
Unknown1B = 0x1B,

/// <summary>
/// Completely unknown, seems to have 1 parameter
/// </summary>
Unknown1C = 0x1C,

/// <summary>
/// Pauses text rendering for a time(tick based?)
/// </summary>
Pause = 0x1D,

/// <summary>
/// Creates a highlighted section of text
/// </summary>
Highlight = 0x1E,

/// <summary>
/// Moves text rendering to next line
/// </summary>
NextLine = 0x1F,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Collections.ObjectModel;
using System.IO;

namespace G2DataGUI.Common.Data.Maps.MapDialogueOpcodes.Highlight;

public class HighlightEndOpcode : IHighlightOpcode
{
public DialogueOpcode Opcode { get; set; } = DialogueOpcode.Highlight;
public HighlightOption Option { get; set; } = HighlightOption.End;
public ObservableCollection<IMapDialogueOpcode> NestedOpcodes { get; set; } = new();

public static IMapDialogueOpcode ReadOpcode(Stream reader)
{
return new HighlightEndOpcode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace G2DataGUI.Common.Data.Maps.MapDialogueOpcodes.Highlight;

public enum HighlightOption : byte
{
Start = 0x0C,
End = 0x0F,
}
Loading

0 comments on commit 2973d98

Please sign in to comment.