Skip to content

Commit

Permalink
add more textbox opcodes, document additional potential opcodes
Browse files Browse the repository at this point in the history
  • Loading branch information
krogenth committed Aug 12, 2023
1 parent fd1cc2e commit a7a5a7b
Show file tree
Hide file tree
Showing 20 changed files with 370 additions and 122 deletions.
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
64 changes: 39 additions & 25 deletions src/G2DataGUI.Common/Data/Maps/MapDialogue.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
using System.Collections.Generic;
using System.IO;
using G2DataGUI.Common.Data.Maps.MapDialogueOpcodes;
using G2DataGUI.Common.Data.Maps.MapDialogueOpcode;
using G2DataGUI.IO.Streams;
using G2DataGUI.Common.Extensions;
using System.Linq;
using System;

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

public static MapDialogue ReadMapDialogue(Stream reader, uint dialogueSectionLength, string mapname)
{
Expand All @@ -18,34 +20,46 @@ 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;
// using MemoryStream memReader = new();
var dialogueStartPosition = reader.Position;
for (var index = 1; index < dialogue.Header.Offsets.Count; index++)
{
dialogue.DialogueSectionOpcodes.Add(new List<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);
// }
// }
// 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)
{
try
{
var opcode = IMapDialogueOpcode.ParseNextOpcode(memReader);
if (opcode != null)
{
dialogue.DialogueSectionOpcodes.Last().Add(opcode);
}
}
catch (Exception ex)
{
throw ex;

Check warning on line 47 in src/G2DataGUI.Common/Data/Maps/MapDialogue.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, Debug)

Re-throwing caught exception changes stack information (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2200)

Check warning on line 47 in src/G2DataGUI.Common/Data/Maps/MapDialogue.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, Debug)

Re-throwing caught exception changes stack information (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2200)

Check warning on line 47 in src/G2DataGUI.Common/Data/Maps/MapDialogue.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, Release)

Re-throwing caught exception changes stack information (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2200)

Check warning on line 47 in src/G2DataGUI.Common/Data/Maps/MapDialogue.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x, Release)

Re-throwing caught exception changes stack information (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2200)
}
}
}

// if (!Directory.Exists("dialogue_sections"))
// {
// Directory.CreateDirectory("dialogue_sections");
// }
if (!Directory.Exists("dialogue_sections"))
{
Directory.CreateDirectory("dialogue_sections");
}

// if (!Directory.Exists($"dialogue_sections/{mapname}"))
// {
// Directory.CreateDirectory($"dialogue_sections/{mapname}");
// }
if (!Directory.Exists($"dialogue_sections/{mapname}"))
{
Directory.CreateDirectory($"dialogue_sections/{mapname}");
}

var dialogueStartPosition = reader.Position;
//var dialogueStartPosition = reader.Position;
reader.Seek(dialogueStartPosition, SeekOrigin.Begin);
//var dialogueStartPosition = reader.Position;
for (var index = 1; index < dialogue.Header.Offsets.Count; index++)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System.IO;
using G2DataGUI.IO.Streams;

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

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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System.IO;
using G2DataGUI.IO.Streams;

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

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

/// <summary>
/// Appears to always be 0x00
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.Collections.Generic;
using System.IO;
using G2DataGUI.Common.Data.Maps.MapDialogueOpcode;
using G2DataGUI.Common.Extensions;
using G2DataGUI.IO.Streams;

namespace G2DataGUI.Common.Data.Maps.MapDialogueOpcodes;

