using System; using System.Runtime.Serialization; using System.Collections; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; using System.IO; using SpiffLib; namespace m { [Serializable] public class TemplateDoc : Document, ISerializable, IDeserializationCallback { Template m_tmplBackground = null; int m_cookie = 5000; ArrayList m_alsTemplates = new ArrayList(); string m_strNameBackground = null; Size m_sizTile; Palette m_pal; public delegate void BackgroundChangedHandler(TemplateDoc tmpd); public event BackgroundChangedHandler BackgroundChanged; public delegate void NameChangedHandler(Document doc); public event NameChangedHandler NameChanged; public TemplateDoc(DocTemplate doct, string strFile, Object[] aobj) : base(doct, strFile) { if (aobj != null) { m_sizTile = (Size)aobj[0]; } else { m_sizTile = AskTileSize(); } m_doct = (TemplateDocTemplate)doct; InitCommon(); } public TemplateDoc(SerializationInfo info, StreamingContext ctx) : base((DocTemplate)(((Hashtable)ctx.Context)["DocTemplate"]), (string)(((Hashtable)ctx.Context)["Filename"])) { m_cookie = info.GetInt32("Cookie"); // Backwards compat try { m_strNameBackground = info.GetInt32("CookieBackground").ToString(); } catch { m_strNameBackground = "0"; try { m_strNameBackground = info.GetString("NameBackground"); } catch { } } // Get tile size. If none, default 16,16 try { m_sizTile = (Size)info.GetValue("TileSize", typeof(Size)); } catch { m_sizTile = new Size(16, 16); } // Get palette try { m_pal = (Palette)info.GetValue("Palette", typeof(Palette)); } catch { m_pal = null; } m_alsTemplates = (ArrayList)info.GetValue("TileTemplates", typeof(ArrayList)); } public void OnDeserialization(object obSender) { foreach (Template tmpl in m_alsTemplates) tmpl.Doc = this; SetModified(false); InitCommon(); } void InitCommon() { TemplateDocTemplate doct = (TemplateDocTemplate)m_doct; doct.TemplateChanged += new TemplateDocTemplate.TemplateChangedHandler(TemplateDocTemplate_TemplateChanged); } public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Cookie", m_cookie); info.AddValue("TileTemplates", m_alsTemplates); string strNameBackground = ""; if (m_tmplBackground != null) strNameBackground = m_tmplBackground.Name; info.AddValue("NameBackground", strNameBackground); info.AddValue("TileSize", m_sizTile); if (m_pal != null) info.AddValue("Palette", m_pal); } Size AskTileSize() { TileSizeForm form = new TileSizeForm(); form.ShowDialog(DocManager.GetFrameParent()); return form.GetTileSize(); } public override void SetPath(string strFile) { string strDir = m_strDir; string strFileName = m_strFileName; base.SetPath(strFile); if (strDir != m_strDir || strFileName != m_strFileName) { if (NameChanged != null) NameChanged(this); } } public override string GetName() { if (m_strFileName == null) return base.GetName(); return Path.ChangeExtension(m_strFileName, null); } public void AddTemplates(string[] astrFileBitmap) { ArrayList alsNamesAdded = new ArrayList(); foreach (string strFileBitmap in astrFileBitmap) { Template tmpl = new Template(this, "tmpl" + m_cookie); m_cookie++; if (tmpl.Import(strFileBitmap)) { alsNamesAdded.Add(tmpl.Name); m_alsTemplates.Add(tmpl); } } if (alsNamesAdded.Count != 0) { TemplateDocTemplate doct = (TemplateDocTemplate)m_doct; doct.OnTemplatesAdded(this, (string[])alsNamesAdded.ToArray(typeof(string))); } SetModified(true); } public void AddTemplates(Template[] atmpl) { if (atmpl.Length == 0) return; ArrayList alsNamesAdded = new ArrayList(); foreach (Template tmpl in atmpl) { m_alsTemplates.Add(tmpl); alsNamesAdded.Add(tmpl.Name); } TemplateDocTemplate doct = (TemplateDocTemplate)m_doct; doct.OnTemplatesAdded(this, (string[])alsNamesAdded.ToArray(typeof(string))); SetModified(true); } public void RemoveTemplates(Template[] atmpl) { if (atmpl.Length == 0) return; ArrayList alsNames = new ArrayList(); foreach (Template tmpl in atmpl) { m_alsTemplates.Remove(tmpl); alsNames.Add(tmpl.Name); if (tmpl == m_tmplBackground) SetBackgroundTemplate(null); } TemplateDocTemplate doct = (TemplateDocTemplate)m_doct; doct.OnTemplatesRemoved(this, (string[])alsNames.ToArray(typeof(string))); SetModified(true); } public Template[] GetTemplates() { return (Template[])m_alsTemplates.ToArray(typeof(Template)); } void TemplateDocTemplate_TemplateChanged(TemplateDoc tmpd, string strProperty, string strName, string strParam) { if (tmpd == this) SetModified(true); } public Template FindTemplate(string strName) { foreach (Template tmpl in m_alsTemplates) { if (tmpl.Name != null && tmpl.Name == strName) return tmpl; } return null; } public void Dispose() { RemoveTemplates((Template[])m_alsTemplates.ToArray(typeof(Template))); } public Template GetBackgroundTemplate() { if (m_tmplBackground == null && m_strNameBackground != null) m_tmplBackground = FindTemplate(m_strNameBackground); return m_tmplBackground; } public void SetBackgroundTemplate(Template tmpl) { if (m_tmplBackground == tmpl) return; m_tmplBackground = tmpl; if (BackgroundChanged != null) BackgroundChanged(this); SetModified(true); } public void SetPalette(Palette pal, bool fColorMatch) { m_pal = pal; SetModified(true); if (!fColorMatch) return; ArrayList alsColors = new ArrayList(); foreach (Template tmpl in m_alsTemplates) { Bitmap bm = tmpl.Bitmap; bool[,] afOccupancy = tmpl.OccupancyMap; int ctx = afOccupancy.GetLength(1); int cty = afOccupancy.GetLength(0); for (int ty = 0; ty < cty; ty++) { for (int tx = 0; tx < ctx; tx++) { if (!afOccupancy[ty, tx]) continue; int xOrigin = tx * m_sizTile.Width; int yOrigin = ty * m_sizTile.Height; for (int y = yOrigin; y < yOrigin + m_sizTile.Height; y++) { for (int x = xOrigin; x < xOrigin + m_sizTile.Width; x++) { Color clrOld = bm.GetPixel(x, y); Color clrNew = pal[pal.FindClosestEntry(clrOld)]; bm.SetPixel(x, y, clrNew); } } } } TemplateDocTemplate doct = (TemplateDocTemplate)m_doct; doct.OnTemplateChanged(this, "Bitmap", tmpl.Name, null); } } public Palette GetPalette() { return m_pal; } public bool IsNameUnique(string strName) { foreach (Template tmpl in m_alsTemplates) { if (tmpl.Name == strName) return false; } return true; } public Size TileSize { get { return m_sizTile; } set { // This is only done in special circumstances that don't require notification m_sizTile = value; } } } public enum TerrainTypes { Start = 0, Open = 0, Blocked, Area, Wall, End }; public enum TerrainColors { Grass, Cliff, Water, Road }; [Serializable] public class Template : ISerializable { public string ImportPath = null; private string m_strName = null; public bool[,] OccupancyMap = null; public TerrainTypes[,] TerrainMap = null; public TerrainColors[,] TerrainColors = null; public Bitmap Bitmap = null; public TemplateDoc Doc = null; TemplateDocTemplate m_doct = (TemplateDocTemplate)DocManager.FindDocTemplate(typeof(TemplateDoc)); public Template(TemplateDoc doc, string strName) { Doc = doc; m_strName = strName; } public Template(TemplateDoc doc, Bitmap bm, string strName) { m_strName = strName; Doc = doc; if (!SetBitmap(bm)) throw new Exception("Invalid tile template"); } public Template(SerializationInfo info, StreamingContext ctx) { // Backwards compat try { m_strName = info.GetInt32("Cookie").ToString(); } catch { m_strName = info.GetString("Name"); } try { TerrainColors = (TerrainColors[,])info.GetValue("TerrainColors", typeof(TerrainColors[,])); } catch { TerrainColors = null; } OccupancyMap = (bool[,])info.GetValue("OccupancyMap", typeof(bool[,])); TerrainMap = (TerrainTypes[,])info.GetValue("TerrainMap", typeof(TerrainTypes[,])); Bitmap = (Bitmap)info.GetValue("Bitmap", typeof(Bitmap)); } public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Name", m_strName); info.AddValue("OccupancyMap", OccupancyMap); info.AddValue("TerrainMap", TerrainMap); info.AddValue("Bitmap", Bitmap); info.AddValue("TerrainColors", TerrainColors); } public bool Import(string strFileBitmap) { try { Bitmap bm = new Bitmap(strFileBitmap); if (SetBitmap(bm)) { ImportPath = strFileBitmap; return true; } return false; } catch { MessageBox.Show("Error opening tile bitmap"); return false; } } private bool SetBitmap(Bitmap bm) { if ((bm.Width % Doc.TileSize.Width) != 0 && (bm.Height % Doc.TileSize.Height) != 0) { MessageBox.Show("Tile dimensions not a multiple of tile size"); return false; } bm.MakeTransparent(Color.FromArgb(255, 0, 255)); Bitmap = bm; UpdateMaps(); m_doct.OnTemplateChanged(Doc, "Bitmap", m_strName, null); return true; } // Update the map sizes to reflect the new bitmap private void UpdateMaps() { int ctx = Bitmap.Width / Doc.TileSize.Width; int cty = Bitmap.Height / Doc.TileSize.Height; // Try to copy what we can of the old terrain map TerrainTypes[,] ater = new TerrainTypes[cty, ctx]; if (TerrainMap != null) { int ctyOld = TerrainMap.GetLength(0); int ctxOld = TerrainMap.GetLength(1); for (int tx = 0; tx < ctx && tx < ctxOld; tx++) { for (int ty = 0; ty < cty && ty < ctyOld; ty++) { ater[ty, tx] = TerrainMap[ty, tx]; } } } TerrainMap = ater; // Create a new occupancy map. Old one not relevant. bool[,] afOcc = new bool[cty, ctx]; for (int tx = 0; tx < ctx; tx++) { for (int ty = 0; ty < cty; ty++) { afOcc[ty, tx] = true; Color clr = Bitmap.GetPixel(tx * Doc.TileSize.Width, ty * Doc.TileSize.Height); if (clr.A == 0) afOcc[ty, tx] = false; } } OccupancyMap = afOcc; } // Properties public string Name { get { return m_strName; } set { // Only if unique if (value == m_strName) return; if (!Doc.IsNameUnique(value)) { MessageBox.Show("The name " + value + " is not unique. Not assigned."); return; } string strNameOld = m_strName; m_strName = value; m_doct.OnTemplateChanged(Doc, "Name", strNameOld, m_strName); } } public int Ctx { get { return Bitmap.Width / Doc.TileSize.Width; } } public int Cty { get { return Bitmap.Height / Doc.TileSize.Height; } } } // A doc template for (tile) templates. public class TemplateDocTemplate : DocTemplate { static string[] astr = { "Template Collection", "Untitled", "Templates", "tc" }; public delegate void TemplatesAddedHandler(TemplateDoc tmpd, string[] astrName); public event TemplatesAddedHandler TemplatesAdded; public delegate void TemplatesRemovedHandler(TemplateDoc tmpd, string[] astrName); public event TemplatesRemovedHandler TemplatesRemoved; public delegate void TemplateChangedHandler(TemplateDoc tmpd, string strProperty, string strName, string strParam); public event TemplateChangedHandler TemplateChanged; public TemplateDocTemplate() : base(astr, typeof(TemplateDoc), null, null, new TemplateDocBinder()) { } public override Document OpenDocument(string strFile) { // Don't support loading the same templates twice string strPathLower = null; if (strFile != null) strPathLower = Path.GetFullPath(strFile).ToLower(); foreach (Document doc in m_alsDocuments) { string strPath = doc.GetPath(); if (strPath == null) continue; if (strPath.ToLower() == strPathLower) { SetActiveDocument(doc); return doc; } } return base.OpenDocument(strFile); } public void OnTemplatesAdded(TemplateDoc tmpd, string[] astrName) { if (TemplatesAdded != null) TemplatesAdded(tmpd, astrName); } public void OnTemplateChanged(TemplateDoc tmpd, string strProperty, string strName, string strParam) { if (TemplateChanged != null) TemplateChanged(tmpd, strProperty, strName, strParam); } public void OnTemplatesRemoved(TemplateDoc tmpd, string[] astrName) { if (TemplatesRemoved != null) TemplatesRemoved(tmpd, astrName); } } // Compatibility goo public class TemplateDocBinder : SerializationBinder { public override Type BindToType(string strAssembly, string strType) { if (strType == "m.TileTemplateCollection") return typeof(TemplateDoc); if (strType == "m.TileTemplate") return typeof(Template); return Type.GetType(strType); } } }