#region References using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.IO; using System.Text; using System.Text.RegularExpressions; #endregion namespace Ultima { public sealed class Multis { private static MultiComponentList[] m_Components = new MultiComponentList[0x2000]; private static FileIndex m_FileIndex = new FileIndex("Multi.idx", "Multi.mul", 0x2000, 14); public enum ImportType { TXT, UOA, UOAB, WSC, MULTICACHE, UOADESIGN } public static bool PostHSFormat { get; set; } /// /// ReReads multi.mul /// public static void Reload() { m_FileIndex = new FileIndex("Multi.idx", "Multi.mul", 0x2000, 14); m_Components = new MultiComponentList[0x2000]; } /// /// Gets of multi /// /// /// public static MultiComponentList GetComponents(int index) { MultiComponentList mcl; index &= 0x1FFF; if (index >= 0 && index < m_Components.Length) { mcl = m_Components[index]; if (mcl == null) { m_Components[index] = mcl = Load(index); } } else { mcl = MultiComponentList.Empty; } return mcl; } public static MultiComponentList Load(int index) { try { int length, extra; bool patched; Stream stream = m_FileIndex.Seek(index, out length, out extra, out patched); if (stream == null) { return MultiComponentList.Empty; } if (PostHSFormat || Art.IsUOAHS()) { return new MultiComponentList(new BinaryReader(stream), length / 16); } else { return new MultiComponentList(new BinaryReader(stream), length / 12); } } catch { return MultiComponentList.Empty; } } public static void Remove(int index) { m_Components[index] = MultiComponentList.Empty; } public static void Add(int index, MultiComponentList comp) { m_Components[index] = comp; } public static MultiComponentList ImportFromFile(int index, string FileName, ImportType type) { try { return m_Components[index] = new MultiComponentList(FileName, type); } catch { return m_Components[index] = MultiComponentList.Empty; } } public static MultiComponentList LoadFromFile(string FileName, ImportType type) { try { return new MultiComponentList(FileName, type); } catch { return MultiComponentList.Empty; } } public static List LoadFromCache(string FileName) { var multilist = new List(); using (var ip = new StreamReader(FileName)) { string line; while ((line = ip.ReadLine()) != null) { string[] split = Regex.Split(line, @"\s+"); if (split.Length == 7) { int count = Convert.ToInt32(split[2]); multilist.Add(new MultiComponentList(ip, count)); } } } return multilist; } public static string ReadUOAString(BinaryReader bin) { byte flag = bin.ReadByte(); if (flag == 0) { return null; } else { return bin.ReadString(); } } public static List LoadFromDesigner(string FileName) { var multilist = new List(); string root = Path.GetFileNameWithoutExtension(FileName); string idx = String.Format("{0}.idx", root); string bin = String.Format("{0}.bin", root); if ((!File.Exists(idx)) || (!File.Exists(bin))) { return multilist; } using ( FileStream idxfs = new FileStream(idx, FileMode.Open, FileAccess.Read, FileShare.Read), binfs = new FileStream(bin, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (BinaryReader idxbin = new BinaryReader(idxfs), binbin = new BinaryReader(binfs)) { int count = idxbin.ReadInt32(); int version = idxbin.ReadInt32(); for (int i = 0; i < count; ++i) { var data = new Object[2]; switch (version) { case 0: data[0] = ReadUOAString(idxbin); var arr = new List(); data[0] += "-" + ReadUOAString(idxbin); data[0] += "-" + ReadUOAString(idxbin); int width = idxbin.ReadInt32(); int height = idxbin.ReadInt32(); int uwidth = idxbin.ReadInt32(); int uheight = idxbin.ReadInt32(); long filepos = idxbin.ReadInt64(); int reccount = idxbin.ReadInt32(); binbin.BaseStream.Seek(filepos, SeekOrigin.Begin); int index, x, y, z, level, hue; for (int j = 0; j < reccount; ++j) { index = x = y = z = level = hue = 0; int compVersion = binbin.ReadInt32(); switch (compVersion) { case 0: index = binbin.ReadInt32(); x = binbin.ReadInt32(); y = binbin.ReadInt32(); z = binbin.ReadInt32(); level = binbin.ReadInt32(); break; case 1: index = binbin.ReadInt32(); x = binbin.ReadInt32(); y = binbin.ReadInt32(); z = binbin.ReadInt32(); level = binbin.ReadInt32(); hue = binbin.ReadInt32(); break; } var tempitem = new MultiComponentList.MultiTileEntry(); tempitem.m_ItemID = (ushort)index; tempitem.m_Flags = TileFlag.Background; tempitem.m_OffsetX = (short)x; tempitem.m_OffsetY = (short)y; tempitem.m_OffsetZ = (short)z; arr.Add(tempitem); } data[1] = new MultiComponentList(arr); break; } multilist.Add(data); } } return multilist; } } public static List RebuildTiles(MultiComponentList.MultiTileEntry[] tiles) { var newtiles = new List(); newtiles.AddRange(tiles); if (newtiles[0].m_OffsetX == 0 && newtiles[0].m_OffsetY == 0 && newtiles[0].m_OffsetZ == 0) // found a centeritem { if (newtiles[0].m_ItemID != 0x1) // its a "good" one { for (int j = newtiles.Count - 1; j >= 0; --j) // remove all invis items { if (newtiles[j].m_ItemID == 0x1) { newtiles.RemoveAt(j); } } return newtiles; } else // a bad one { for (int i = 1; i < newtiles.Count; ++i) // do we have a better one? { if (newtiles[i].m_OffsetX == 0 && newtiles[i].m_OffsetY == 0 && newtiles[i].m_ItemID != 0x1 && newtiles[i].m_OffsetZ == 0) { MultiComponentList.MultiTileEntry centeritem = newtiles[i]; newtiles.RemoveAt(i); // jep so save it for (int j = newtiles.Count - 1; j >= 0; --j) // and remove all invis { if (newtiles[j].m_ItemID == 0x1) { newtiles.RemoveAt(j); } } newtiles.Insert(0, centeritem); return newtiles; } } for (int j = newtiles.Count - 1; j >= 1; --j) // nothing found so remove all invis exept the first { if (newtiles[j].m_ItemID == 0x1) { newtiles.RemoveAt(j); } } return newtiles; } } for (int i = 0; i < newtiles.Count; ++i) // is there a good one { if (newtiles[i].m_OffsetX == 0 && newtiles[i].m_OffsetY == 0 && newtiles[i].m_ItemID != 0x1 && newtiles[i].m_OffsetZ == 0) { MultiComponentList.MultiTileEntry centeritem = newtiles[i]; newtiles.RemoveAt(i); // store it for (int j = newtiles.Count - 1; j >= 0; --j) // remove all invis { if (newtiles[j].m_ItemID == 0x1) { newtiles.RemoveAt(j); } } newtiles.Insert(0, centeritem); return newtiles; } } for (int j = newtiles.Count - 1; j >= 0; --j) // nothing found so remove all invis { if (newtiles[j].m_ItemID == 0x1) { newtiles.RemoveAt(j); } } var invisitem = new MultiComponentList.MultiTileEntry(); invisitem.m_ItemID = 0x1; // and create a new invis invisitem.m_OffsetX = 0; invisitem.m_OffsetY = 0; invisitem.m_OffsetZ = 0; invisitem.m_Flags = 0; newtiles.Insert(0, invisitem); return newtiles; } public static void Save(string path) { bool isUOAHS = PostHSFormat || Art.IsUOAHS(); string idx = Path.Combine(path, "multi.idx"); string mul = Path.Combine(path, "multi.mul"); using ( FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write), fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write)) { using (BinaryWriter binidx = new BinaryWriter(fsidx), binmul = new BinaryWriter(fsmul)) { for (int index = 0; index < 0x2000; ++index) { MultiComponentList comp = GetComponents(index); if (comp == MultiComponentList.Empty) { binidx.Write(-1); // lookup binidx.Write(-1); // length binidx.Write(-1); // extra } else { List tiles = RebuildTiles(comp.SortedTiles); binidx.Write((int)fsmul.Position); //lookup if (isUOAHS) { binidx.Write((tiles.Count * 16)); //length } else { binidx.Write((tiles.Count * 12)); //length } binidx.Write(-1); //extra for (int i = 0; i < tiles.Count; ++i) { binmul.Write(tiles[i].m_ItemID); binmul.Write(tiles[i].m_OffsetX); binmul.Write(tiles[i].m_OffsetY); binmul.Write(tiles[i].m_OffsetZ); if (isUOAHS) { binmul.Write((ulong)tiles[i].m_Flags); } else { binmul.Write((uint)tiles[i].m_Flags); } } } } } } } } public sealed class MultiComponentList { private Point m_Min, m_Max, m_Center; private int m_Width, m_Height; private readonly int m_maxHeight; private int m_Surface; private MTile[][][] m_Tiles; private readonly MultiTileEntry[] m_SortedTiles; public static readonly MultiComponentList Empty = new MultiComponentList(); public Point Min { get { return m_Min; } } public Point Max { get { return m_Max; } } public Point Center { get { return m_Center; } } public int Width { get { return m_Width; } } public int Height { get { return m_Height; } } public MTile[][][] Tiles { get { return m_Tiles; } } public int maxHeight { get { return m_maxHeight; } } public MultiTileEntry[] SortedTiles { get { return m_SortedTiles; } } public int Surface { get { return m_Surface; } } public struct MultiTileEntry { public ushort m_ItemID; public short m_OffsetX, m_OffsetY, m_OffsetZ; public TileFlag m_Flags; } /// /// Returns Bitmap of Multi /// /// public Bitmap GetImage() { return GetImage(300); } /// /// Returns Bitmap of Multi to maxheight /// /// /// public Bitmap GetImage(int maxheight) { if (m_Width == 0 || m_Height == 0) { return null; } int xMin = 1000, yMin = 1000; int xMax = -1000, yMax = -1000; for (int x = 0; x < m_Width; ++x) { for (int y = 0; y < m_Height; ++y) { MTile[] tiles = m_Tiles[x][y]; for (int i = 0; i < tiles.Length; ++i) { Bitmap bmp = Art.GetStatic(tiles[i].ID); if (bmp == null) { continue; } int px = (x - y) * 22; int py = (x + y) * 22; px -= (bmp.Width / 2); py -= tiles[i].Z << 2; py -= bmp.Height; if (px < xMin) { xMin = px; } if (py < yMin) { yMin = py; } px += bmp.Width; py += bmp.Height; if (px > xMax) { xMax = px; } if (py > yMax) { yMax = py; } } } } var canvas = new Bitmap(xMax - xMin, yMax - yMin); Graphics gfx = Graphics.FromImage(canvas); gfx.Clear(Color.White); for (int x = 0; x < m_Width; ++x) { for (int y = 0; y < m_Height; ++y) { MTile[] tiles = m_Tiles[x][y]; for (int i = 0; i < tiles.Length; ++i) { Bitmap bmp = Art.GetStatic(tiles[i].ID); if (bmp == null) { continue; } if ((tiles[i].Z) > maxheight) { continue; } int px = (x - y) * 22; int py = (x + y) * 22; px -= (bmp.Width / 2); py -= tiles[i].Z << 2; py -= bmp.Height; px -= xMin; py -= yMin; gfx.DrawImageUnscaled(bmp, px, py, bmp.Width, bmp.Height); } int tx = (x - y) * 22; int ty = (x + y) * 22; tx -= xMin; ty -= yMin; } } gfx.Dispose(); return canvas; } public MultiComponentList(BinaryReader reader, int count) { bool useNewMultiFormat = Multis.PostHSFormat || Art.IsUOAHS(); m_Min = m_Max = Point.Empty; m_SortedTiles = new MultiTileEntry[count]; for (int i = 0; i < count; ++i) { m_SortedTiles[i].m_ItemID = Art.GetLegalItemID(reader.ReadUInt16()); m_SortedTiles[i].m_OffsetX = reader.ReadInt16(); m_SortedTiles[i].m_OffsetY = reader.ReadInt16(); m_SortedTiles[i].m_OffsetZ = reader.ReadInt16(); if (useNewMultiFormat) { m_SortedTiles[i].m_Flags = (TileFlag)reader.ReadUInt64(); } else { m_SortedTiles[i].m_Flags = (TileFlag)reader.ReadUInt32(); } MultiTileEntry e = m_SortedTiles[i]; if (e.m_OffsetX < m_Min.X) { m_Min.X = e.m_OffsetX; } if (e.m_OffsetY < m_Min.Y) { m_Min.Y = e.m_OffsetY; } if (e.m_OffsetX > m_Max.X) { m_Max.X = e.m_OffsetX; } if (e.m_OffsetY > m_Max.Y) { m_Max.Y = e.m_OffsetY; } if (e.m_OffsetZ > m_maxHeight) { m_maxHeight = e.m_OffsetZ; } } ConvertList(); reader.Close(); } public MultiComponentList(string FileName, Multis.ImportType Type) { m_Min = m_Max = Point.Empty; int itemcount; switch (Type) { case Multis.ImportType.TXT: itemcount = 0; using (var ip = new StreamReader(FileName)) { string line; while ((line = ip.ReadLine()) != null) { itemcount++; } } m_SortedTiles = new MultiTileEntry[itemcount]; itemcount = 0; m_Min.X = 10000; m_Min.Y = 10000; using (var ip = new StreamReader(FileName)) { string line; while ((line = ip.ReadLine()) != null) { string[] split = line.Split(' '); string tmp = split[0]; tmp = tmp.Replace("0x", ""); m_SortedTiles[itemcount].m_ItemID = ushort.Parse(tmp, NumberStyles.HexNumber); m_SortedTiles[itemcount].m_OffsetX = Convert.ToInt16(split[1]); m_SortedTiles[itemcount].m_OffsetY = Convert.ToInt16(split[2]); m_SortedTiles[itemcount].m_OffsetZ = Convert.ToInt16(split[3]); m_SortedTiles[itemcount].m_Flags = (TileFlag)Convert.ToUInt64(split[4]); MultiTileEntry e = m_SortedTiles[itemcount]; if (e.m_OffsetX < m_Min.X) { m_Min.X = e.m_OffsetX; } if (e.m_OffsetY < m_Min.Y) { m_Min.Y = e.m_OffsetY; } if (e.m_OffsetX > m_Max.X) { m_Max.X = e.m_OffsetX; } if (e.m_OffsetY > m_Max.Y) { m_Max.Y = e.m_OffsetY; } if (e.m_OffsetZ > m_maxHeight) { m_maxHeight = e.m_OffsetZ; } itemcount++; } int centerx = m_Max.X - (int)(Math.Round((m_Max.X - m_Min.X) / 2.0)); int centery = m_Max.Y - (int)(Math.Round((m_Max.Y - m_Min.Y) / 2.0)); m_Min = m_Max = Point.Empty; int i = 0; for (; i < m_SortedTiles.Length; i++) { m_SortedTiles[i].m_OffsetX -= (short)centerx; m_SortedTiles[i].m_OffsetY -= (short)centery; if (m_SortedTiles[i].m_OffsetX < m_Min.X) { m_Min.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetX > m_Max.X) { m_Max.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetY < m_Min.Y) { m_Min.Y = m_SortedTiles[i].m_OffsetY; } if (m_SortedTiles[i].m_OffsetY > m_Max.Y) { m_Max.Y = m_SortedTiles[i].m_OffsetY; } } } break; case Multis.ImportType.UOA: itemcount = 0; using (var ip = new StreamReader(FileName)) { string line; while ((line = ip.ReadLine()) != null) { ++itemcount; if (itemcount == 4) { string[] split = line.Split(' '); itemcount = Convert.ToInt32(split[0]); break; } } } m_SortedTiles = new MultiTileEntry[itemcount]; itemcount = 0; m_Min.X = 10000; m_Min.Y = 10000; using (var ip = new StreamReader(FileName)) { string line; int i = -1; while ((line = ip.ReadLine()) != null) { ++i; if (i < 4) { continue; } string[] split = line.Split(' '); m_SortedTiles[itemcount].m_ItemID = Convert.ToUInt16(split[0]); m_SortedTiles[itemcount].m_OffsetX = Convert.ToInt16(split[1]); m_SortedTiles[itemcount].m_OffsetY = Convert.ToInt16(split[2]); m_SortedTiles[itemcount].m_OffsetZ = Convert.ToInt16(split[3]); m_SortedTiles[itemcount].m_Flags = (TileFlag)Convert.ToUInt64(split[4]); MultiTileEntry e = m_SortedTiles[itemcount]; if (e.m_OffsetX < m_Min.X) { m_Min.X = e.m_OffsetX; } if (e.m_OffsetY < m_Min.Y) { m_Min.Y = e.m_OffsetY; } if (e.m_OffsetX > m_Max.X) { m_Max.X = e.m_OffsetX; } if (e.m_OffsetY > m_Max.Y) { m_Max.Y = e.m_OffsetY; } if (e.m_OffsetZ > m_maxHeight) { m_maxHeight = e.m_OffsetZ; } ++itemcount; } int centerx = m_Max.X - (int)(Math.Round((m_Max.X - m_Min.X) / 2.0)); int centery = m_Max.Y - (int)(Math.Round((m_Max.Y - m_Min.Y) / 2.0)); m_Min = m_Max = Point.Empty; i = 0; for (; i < m_SortedTiles.Length; ++i) { m_SortedTiles[i].m_OffsetX -= (short)centerx; m_SortedTiles[i].m_OffsetY -= (short)centery; if (m_SortedTiles[i].m_OffsetX < m_Min.X) { m_Min.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetX > m_Max.X) { m_Max.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetY < m_Min.Y) { m_Min.Y = m_SortedTiles[i].m_OffsetY; } if (m_SortedTiles[i].m_OffsetY > m_Max.Y) { m_Max.Y = m_SortedTiles[i].m_OffsetY; } } } break; case Multis.ImportType.UOAB: using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (var reader = new BinaryReader(fs)) { if (reader.ReadInt16() != 1) //Version check { return; } string tmp; tmp = Multis.ReadUOAString(reader); //Name tmp = Multis.ReadUOAString(reader); //Category tmp = Multis.ReadUOAString(reader); //Subsection int width = reader.ReadInt32(); int height = reader.ReadInt32(); int uwidth = reader.ReadInt32(); int uheight = reader.ReadInt32(); int count = reader.ReadInt32(); itemcount = count; m_SortedTiles = new MultiTileEntry[itemcount]; itemcount = 0; m_Min.X = 10000; m_Min.Y = 10000; for (; itemcount < count; ++itemcount) { m_SortedTiles[itemcount].m_ItemID = (ushort)reader.ReadInt16(); m_SortedTiles[itemcount].m_OffsetX = reader.ReadInt16(); m_SortedTiles[itemcount].m_OffsetY = reader.ReadInt16(); m_SortedTiles[itemcount].m_OffsetZ = reader.ReadInt16(); reader.ReadInt16(); // level m_SortedTiles[itemcount].m_Flags = TileFlag.Background; reader.ReadInt16(); // hue MultiTileEntry e = m_SortedTiles[itemcount]; if (e.m_OffsetX < m_Min.X) { m_Min.X = e.m_OffsetX; } if (e.m_OffsetY < m_Min.Y) { m_Min.Y = e.m_OffsetY; } if (e.m_OffsetX > m_Max.X) { m_Max.X = e.m_OffsetX; } if (e.m_OffsetY > m_Max.Y) { m_Max.Y = e.m_OffsetY; } if (e.m_OffsetZ > m_maxHeight) { m_maxHeight = e.m_OffsetZ; } } int centerx = m_Max.X - (int)(Math.Round((m_Max.X - m_Min.X) / 2.0)); int centery = m_Max.Y - (int)(Math.Round((m_Max.Y - m_Min.Y) / 2.0)); m_Min = m_Max = Point.Empty; itemcount = 0; for (; itemcount < m_SortedTiles.Length; ++itemcount) { m_SortedTiles[itemcount].m_OffsetX -= (short)centerx; m_SortedTiles[itemcount].m_OffsetY -= (short)centery; if (m_SortedTiles[itemcount].m_OffsetX < m_Min.X) { m_Min.X = m_SortedTiles[itemcount].m_OffsetX; } if (m_SortedTiles[itemcount].m_OffsetX > m_Max.X) { m_Max.X = m_SortedTiles[itemcount].m_OffsetX; } if (m_SortedTiles[itemcount].m_OffsetY < m_Min.Y) { m_Min.Y = m_SortedTiles[itemcount].m_OffsetY; } if (m_SortedTiles[itemcount].m_OffsetY > m_Max.Y) { m_Max.Y = m_SortedTiles[itemcount].m_OffsetY; } } } } break; case Multis.ImportType.WSC: itemcount = 0; using (var ip = new StreamReader(FileName)) { string line; while ((line = ip.ReadLine()) != null) { line = line.Trim(); if (line.StartsWith("SECTION WORLDITEM")) { ++itemcount; } } } m_SortedTiles = new MultiTileEntry[itemcount]; itemcount = 0; m_Min.X = 10000; m_Min.Y = 10000; using (var ip = new StreamReader(FileName)) { string line; var tempitem = new MultiTileEntry(); tempitem.m_ItemID = 0xFFFF; tempitem.m_Flags = TileFlag.Background; while ((line = ip.ReadLine()) != null) { line = line.Trim(); if (line.StartsWith("SECTION WORLDITEM")) { if (tempitem.m_ItemID != 0xFFFF) { m_SortedTiles[itemcount] = tempitem; ++itemcount; } tempitem.m_ItemID = 0xFFFF; } else if (line.StartsWith("ID")) { line = line.Remove(0, 2); line = line.Trim(); tempitem.m_ItemID = Convert.ToUInt16(line); } else if (line.StartsWith("X")) { line = line.Remove(0, 1); line = line.Trim(); tempitem.m_OffsetX = Convert.ToInt16(line); if (tempitem.m_OffsetX < m_Min.X) { m_Min.X = tempitem.m_OffsetX; } if (tempitem.m_OffsetX > m_Max.X) { m_Max.X = tempitem.m_OffsetX; } } else if (line.StartsWith("Y")) { line = line.Remove(0, 1); line = line.Trim(); tempitem.m_OffsetY = Convert.ToInt16(line); if (tempitem.m_OffsetY < m_Min.Y) { m_Min.Y = tempitem.m_OffsetY; } if (tempitem.m_OffsetY > m_Max.Y) { m_Max.Y = tempitem.m_OffsetY; } } else if (line.StartsWith("Z")) { line = line.Remove(0, 1); line = line.Trim(); tempitem.m_OffsetZ = Convert.ToInt16(line); if (tempitem.m_OffsetZ > m_maxHeight) { m_maxHeight = tempitem.m_OffsetZ; } } } if (tempitem.m_ItemID != 0xFFFF) { m_SortedTiles[itemcount] = tempitem; } int centerx = m_Max.X - (int)(Math.Round((m_Max.X - m_Min.X) / 2.0)); int centery = m_Max.Y - (int)(Math.Round((m_Max.Y - m_Min.Y) / 2.0)); m_Min = m_Max = Point.Empty; int i = 0; for (; i < m_SortedTiles.Length; i++) { m_SortedTiles[i].m_OffsetX -= (short)centerx; m_SortedTiles[i].m_OffsetY -= (short)centery; if (m_SortedTiles[i].m_OffsetX < m_Min.X) { m_Min.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetX > m_Max.X) { m_Max.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetY < m_Min.Y) { m_Min.Y = m_SortedTiles[i].m_OffsetY; } if (m_SortedTiles[i].m_OffsetY > m_Max.Y) { m_Max.Y = m_SortedTiles[i].m_OffsetY; } } } break; } ConvertList(); } public MultiComponentList(List arr) { m_Min = m_Max = Point.Empty; int itemcount = arr.Count; m_SortedTiles = new MultiTileEntry[itemcount]; m_Min.X = 10000; m_Min.Y = 10000; int i = 0; foreach (MultiTileEntry entry in arr) { if (entry.m_OffsetX < m_Min.X) { m_Min.X = entry.m_OffsetX; } if (entry.m_OffsetY < m_Min.Y) { m_Min.Y = entry.m_OffsetY; } if (entry.m_OffsetX > m_Max.X) { m_Max.X = entry.m_OffsetX; } if (entry.m_OffsetY > m_Max.Y) { m_Max.Y = entry.m_OffsetY; } if (entry.m_OffsetZ > m_maxHeight) { m_maxHeight = entry.m_OffsetZ; } m_SortedTiles[i] = entry; ++i; } arr.Clear(); int centerx = m_Max.X - (int)(Math.Round((m_Max.X - m_Min.X) / 2.0)); int centery = m_Max.Y - (int)(Math.Round((m_Max.Y - m_Min.Y) / 2.0)); m_Min = m_Max = Point.Empty; for (i = 0; i < m_SortedTiles.Length; ++i) { m_SortedTiles[i].m_OffsetX -= (short)centerx; m_SortedTiles[i].m_OffsetY -= (short)centery; if (m_SortedTiles[i].m_OffsetX < m_Min.X) { m_Min.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetX > m_Max.X) { m_Max.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetY < m_Min.Y) { m_Min.Y = m_SortedTiles[i].m_OffsetY; } if (m_SortedTiles[i].m_OffsetY > m_Max.Y) { m_Max.Y = m_SortedTiles[i].m_OffsetY; } } ConvertList(); } public MultiComponentList(StreamReader stream, int count) { string line; int itemcount = 0; m_Min = m_Max = Point.Empty; m_SortedTiles = new MultiTileEntry[count]; m_Min.X = 10000; m_Min.Y = 10000; while ((line = stream.ReadLine()) != null) { string[] split = Regex.Split(line, @"\s+"); m_SortedTiles[itemcount].m_ItemID = Convert.ToUInt16(split[0]); m_SortedTiles[itemcount].m_Flags = (TileFlag)Convert.ToUInt64(split[1]); m_SortedTiles[itemcount].m_OffsetX = Convert.ToInt16(split[2]); m_SortedTiles[itemcount].m_OffsetY = Convert.ToInt16(split[3]); m_SortedTiles[itemcount].m_OffsetZ = Convert.ToInt16(split[4]); MultiTileEntry e = m_SortedTiles[itemcount]; if (e.m_OffsetX < m_Min.X) { m_Min.X = e.m_OffsetX; } if (e.m_OffsetY < m_Min.Y) { m_Min.Y = e.m_OffsetY; } if (e.m_OffsetX > m_Max.X) { m_Max.X = e.m_OffsetX; } if (e.m_OffsetY > m_Max.Y) { m_Max.Y = e.m_OffsetY; } if (e.m_OffsetZ > m_maxHeight) { m_maxHeight = e.m_OffsetZ; } ++itemcount; if (itemcount == count) { break; } } int centerx = m_Max.X - (int)(Math.Round((m_Max.X - m_Min.X) / 2.0)); int centery = m_Max.Y - (int)(Math.Round((m_Max.Y - m_Min.Y) / 2.0)); m_Min = m_Max = Point.Empty; int i = 0; for (; i < m_SortedTiles.Length; i++) { m_SortedTiles[i].m_OffsetX -= (short)centerx; m_SortedTiles[i].m_OffsetY -= (short)centery; if (m_SortedTiles[i].m_OffsetX < m_Min.X) { m_Min.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetX > m_Max.X) { m_Max.X = m_SortedTiles[i].m_OffsetX; } if (m_SortedTiles[i].m_OffsetY < m_Min.Y) { m_Min.Y = m_SortedTiles[i].m_OffsetY; } if (m_SortedTiles[i].m_OffsetY > m_Max.Y) { m_Max.Y = m_SortedTiles[i].m_OffsetY; } } ConvertList(); } private void ConvertList() { m_Center = new Point(-m_Min.X, -m_Min.Y); m_Width = (m_Max.X - m_Min.X) + 1; m_Height = (m_Max.Y - m_Min.Y) + 1; var tiles = new MTileList[m_Width][]; m_Tiles = new MTile[m_Width][][]; for (int x = 0; x < m_Width; ++x) { tiles[x] = new MTileList[m_Height]; m_Tiles[x] = new MTile[m_Height][]; for (int y = 0; y < m_Height; ++y) { tiles[x][y] = new MTileList(); } } for (int i = 0; i < m_SortedTiles.Length; ++i) { int xOffset = m_SortedTiles[i].m_OffsetX + m_Center.X; int yOffset = m_SortedTiles[i].m_OffsetY + m_Center.Y; tiles[xOffset][yOffset] .Add((m_SortedTiles[i].m_ItemID), (sbyte)m_SortedTiles[i].m_OffsetZ, m_SortedTiles[i].m_Flags); } m_Surface = 0; for (int x = 0; x < m_Width; ++x) { for (int y = 0; y < m_Height; ++y) { m_Tiles[x][y] = tiles[x][y].ToArray(); for (int i = 0; i < m_Tiles[x][y].Length; ++i) { m_Tiles[x][y][i].Solver = i; } if (m_Tiles[x][y].Length > 1) { Array.Sort(m_Tiles[x][y]); } if (m_Tiles[x][y].Length > 0) { ++m_Surface; } } } } public MultiComponentList(MTileList[][] newtiles, int count, int width, int height) { m_Min = m_Max = Point.Empty; m_SortedTiles = new MultiTileEntry[count]; m_Center = new Point((int)(Math.Round((width / 2.0))) - 1, (int)(Math.Round((height / 2.0))) - 1); if (m_Center.X < 0) { m_Center.X = width / 2; } if (m_Center.Y < 0) { m_Center.Y = height / 2; } m_maxHeight = -128; int counter = 0; for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { MTile[] tiles = newtiles[x][y].ToArray(); for (int i = 0; i < tiles.Length; ++i) { m_SortedTiles[counter].m_ItemID = (tiles[i].ID); m_SortedTiles[counter].m_OffsetX = (short)(x - m_Center.X); m_SortedTiles[counter].m_OffsetY = (short)(y - m_Center.Y); m_SortedTiles[counter].m_OffsetZ = (short)(tiles[i].Z); m_SortedTiles[counter].m_Flags = tiles[i].Flag; if (m_SortedTiles[counter].m_OffsetX < m_Min.X) { m_Min.X = m_SortedTiles[counter].m_OffsetX; } if (m_SortedTiles[counter].m_OffsetX > m_Max.X) { m_Max.X = m_SortedTiles[counter].m_OffsetX; } if (m_SortedTiles[counter].m_OffsetY < m_Min.Y) { m_Min.Y = m_SortedTiles[counter].m_OffsetY; } if (m_SortedTiles[counter].m_OffsetY > m_Max.Y) { m_Max.Y = m_SortedTiles[counter].m_OffsetY; } if (m_SortedTiles[counter].m_OffsetZ > m_maxHeight) { m_maxHeight = m_SortedTiles[counter].m_OffsetZ; } ++counter; } } } ConvertList(); } private MultiComponentList() { m_Tiles = new MTile[0][][]; } public void ExportToTextFile(string FileName) { using ( var Tex = new StreamWriter( new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite), Encoding.GetEncoding(1252))) { for (int i = 0; i < m_SortedTiles.Length; ++i) { Tex.WriteLine( String.Format( "0x{0:X} {1} {2} {3} {4}", m_SortedTiles[i].m_ItemID, m_SortedTiles[i].m_OffsetX, m_SortedTiles[i].m_OffsetY, m_SortedTiles[i].m_OffsetZ, m_SortedTiles[i].m_Flags)); } } } public void ExportToWscFile(string FileName) { using ( var Tex = new StreamWriter( new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite), Encoding.GetEncoding(1252))) { for (int i = 0; i < m_SortedTiles.Length; ++i) { Tex.WriteLine(String.Format("SECTION WORLDITEM {0}", i)); Tex.WriteLine("{"); Tex.WriteLine(String.Format("\tID\t{0}", m_SortedTiles[i].m_ItemID)); Tex.WriteLine(String.Format("\tX\t{0}", m_SortedTiles[i].m_OffsetX)); Tex.WriteLine(String.Format("\tY\t{0}", m_SortedTiles[i].m_OffsetY)); Tex.WriteLine(String.Format("\tZ\t{0}", m_SortedTiles[i].m_OffsetZ)); Tex.WriteLine("\tColor\t0"); Tex.WriteLine("}"); } } } public void ExportToUOAFile(string FileName) { using ( var Tex = new StreamWriter( new FileStream(FileName, FileMode.Create, FileAccess.ReadWrite), Encoding.GetEncoding(1252))) { Tex.WriteLine("6 version"); Tex.WriteLine("1 template id"); Tex.WriteLine("-1 item version"); Tex.WriteLine(String.Format("{0} num components", m_SortedTiles.Length)); for (int i = 0; i < m_SortedTiles.Length; ++i) { Tex.WriteLine( String.Format( "{0} {1} {2} {3} {4}", m_SortedTiles[i].m_ItemID, m_SortedTiles[i].m_OffsetX, m_SortedTiles[i].m_OffsetY, m_SortedTiles[i].m_OffsetZ, m_SortedTiles[i].m_Flags)); } } } } }