public void ReadLabdata(Labdata labdata, IDataReader dataReader, IGameData gameData) { labdata.WallHeight = dataReader.ReadWord(); labdata.CombatBackground = dataReader.ReadWord() & 0x0fu; labdata.CeilingColorIndex = dataReader.ReadByte(); labdata.FloorColorIndex = dataReader.ReadByte(); // Note: The ceiling texture index can be 0 in which case a sky is used. // The sky is composed of a color gradient and a lab background // which is given inside the map data. // To be more precisely if the texture index (ceiling and also floor) is // 0, the color index is used to draw instead. For example the town of // S'Angrila doesn't use a floor texture but only a color. uint ceilingTextureIndex = dataReader.ReadByte(); uint floorTextureIndex = dataReader.ReadByte(); labdata.Objects.Clear(); int numObjects = dataReader.ReadWord(); var objects = new List <Tuple <ushort, List <Tuple <short, short, short, int> > > >(numObjects); for (int i = 0; i < numObjects; ++i) { var obj = Tuple.Create(dataReader.ReadWord(), new List <Tuple <short, short, short, int> >(8)); for (int n = 0; n < 8; ++n) // 8 sub entries (a map object can consist of up to 8 sub objects) { obj.Item2.Add(Tuple.Create( (short)dataReader.ReadWord(), (short)dataReader.ReadWord(), (short)dataReader.ReadWord(), (int)dataReader.ReadWord())); } objects.Add(obj); } labdata.ObjectInfos.Clear(); int numObjectInfos = dataReader.ReadWord(); for (int i = 0; i < numObjectInfos; ++i) { var objectInfo = new Labdata.ObjectInfo { Flags = (Tileset.TileFlags)dataReader.ReadDword(), TextureIndex = dataReader.ReadWord(), NumAnimationFrames = dataReader.ReadByte(), ColorIndex = dataReader.ReadByte(), TextureWidth = dataReader.ReadByte(), TextureHeight = dataReader.ReadByte(), MappedTextureWidth = dataReader.ReadWord(), MappedTextureHeight = dataReader.ReadWord() }; labdata.ObjectInfos.Add(objectInfo); } foreach (var obj in objects) { var subObjects = new List <Labdata.ObjectPosition>(8); foreach (var pos in obj.Item2) { if (pos.Item4 != 0) { subObjects.Add(new Labdata.ObjectPosition { X = pos.Item1, Y = pos.Item2, Z = pos.Item3, Object = labdata.ObjectInfos[pos.Item4 - 1] }); } } labdata.Objects.Add(new Labdata.Object { AutomapType = (AutomapType)obj.Item1, SubObjects = subObjects }); } labdata.Walls.Clear(); int numWalls = dataReader.ReadWord(); for (int i = 0; i < numWalls; ++i) { var wallData = new Labdata.WallData { Flags = (Tileset.TileFlags)dataReader.ReadDword(), TextureIndex = dataReader.ReadByte(), AutomapType = (AutomapType)dataReader.ReadByte(), ColorIndex = dataReader.ReadByte() }; int numOverlays = dataReader.ReadByte(); if (numOverlays != 0) { wallData.Overlays = new Labdata.OverlayData[numOverlays]; for (int o = 0; o < numOverlays; ++o) { wallData.Overlays[o] = new Labdata.OverlayData { Blend = dataReader.ReadByte() != 0, TextureIndex = dataReader.ReadByte(), PositionX = dataReader.ReadByte(), PositionY = dataReader.ReadByte(), TextureWidth = dataReader.ReadByte(), TextureHeight = dataReader.ReadByte() }; } } labdata.Walls.Add(wallData); } // Load labyrinth graphics var graphicReader = new GraphicReader(); if (floorTextureIndex != 0) { labdata.FloorGraphic = ReadGraphic(graphicReader, gameData.Files["Floors.amb"].Files[(int)floorTextureIndex], 64, 64, false, false, true); } if (ceilingTextureIndex != 0) { labdata.CeilingGraphic = ReadGraphic(graphicReader, gameData.Files["Floors.amb"].Files[(int)ceilingTextureIndex], 64, 64, false, false, true); } var objectTextureFiles = gameData.Files[$"2Object3D.amb"].Files; gameData.Files[$"3Object3D.amb"].Files.ToList().ForEach(f => objectTextureFiles[f.Key] = f.Value); labdata.ObjectGraphics.Clear(); foreach (var objectInfo in labdata.ObjectInfos) { if (objectInfo.NumAnimationFrames == 1) { labdata.ObjectGraphics.Add(ReadGraphic(graphicReader, objectTextureFiles[(int)objectInfo.TextureIndex], (int)objectInfo.TextureWidth, (int)objectInfo.TextureHeight, true, true, true)); } else { var compoundGraphic = new Graphic((int)objectInfo.NumAnimationFrames * (int)objectInfo.TextureWidth, (int)objectInfo.TextureHeight, 0); for (uint i = 0; i < objectInfo.NumAnimationFrames; ++i) { var partialGraphic = ReadGraphic(graphicReader, objectTextureFiles[(int)objectInfo.TextureIndex], (int)objectInfo.TextureWidth, (int)objectInfo.TextureHeight, true, true, i == 0); compoundGraphic.AddOverlay(i * objectInfo.TextureWidth, 0u, partialGraphic, false); } labdata.ObjectGraphics.Add(compoundGraphic); } } var wallTextureFiles = gameData.Files[$"2Wall3D.amb"].Files; var overlayTextureFiles = gameData.Files[$"2Overlay3D.amb"].Files; gameData.Files[$"3Wall3D.amb"].Files.ToList().ForEach(f => wallTextureFiles[f.Key] = f.Value); gameData.Files[$"3Overlay3D.amb"].Files.ToList().ForEach(f => overlayTextureFiles[f.Key] = f.Value); labdata.WallGraphics.Clear(); int wallIndex = 0; foreach (var wall in labdata.Walls) { var wallGraphic = ReadGraphic(graphicReader, wallTextureFiles[(int)wall.TextureIndex], 128, 80, wall.Flags.HasFlag(Tileset.TileFlags.Transparency), true, true); labdata.WallGraphics.Add(wallGraphic); if (wall.Overlays != null && wall.Overlays.Length != 0) { foreach (var overlay in wall.Overlays) { wallGraphic.AddOverlay(overlay.PositionX, overlay.PositionY, ReadGraphic(graphicReader, overlayTextureFiles[(int)overlay.TextureIndex], (int)overlay.TextureWidth, (int)overlay.TextureHeight, true, true, true), overlay.Blend); } } ++wallIndex; } }
public void ReadLabdata(Labdata labdata, IDataReader dataReader, IGameData gameData) { labdata.WallHeight = dataReader.ReadWord(); labdata.Unknown1 = dataReader.ReadByte(); // Unknown labdata.CombatBackground = dataReader.ReadByte() & 0x0fu; labdata.Unknown2 = dataReader.ReadBytes(2); // Unknown // Note: The ceiling texture index can be 0 in which case a sky is used. // The sky is composed of a color gradient and a lab background // which is given inside the map data. uint ceilingTextureIndex = dataReader.ReadByte(); uint floorTextureIndex = dataReader.ReadByte(); labdata.Objects.Clear(); int numObjects = dataReader.ReadWord(); var objects = new List <Tuple <ushort, List <Tuple <float, float, float, int> > > >(numObjects); for (int i = 0; i < numObjects; ++i) { var obj = Tuple.Create(dataReader.ReadWord(), new List <Tuple <float, float, float, int> >(8)); for (int n = 0; n < 8; ++n) // 8 sub entries (a map object can consist of up to 8 sub objects) { obj.Item2.Add(Tuple.Create( (float)(short)dataReader.ReadWord(), (float)(short)dataReader.ReadWord(), (float)(short)dataReader.ReadWord(), (int)dataReader.ReadWord())); } objects.Add(obj); } labdata.ObjectInfos.Clear(); int numObjectInfos = dataReader.ReadWord(); for (int i = 0; i < numObjectInfos; ++i) { var objectInfo = new Labdata.ObjectInfo { Unknown1 = dataReader.ReadBytes(3), // TODO: Collision info for all 3 axes? Flags = (Labdata.ObjectFlags)dataReader.ReadByte(), TextureIndex = dataReader.ReadWord(), NumAnimationFrames = dataReader.ReadByte(), Unknown2 = dataReader.ReadByte(), TextureWidth = dataReader.ReadByte(), TextureHeight = dataReader.ReadByte(), MappedTextureWidth = dataReader.ReadWord(), MappedTextureHeight = dataReader.ReadWord() }; labdata.ObjectInfos.Add(objectInfo); //Console.WriteLine($"Type: {objectInfo.Type}, Texture: {objectInfo.TextureIndex},{objectInfo.TextureWidth}x{objectInfo.TextureHeight} -> {objectInfo.MappedTextureWidth}x{objectInfo.MappedTextureHeight}, Frames: {objectInfo.NumAnimationFrames}"); } foreach (var obj in objects) { var subObjects = new List <Labdata.ObjectPosition>(8); foreach (var pos in obj.Item2) { if (pos.Item4 != 0) { subObjects.Add(new Labdata.ObjectPosition { X = pos.Item1, Y = pos.Item2, Z = pos.Item3, Object = labdata.ObjectInfos[pos.Item4 - 1] }); } } labdata.Objects.Add(new Labdata.Object { Header = obj.Item1, SubObjects = subObjects }); } labdata.Walls.Clear(); int numWalls = dataReader.ReadWord(); for (int i = 0; i < numWalls; ++i) { var wallData = new Labdata.WallData { Unknown1 = dataReader.ReadBytes(3), // TODO: Collision info for all 3 axes? Flags = (Labdata.WallFlags)dataReader.ReadByte(), TextureIndex = dataReader.ReadByte(), AutomapType = (AutomapType)dataReader.ReadByte(), Unknown2 = dataReader.ReadByte() }; int numOverlays = dataReader.ReadByte(); if (numOverlays != 0) { wallData.Overlays = new Labdata.OverlayData[numOverlays]; for (int o = 0; o < numOverlays; ++o) { wallData.Overlays[o] = new Labdata.OverlayData { NumAnimationFrames = dataReader.ReadByte(), TextureIndex = dataReader.ReadByte(), PositionX = dataReader.ReadByte(), PositionY = dataReader.ReadByte(), TextureWidth = dataReader.ReadByte(), TextureHeight = dataReader.ReadByte() }; } } labdata.Walls.Add(wallData); //Console.WriteLine($"Wall{i+1} -> {wallData}"); } // Load labyrinth graphics var graphicReader = new GraphicReader(); if (floorTextureIndex != 0) { labdata.FloorGraphic = ReadGraphic(graphicReader, gameData.Files["Floors.amb"].Files[(int)floorTextureIndex], 64, 64, false, false); } if (ceilingTextureIndex != 0) { labdata.CeilingGraphic = ReadGraphic(graphicReader, gameData.Files["Floors.amb"].Files[(int)ceilingTextureIndex], 64, 64, false, false); // TODO } var objectTextureFiles = gameData.Files[$"2Object3D.amb"].Files; gameData.Files[$"3Object3D.amb"].Files.ToList().ForEach(f => objectTextureFiles[f.Key] = f.Value); labdata.ObjectGraphics.Clear(); foreach (var objectInfo in labdata.ObjectInfos) { labdata.ObjectGraphics.Add(ReadGraphic(graphicReader, objectTextureFiles[(int)objectInfo.TextureIndex], (int)objectInfo.TextureWidth, (int)objectInfo.TextureHeight, true, true)); } var wallTextureFiles = gameData.Files[$"2Wall3D.amb"].Files; var overlayTextureFiles = gameData.Files[$"2Overlay3D.amb"].Files; gameData.Files[$"3Wall3D.amb"].Files.ToList().ForEach(f => wallTextureFiles[f.Key] = f.Value); gameData.Files[$"3Overlay3D.amb"].Files.ToList().ForEach(f => overlayTextureFiles[f.Key] = f.Value); labdata.WallGraphics.Clear(); int wallIndex = 0; foreach (var wall in labdata.Walls) { var wallGraphic = ReadGraphic(graphicReader, wallTextureFiles[(int)wall.TextureIndex], 128, 80, wall.Flags.HasFlag(Labdata.WallFlags.Transparency), true); labdata.WallGraphics.Add(wallGraphic); if (wall.Overlays != null && wall.Overlays.Length != 0) { foreach (var overlay in wall.Overlays) { wallGraphic.AddOverlay(overlay.PositionX, overlay.PositionY, ReadGraphic(graphicReader, overlayTextureFiles[(int)overlay.TextureIndex], (int)overlay.TextureWidth, (int)overlay.TextureHeight, true, true)); } } ++wallIndex; } }