/// <summary> /// The position of the data reader should be at /// the start of the message sections just behind the /// insert disk messages. /// /// It will be behind all the message sections after this. /// </summary> internal Messages(IDataReader dataReader) { while (Entries.Count < NumFirstMessages) { ReadText(dataReader); } --dataReader.Position; dataReader.AlignToWord(); int numIndices = (int)dataReader.ReadDword(); UnknownIndices = new List <uint>(numIndices); for (int i = 0; i < numIndices; ++i) { UnknownIndices.Add(dataReader.ReadWord()); } while (Entries.Count < NumFirstMessages + NumSecondMessages) { ReadText(dataReader); } dataReader.AlignToWord(); }
// Second data hunk, right behind UITexts. internal Buttons(IDataReader dataReader) { var graphicInfo = new GraphicInfo { Width = 32, Height = 13, Alpha = true, GraphicFormat = GraphicFormat.Palette3Bit, PaletteOffset = 24 }; var graphicReader = new GraphicReader(); Graphic ReadGraphic(IDataReader dataReader) { var graphic = new Graphic(); graphicReader.ReadGraphic(graphic, dataReader, graphicInfo); return(graphic); } foreach (var buttonType in Enum.GetValues <ButtonType>()) { entries.Add(buttonType, ReadGraphic(dataReader)); } dataReader.AlignToWord(); }
/// <summary> /// The position of the data reader should be at /// the start of the message sections just behind the /// insert disk messages. /// /// It will be behind all the message sections after this. /// </summary> internal Messages(IDataReader dataReader) { while (ReadText(dataReader)) { ; } int numTextEntries = (int)dataReader.ReadDword(); var textEntryLengths = new List <uint>(numTextEntries); for (int i = 0; i < numTextEntries; ++i) { textEntryLengths.Add(dataReader.ReadWord()); } for (int i = 0; i < numTextEntries; ++i) { entries.Add(dataReader.ReadString((int)textEntryLengths[i], AmigaExecutable.Encoding).TrimEnd('\0')); } dataReader.AlignToWord(); if (dataReader.PeekWord() == 0) { dataReader.Position += 2; } }
/// <summary> /// The position of the data reader should be at /// the start of the automap names just behind the /// messages. /// /// It will be behind the automap names after this. /// </summary> internal AutomapNames(IDataReader dataReader) { foreach (var type in Enum.GetValues(typeof(AutomapType))) { Entries.Add((AutomapType)type, dataReader.ReadNullTerminatedString()); } dataReader.AlignToWord(); }
/// <summary> /// The position of the data reader should be at /// the start of the song names just behind the /// option names. /// /// It will be behind the song names after this. /// </summary> internal SongNames(IDataReader dataReader) { for (int i = 0; i < NumSongs; ++i) { Entries.Add(dataReader.ReadNullTerminatedString()); } dataReader.AlignToWord(); }
/// <summary> /// The position of the data reader should be at /// the start of the option names just behind the /// automap names. /// /// It will be behind the option names after this. /// </summary> internal OptionNames(IDataReader dataReader) { foreach (Option type in Enum.GetValues(typeof(Option))) { Entries.Add(type, dataReader.ReadNullTerminatedString()); } dataReader.AlignToWord(); }
/// <summary> /// The position of the data reader should be at /// the start of the automap names just behind the /// messages. /// /// It will be behind the automap names after this. /// </summary> internal AutomapNames(IDataReader dataReader) { entries.Add(AutomapType.None, ""); entries.Add(AutomapType.Wall, ""); foreach (var type in Enum.GetValues <AutomapType>().Skip(2).Take(17)) { entries.Add(type, dataReader.ReadNullTerminatedString(AmigaExecutable.Encoding)); } dataReader.AlignToWord(); }
void ReadText(IDataReader dataReader) { if (dataReader.PeekWord() == 0) // offset section / split text with placeholders { dataReader.AlignToWord(); if (dataReader.PeekWord() != 0) { throw new AmbermoonException(ExceptionScope.Data, "Invalid text section."); } while (dataReader.PeekDword() == 0) { dataReader.Position += 4; } string text = ""; var offsets = new List <uint>(); int endOffset = dataReader.Position; while (dataReader.PeekByte() == 0) { offsets.Add(dataReader.ReadDword()); dataReader.ReadDword(); // TODO: always 0? Maybe some placeholder index reshifting? } for (int i = 0; i < offsets.Count; ++i) { dataReader.Position = (int)offsets[i]; text += dataReader.ReadNullTerminatedString(); if (i != offsets.Count - 1) // Insert placeholder { text += "{" + i + "}"; } if (dataReader.Position > endOffset) { endOffset = dataReader.Position; } } Entries.Add(text); dataReader.Position = endOffset; } else // just a text { Entries.Add(dataReader.ReadNullTerminatedString()); } }
/// <summary> /// The position of the data reader should be at /// the start of the option names just behind the /// automap names. /// /// It will be behind the option names after this. /// </summary> internal OptionNames(IDataReader dataReader) { foreach (var type in Enum.GetValues <Option>()) { entries.Add(type, dataReader.ReadNullTerminatedString(AmigaExecutable.Encoding)); if (type == Option.CeilingTexture3D) { break; // stop here } } dataReader.AlignToWord(); }
/// <summary> /// The position of the data reader should be at /// the start of the UI texts just behind the /// ailment names. /// /// It will be behind the UI texts after this. /// </summary> internal UITexts(IDataReader dataReader) { foreach (var type in Enum.GetValues <UITextIndex>()) { // TODO: This needs improvement! var text = dataReader.ReadNullTerminatedString(AmigaExecutable.Encoding); text = text.Replace("0123456789", "{1:1111111111}"); text = text.Replace("012345678", "{1:111111111}"); text = text.Replace("01234567", "{1:11111111}"); text = text.Replace("0123456", "{1:1111111}"); text = text.Replace("012345", "{1:111111}"); text = text.Replace("01234", "{1:11111}"); text = text.Replace("0123", "{1:1111}"); text = text.Replace("012", "{1:111}"); text = text.Replace("01", "{1:11}"); text = text.Replace("0", "{1:1}"); text = text.Replace('1', '0'); int offset = 0; int n = 0; while (offset < text.Length) { int index = text.IndexOf("0:", offset); if (index == -1) { break; } if (n == 0) { ++n; } else { text = text.Remove(index, 1); text = text.Insert(index, (n++).ToString()); } offset = index + 3; } entries.Add(type, text); } dataReader.AlignToWord(); }
/// <summary> /// The position of the data reader should be at /// the start of the song names just behind the /// option names. /// /// It will be behind the song names after this. /// </summary> internal SongNames(IDataReader dataReader) { string ReadName() { var name = dataReader.ReadNullTerminatedString(AmigaExecutable.Encoding); if (string.IsNullOrWhiteSpace(name)) { name = "No name"; } return(name); } for (int i = 1; i <= NumSongs; ++i) { entries.Add((Song)i, ReadName()); } dataReader.AlignToWord(); }
/// <summary> /// The position of the data reader should be at /// the start of the world names just behind the /// file list. /// /// It will be behind the world names after this. /// </summary> internal WorldNames(IDataReader dataReader) { var offsets = new uint[3]; int endOffset = dataReader.Position; for (int i = 0; i < 3; ++i) { offsets[i] = dataReader.ReadDword(); } for (int i = 0; i < 3; ++i) { dataReader.Position = (int)offsets[i]; entries.Add((World)i, dataReader.ReadNullTerminatedString(AmigaExecutable.Encoding)); if (dataReader.Position > endOffset) { endOffset = dataReader.Position; } } dataReader.Position = endOffset; dataReader.AlignToWord(); }
/// <summary> /// The position of the data reader should be at /// the start of the file list. /// /// It will be behind the file list after this. /// </summary> internal FileList(IDataReader dataReader) { int numEntries = dataReader.ReadWord() * 4; dataReader.ReadWord(); // TODO: always 0? var offsets = new uint[numEntries]; int endOffset = dataReader.Position; for (int i = 0; i < numEntries; ++i) { offsets[i] = dataReader.ReadDword(); } for (int i = 0; i < numEntries; ++i) { if (offsets[i] == 0) { IndexedEntries.Add(new string[0]); continue; } dataReader.Position = (int)offsets[i]; byte diskNumber = dataReader.ReadByte(); if (dataReader.PeekByte() >= 0x20) { if (diskNumber == 0) { throw new AmbermoonException(ExceptionScope.Data, "Invalid disk number 0."); } string filename = dataReader.ReadNullTerminatedString(); Entries[filename] = (char)('A' + diskNumber - 1); IndexedEntries.Add(new string[1] { filename }); } else { --dataReader.Position; var diskNumbers = dataReader.ReadBytes(4); var baseFileName = dataReader.ReadNullTerminatedString(); string[] filenames = new string[4]; for (int d = 0; d < 4; ++d) { if (diskNumbers[d] != 0) { string filename = baseFileName.Replace('0', (char)('1' + d)); Entries[filename] = (char)('A' + diskNumbers[d] - 1); filenames[d] = filename; } } IndexedEntries.Add(filenames); } if (dataReader.Position > endOffset) { endOffset = dataReader.Position; } } dataReader.Position = endOffset; dataReader.AlignToWord(); }
bool ReadText(IDataReader dataReader) { // The next section starts with an amount of 300 as a dword. // If we find it we stop reading by returning false. For safety // we will check if the value is lower than 0x1000 as the offsets // here will be over 0x8000. var next = dataReader.PeekDword(); var nextWord = next >> 8; if (nextWord > 0x100 && nextWord < 0x1000) { --dataReader.Position; return(false); } nextWord >>= 8; if (nextWord > 0x100 && nextWord < 0x1000) { dataReader.Position -= 2; return(false); } nextWord >>= 8; if (nextWord > 0x100 && nextWord < 0x1000) { dataReader.Position -= 3; return(false); } if (dataReader.PeekWord() == 0) // offset section / split text with placeholders { dataReader.AlignToWord(); if (dataReader.PeekWord() != 0) { throw new AmbermoonException(ExceptionScope.Data, "Invalid text section."); } while (dataReader.PeekDword() == 0) { dataReader.Position += 4; } if (dataReader.PeekByte() != 0) { dataReader.Position -= 2; } string text = ""; var offsets = new List <uint>(); int endOffset = dataReader.Position; uint firstOffset = uint.MaxValue; while (dataReader.PeekByte() == 0 && dataReader.Position < firstOffset) { var offset = dataReader.ReadDword(); if (offset != 0) { if (offset < firstOffset) { firstOffset = offset; } offsets.Add(offset); } } for (int i = 0; i < offsets.Count; ++i) { dataReader.Position = (int)offsets[i]; text += dataReader.ReadNullTerminatedString(AmigaExecutable.Encoding); if (i != offsets.Count - 1) // Insert placeholder { text += "{" + i + "}"; } if (dataReader.Position > endOffset) { endOffset = dataReader.Position; } } entries.Add(text); dataReader.Position = endOffset; } else // just a text { entries.Add(dataReader.ReadNullTerminatedString(AmigaExecutable.Encoding)); bool sectionFollows = dataReader.PeekDword() == 0; while (dataReader.PeekByte() == 0 || dataReader.PeekByte() == 0xff) { if (sectionFollows) { if ((dataReader.PeekDword() & 0x0000ffff) > 0xff) { break; } } else { sectionFollows = dataReader.PeekDword() == 0; } ++dataReader.Position; } } return(true); }