/// <summary>
/// Creates a textbox in the top-left of the screen
/// that displays a list of options for the palyer to choose from.
/// </summary>
public class CreateOptionsTextBoxOpcode : ITextBoxOpcode, IMapDialogueOpcode
{
public DialogueOpcode Opcode { get; set; } = DialogueOpcode.TextBox;
public TextBoxOption Option { get; set; } = TextBoxOption.CreateOptionsTextBox;
public byte TextBoxLength { get; set; }
public byte TextBoxHeight { get; set; }
public IList<IMapDialogueOpcode> NestedOpcodes { get; set; } = new List<IMapDialogueOpcode>();

public static IMapDialogueOpcode ReadOpcode(Stream reader)
{
CreateOptionsTextBoxOpcode opcode = new()
{
TextBoxLength = reader.ReadRawByte(),
TextBoxHeight = reader.ReadRawByte(),
};

do
{
byte data = reader.ReadRawByte();
if (data.EnumExists<DialogueOpcode>())
{
switch (data.ToEnum<DialogueOpcode>())
{
case DialogueOpcode.ScriptCall:
opcode.NestedOpcodes.Add(ScriptCallOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.CameraMove:
opcode.NestedOpcodes.Add(CameraMoveOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.ItemAquire:
opcode.NestedOpcodes.Add(ItemAcquireOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.CharacterPortait:
opcode.NestedOpcodes.Add(CharacterPortaitOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.NextPage:
opcode.NestedOpcodes.Add(NextPageOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.Pause:
opcode.NestedOpcodes.Add(PauseOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.NextLine:
opcode.NestedOpcodes.Add(NextLineOpcode.ReadOpcode(reader));
break;
// textbox removal should be the only thing that returns the textbox
// should verify it isn't a textbox within a textbox(is that even possible?)
case DialogueOpcode.TextBox:
opcode.NestedOpcodes.Add(ITextBoxOpcode.ReadOpcode(reader));
return opcode;
}
}
else
{
reader.Seek(-1, SeekOrigin.Current);
opcode.NestedOpcodes.Add(TextOpcode.ReadOpcode(reader));
}
} while (true);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
using System.Collections.Generic;
using System.IO;
using System.Reflection.Emit;
using G2DataGUI.Common.Extensions;
using G2DataGUI.IO.Streams;

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

public class CreateOverworldTextBoxOpcode : ITextBoxOpcode, IMapDialogueOpcodeReader
{
public DialogueOpcodes Opcode { get; set; } = DialogueOpcodes.TextBox;
public TextBoxOptions Option { get; set; } = TextBoxOptions.CreateOverworldTextBox;
public DialogueOpcode Opcode { get; set; } = DialogueOpcode.TextBox;
public TextBoxOption Option { get; set; } = TextBoxOption.CreateOverworldTextBox;
public byte TextBoxLength { get; set; }
public byte TextBoxHeight { get; set; }
public IList<IMapDialogueOpcode> NestedOpcodes { get; set; } = new List<IMapDialogueOpcode>();
Expand All @@ -18,7 +17,6 @@ public static IMapDialogueOpcode ReadOpcode(Stream reader)
{
CreateOverworldTextBoxOpcode opcode = new()
{
Option = (TextBoxOptions)reader.ReadRawByte(),
TextBoxLength = reader.ReadRawByte(),
TextBoxHeight = reader.ReadRawByte(),
};
Expand All @@ -30,34 +28,34 @@ public static IMapDialogueOpcode ReadOpcode(Stream reader)
do
{
data = reader.ReadRawByte();
if (data.EnumExists<DialogueOpcodes>())
if (data.EnumExists<DialogueOpcode>())
{
switch (data.ToEnum<DialogueOpcodes>())
switch (data.ToEnum<DialogueOpcode>())
{
case DialogueOpcodes.ScriptCall:
case DialogueOpcode.ScriptCall:
opcode.NestedOpcodes.Add(ScriptCallOpcode.ReadOpcode(reader));
break;
case DialogueOpcodes.CameraMove:
case DialogueOpcode.CameraMove:
opcode.NestedOpcodes.Add(CameraMoveOpcode.ReadOpcode(reader));
break;
case DialogueOpcodes.ItemAquire:
case DialogueOpcode.ItemAquire:
opcode.NestedOpcodes.Add(ItemAcquireOpcode.ReadOpcode(reader));
break;
case DialogueOpcodes.CharacterPortait:
case DialogueOpcode.CharacterPortait:
opcode.NestedOpcodes.Add(CharacterPortaitOpcode.ReadOpcode(reader));
break;
case DialogueOpcodes.NextPage:
case DialogueOpcode.NextPage:
opcode.NestedOpcodes.Add(NextPageOpcode.ReadOpcode(reader));
break;
case DialogueOpcodes.Pause:
case DialogueOpcode.Pause:
opcode.NestedOpcodes.Add(PauseOpcode.ReadOpcode(reader));
break;
case DialogueOpcodes.NextLine:
case DialogueOpcode.NextLine:
opcode.NestedOpcodes.Add(NextLineOpcode.ReadOpcode(reader));
break;
// textbox removal should be the only thing that returns the textbox
// should verify it isn't a textbox within a textbox(is that even possible?)
case DialogueOpcodes.TextBox:
case DialogueOpcode.TextBox:
opcode.NestedOpcodes.Add(ITextBoxOpcode.ReadOpcode(reader));
return opcode;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using G2DataGUI.Common.Extensions;
using G2DataGUI.IO.Streams;

namespace G2DataGUI.Common.Data.Maps.MapDialogueOpcode;

/// <summary>
/// Defines a sub textbox that appears during dialogue.
/// Sub textboxes appear overlapping the primary textbox
/// in the top-right of the primary textbox.
/// </summary>
internal class CreateSubTextBoxOpcode : ITextBoxOpcode, IMapDialogueOpcode
{
public DialogueOpcode Opcode { get; set; } = DialogueOpcode.TextBox;
public TextBoxOption Option { get; set; } = TextBoxOption.CreateSubTextBox;
public byte Unknown1 { get; set; }
public byte TextBoxHeight { get; set; }
public IList<IMapDialogueOpcode> NestedOpcodes { get; set; } = new List<IMapDialogueOpcode>();

public static IMapDialogueOpcode ReadOpcode(Stream reader)
{
CreateSubTextBoxOpcode opcode = new()
{
Unknown1 = reader.ReadRawByte(),
TextBoxHeight = reader.ReadRawByte(),
};

do
{
byte data = reader.ReadRawByte();
if (data.EnumExists<DialogueOpcode>())
{
switch (data.ToEnum<DialogueOpcode>())
{
case DialogueOpcode.ScriptCall:
opcode.NestedOpcodes.Add(ScriptCallOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.CameraMove:
opcode.NestedOpcodes.Add(CameraMoveOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.ItemAquire:
opcode.NestedOpcodes.Add(ItemAcquireOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.CharacterPortait:
opcode.NestedOpcodes.Add(CharacterPortaitOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.NextPage:
opcode.NestedOpcodes.Add(NextPageOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.Pause:
opcode.NestedOpcodes.Add(PauseOpcode.ReadOpcode(reader));
break;
case DialogueOpcode.NextLine:
opcode.NestedOpcodes.Add(NextLineOpcode.ReadOpcode(reader));
break;
// textbox removal should be the only thing that returns the textbox
// should verify it isn't a textbox within a textbox(is that even possible?)
case DialogueOpcode.TextBox:
opcode.NestedOpcodes.Add(ITextBoxOpcode.ReadOpcode(reader));
return opcode;
}
}
else
{
reader.Seek(-1, SeekOrigin.Current);
opcode.NestedOpcodes.Add(TextOpcode.ReadOpcode(reader));
}
} while (true);
}
}
Loading

0 comments on commit a7a5a7b

Please sign in to comment.