PageRenderTime 83ms CodeModel.GetById 3ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

/WorldView/Structures/TerraInfo/TerraInfo.cs

#
C# | 1416 lines | 1175 code | 237 blank | 4 comment | 213 complexity | 671e706de87f6581140c76bdcdb59908 MD5 | raw file
   1using System;
   2using System.Collections.Generic;
   3using System.Text;
   4using System.Xml;
   5using System.IO;
   6using System.Drawing;
   7using System.Globalization;
   8
   9namespace MoreTerra.Structures.TerraInfo
  10{
  11	public class TerraInfo
  12	{
  13        private Dictionary<Int32, MarkerInfo> markers;
  14        private Dictionary<String, List<MarkerInfo>> markerSets;
  15		private Dictionary<Int32, TileInfo> tiles;
  16		private Dictionary<Int32, WallInfo> walls;
  17		private Dictionary<String, ItemInfo> items;
  18		private Dictionary<String, RenameInfo> renames;
  19		private Dictionary<String, ColorInfo> colors;
  20		private Dictionary<String, NpcInfo> npcs;
  21		private Dictionary<String, List<SpecialObjectInfo>> specialobjects;
  22		private Dictionary<Int32, String> itemNames;
  23
  24		private StringBuilder errorLog;
  25
  26		public TerraInfo()
  27		{
  28            markers = new Dictionary<Int32, MarkerInfo>();
  29			markerSets = new Dictionary<String, List<MarkerInfo>>();
  30			items = new Dictionary<String, ItemInfo>();
  31			itemNames = new Dictionary<Int32, String>();
  32			renames = new Dictionary<String, RenameInfo>();
  33			colors = new Dictionary<String, ColorInfo>();
  34			npcs = new Dictionary<String, NpcInfo>();
  35
  36			tiles = new Dictionary<Int32, TileInfo>();
  37			walls = new Dictionary<Int32, WallInfo>();
  38
  39			specialobjects = new Dictionary<String, List<SpecialObjectInfo>>();
  40			 
  41			errorLog = new StringBuilder();
  42		}
  43
  44        public String LoadInfo(String itemXmlFile)
  45        {
  46            XmlDocument xmlDoc = new XmlDocument();
  47
  48            try
  49            {
  50                xmlDoc.LoadXml(itemXmlFile);
  51
  52            }
  53            catch (FileNotFoundException e)
  54            {
  55                errorLog.AppendLine(e.Message);
  56                return errorLog.ToString();
  57            }
  58
  59            XmlNode dataNode = xmlDoc.DocumentElement;
  60
  61            LoadMarkers(dataNode.SelectSingleNode("markers"));
  62
  63            LoadRenames(dataNode.SelectSingleNode("namechanges").SelectNodes("item"));
  64            LoadNpcs(dataNode.SelectSingleNode("npcs").SelectNodes("npc"));
  65            LoadItems(dataNode.SelectSingleNode("items").SelectNodes("item"));
  66
  67            LoadColors(dataNode.SelectSingleNode("colors").SelectNodes("color"));
  68            LoadTiles(dataNode.SelectSingleNode("tiles").SelectNodes("tile"));
  69            LoadWalls(dataNode.SelectSingleNode("walls").SelectNodes("wall"));
  70
  71            LoadSpecialObjects(dataNode.SelectSingleNode("specialobjects").SelectNodes("object"));
  72
  73            SetupItemNames();
  74
  75            return errorLog.ToString();
  76        }
  77
  78        public String SaveInfo(String toFile)
  79        {
  80            FileStream stream = new FileStream(toFile, FileMode.Create);
  81            StreamWriter writer = new StreamWriter(stream);
  82
  83            writer.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
  84            writer.WriteLine("<data>");
  85
  86            SaveTiles(writer);
  87            SaveWalls(writer);
  88            SaveItems(writer);
  89
  90            SaveRenames(writer);
  91            SaveNPCs(writer);
  92            SaveColors(writer);
  93            SaveMarkers(writer);
  94            SaveSpecialObjects(writer);
  95
  96            writer.WriteLine("</data>");
  97            writer.Close();
  98
  99            return errorLog.ToString();
 100        }
 101
 102
 103#region Load Functions
 104        private void LoadMarkers(XmlNode markerNodes)
 105		{
 106			Int32 setCount = -1;
 107            Int32 markerCount = -1;
 108
 109            if ((markerNodes == null) || (markerNodes.ChildNodes.Count == 0))
 110			{
 111				errorLog.AppendLine("There are no Marker items to load.");
 112				return;
 113			}
 114
 115            XmlNodeList markerSetNodes = markerNodes.SelectNodes("markerset");
 116
 117			foreach (XmlNode setNode in markerSetNodes)
 118			{
 119                String setName = String.Empty;
 120                List<MarkerInfo> curSet;
 121
 122                foreach (XmlAttribute att in setNode.Attributes)
 123				{
 124					switch (att.Name)
 125					{
 126						case "name":
 127                            setName = att.Value;
 128							break;
 129                        default:
 130                            errorLog.AppendLine(String.Format("Marker Set #{0} has unknown attribute \"{1}\" has value \"{2}\"",
 131                                setCount, att.Name, att.Value));
 132							break;
 133                    }
 134
 135                    if (setName == String.Empty)
 136                    {
 137                        errorLog.AppendLine(String.Format("Marker Set #{0} has an empty name attribute.", setCount));
 138                        continue;
 139                    }
 140
 141                    if (markerSets.ContainsKey(setName))
 142							{
 143                        errorLog.AppendLine(String.Format("Marker Set #{0} has a duplicate name. Value=\"{1}\"",
 144                            setCount, setName));
 145								continue;
 146							}
 147                    else
 148                    {
 149                        curSet = new List<MarkerInfo>();
 150                        markerSets.Add(setName, curSet);
 151                    }
 152
 153                    XmlNodeList markerNodeList = setNode.SelectNodes("marker");
 154
 155                    foreach (XmlNode markerNode in markerNodeList)
 156                    {
 157
 158                        String name = String.Empty;
 159                        String markerImage = String.Empty;
 160
 161                        markerCount++;
 162
 163                        foreach (XmlAttribute markerAtt in markerNode.Attributes)
 164                        {
 165
 166                            switch (markerAtt.Name)
 167                            {
 168                                case "name":
 169                                    name = markerAtt.Value;
 170							break;
 171						default:
 172							errorLog.AppendLine(String.Format("Marker #{0} has unknown attribute \"{1}\" has value \"{2}\"",
 173                                        markerCount, markerAtt.Name, markerAtt.Value));
 174							break;
 175					}
 176				}
 177
 178				if (name == String.Empty)
 179				{
 180                            errorLog.AppendLine(String.Format("Marker #{0} had no name attribute.", markerCount));
 181					continue;
 182				}
 183
 184                        if (name.IndexOf(" ") != -1)
 185				{
 186                            String[] imageSegments = name.Split(' ');
 187
 188                            markerImage = "";
 189                            foreach (String str in imageSegments)
 190					{
 191                                markerImage += str;
 192					}
 193				}
 194                        else
 195                        {
 196					markerImage = name;
 197				}
 198
 199				MarkerInfo marker = new MarkerInfo();
 200				marker.name = name;
 201                        marker.markerSet = setName;
 202				marker.markerImage = markerImage;
 203
 204                        curSet.Add(marker);
 205                        markers.Add(markerCount, marker);
 206                    }
 207                }
 208			}
 209
 210		}
 211
 212		private void LoadNpcs(XmlNodeList npcNodes)
 213		{
 214			Int32 count = -1;
 215
 216			if ((npcNodes == null) || (npcNodes.Count == 0))
 217			{
 218				errorLog.AppendLine("There are no Npc items to load.");
 219				return;
 220			}
 221
 222			foreach (XmlNode npcNode in npcNodes)
 223			{
 224				String name = String.Empty;
 225
 226				Int32 imageId = -1;
 227				count++;
 228
 229				foreach (XmlAttribute att in npcNode.Attributes)
 230				{
 231					switch (att.Name)
 232					{
 233						case "name":
 234							name = att.Value;
 235							break;
 236						case "npcImage":
 237							if (Int32.TryParse(att.Value, out imageId) == false)
 238							{
 239								errorLog.AppendLine(String.Format("Npc #{0} has an invalid itemImage attribute. Value = \"{1}\"",
 240									count, att.Value));
 241								continue;
 242							}
 243
 244							if (imageId < 0)
 245							{
 246								errorLog.AppendLine(String.Format("Npc #{0} had a out of range itemImage attribute.  Value=\"{1}\"",
 247									count, imageId));
 248								continue;
 249							}
 250							break;
 251						default:
 252							errorLog.AppendLine(String.Format("Npc #{0} has unknown attribute \"{1}\" has value \"{2}\"",
 253								count, att.Name, att.Value));
 254							break;
 255					}
 256				}
 257
 258				if (name == String.Empty)
 259				{
 260					errorLog.AppendLine(String.Format("Npc #{0} had no name attribute.", count));
 261					continue;
 262				}
 263
 264				if (imageId == -1)
 265				{
 266					errorLog.AppendLine(String.Format("Npc #{0} had no npcImage attribute.", count));
 267					continue;
 268				}
 269
 270
 271				if (npcs.ContainsKey(name))
 272				{
 273					errorLog.AppendLine(String.Format("Npc #{0} had a duplicate name to {1}.", count, name));
 274					continue;
 275				}
 276
 277				NpcInfo npc = new NpcInfo();
 278				npc.name = name;
 279				npc.imageId = imageId;
 280
 281				npcs.Add(name, npc);
 282			}
 283		}
 284
 285		private void LoadWalls(XmlNodeList wallNodes)
 286		{
 287			Int32 count = -1;
 288
 289			if ((wallNodes == null) || (wallNodes.Count == 0))
 290			{
 291				errorLog.AppendLine("There are no Wall items to load.");
 292				return;
 293			}
 294
 295			foreach (XmlNode wallNode in wallNodes)
 296			{
 297				String name = String.Empty;
 298				String color = String.Empty;
 299                String officialColor = String.Empty;
 300				Color useColor;
 301                Color useOfficialColor;
 302				Boolean safe = false;
 303                Boolean transparent = false;
 304
 305				Int32 wallImage = -1;
 306				count++;
 307
 308				foreach (XmlAttribute att in wallNode.Attributes)
 309				{
 310					switch (att.Name)
 311					{
 312						case "name":
 313							name = att.Value;
 314							break;
 315						case "color":
 316							color = att.Value;
 317							break;
 318                        case "officialColor":
 319                            officialColor = att.Value;
 320                            break;
 321						case "wallImage":
 322							if (Int32.TryParse(att.Value, out wallImage) == false)
 323							{
 324								errorLog.AppendLine(String.Format("Wall #{0} has an invalid wallImage attribute. Value = \"{1}\"",
 325									count, att.Value));
 326								continue;
 327							}
 328
 329							if (wallImage < 0)
 330							{
 331								errorLog.AppendLine(String.Format("Wall #{0} had an out of range wallImage attribute.  Value=\"{1}\"",
 332									count, wallImage));
 333								continue;
 334							}
 335							break;
 336						case "unsafe":
 337							if (Boolean.TryParse(att.Value, out safe) == false)
 338							{
 339								errorLog.AppendLine(String.Format("Wall #{0} had an invalid unsafe attribute.  Value=\"{1}\"",
 340									count, att.Value));
 341								continue;
 342							}
 343							safe = !safe;
 344							break;
 345                        case "transparent":
 346							if (Boolean.TryParse(att.Value, out transparent) == false)
 347							{
 348								errorLog.AppendLine(String.Format("Wall #{0} had an invalid transparent attribute.  Value=\"{1}\"",
 349									count, att.Value));
 350								continue;
 351							}
 352							break;
 353						default:
 354								errorLog.AppendLine(String.Format("Wall #{0} has unknown attribute \"{1}\" has value \"{2}\"",
 355								count, att.Name, att.Value));
 356							break;
 357					}
 358				}
 359
 360				if (name == String.Empty)
 361				{
 362					errorLog.AppendLine(String.Format("Wall #{0} had no name attribute.", count));
 363					continue;
 364				}
 365
 366                if (color == String.Empty)
 367                {
 368                    errorLog.AppendLine(String.Format("Wall #{0} had no color attribute.", count));
 369                    continue;
 370                }
 371
 372                if (Global.TryParseColor(color, out useColor) == false)
 373                {
 374                    if (!colors.ContainsKey(color))
 375                    {
 376                        errorLog.AppendLine(String.Format("Wall #{0} had a color attribute that was not a color or a color lookup name. Value=\"{1}\"",
 377                            count, color));
 378                        continue;
 379                    }
 380                    else
 381                    {
 382                        useColor = colors[color].color;
 383                    }
 384                }
 385                else
 386                {
 387                    color = String.Empty;
 388                }
 389
 390                if (officialColor == String.Empty)
 391                {
 392                    errorLog.AppendLine(String.Format("Wall #{0} had no officialColor attribute.", count));
 393                    continue;
 394                }
 395
 396                if (Global.TryParseColor(officialColor, out useOfficialColor) == false)
 397                {
 398                    errorLog.AppendLine(String.Format("Wall #{0} had a officialColor attribute that was not a color. Value=\"{1}\"",
 399                            count, officialColor));
 400                    continue;
 401                }
 402                else
 403                {
 404                    officialColor = String.Empty;
 405                }
 406
 407                if (wallImage == -1)
 408				{
 409					errorLog.AppendLine(String.Format("Wall #{0} had no wallImage attribute.", count));
 410					continue;
 411				}
 412
 413				if (walls.ContainsKey(wallImage))
 414				{
 415					errorLog.AppendLine(String.Format("Wall #{0} had a duplicate wallImage to {1}.", count, wallImage));
 416					continue;
 417				}
 418
 419				WallInfo wall = new WallInfo();
 420				wall.name = name;
 421				wall.wallImage = wallImage;
 422				wall.colorName = color;
 423				wall.color = useColor;
 424                wall.officialColor = useOfficialColor;
 425                wall.transparent = transparent;
 426                wall.color = wall.transparent ? Color.FromArgb(0,useColor) : useColor;
 427                
 428				walls.Add(wallImage, wall);
 429			}
 430		}
 431
 432		private void LoadTiles(XmlNodeList tileNodes)
 433		{
 434			Int32 count = -1;
 435
 436			if ((tileNodes == null) || (tileNodes.Count == 0))
 437			{
 438				errorLog.AppendLine("There are no Tile items to load.");
 439				return;
 440			}
 441
 442			foreach (XmlNode tileNode in tileNodes)
 443			{
 444				String name = String.Empty;
 445				String color = String.Empty;
 446                String officialColor = String.Empty;
 447				String marker = String.Empty;
 448				Color useColor;
 449                Color useOfficialColor;
 450                Boolean important = false;
 451
 452				Int32 tileImage = -1;
 453
 454				count++;
 455
 456				foreach (XmlAttribute att in tileNode.Attributes)
 457				{
 458
 459					switch (att.Name)
 460					{
 461						case "name":
 462							name = att.Value;
 463							break;
 464						case "tileImage":
 465							if (Int32.TryParse(att.Value, out tileImage) == false)
 466							{
 467								errorLog.AppendLine(String.Format("Tile #{0} has an invalid tileImage attribute. Value = \"{1}\"",
 468									count, att.Value));
 469								continue;
 470							}
 471
 472							if ((tileImage < 0) || (tileImage >= TileProperties.TYPES))
 473							{
 474								errorLog.AppendLine(String.Format("Tile #{0} had a out of range numMade attribute.  Value=\"{1}\"",
 475									count, tileImage));
 476								continue;
 477							}
 478							break;
 479						case "important":
 480							if (!Boolean.TryParse(att.Value, out important))
 481                            {
 482                                errorLog.AppendLine(String.Format("Tile #{0} had an invalid important attribute. Value=\"{1}\"",
 483                                    count, att.Value));
 484                                continue;
 485                            }
 486							break;
 487						case "color":
 488							color = att.Value;
 489							break;
 490                        case "officialColor":
 491                            officialColor = att.Value;
 492                            break;
 493						case "marker":
 494							marker = att.Value;
 495							break;
 496						default:
 497							errorLog.AppendLine(String.Format("Tile #{0} has unknown attribute \"{1}\" has value \"{2}\"",
 498								count, att.Name, att.Value));
 499							break;
 500					}
 501				}
 502
 503				if (name == String.Empty)
 504				{
 505					errorLog.AppendLine(String.Format("Tile #{0} had no name attribute.", count));
 506					continue;
 507				}
 508
 509				if (tileImage == -1)
 510				{
 511					errorLog.AppendLine(String.Format("Tile #{0} had no tileImage attribute.", count));
 512					continue;
 513				}
 514
 515				if (tiles.ContainsKey(tileImage))
 516				{
 517					errorLog.AppendLine(String.Format("Tile #{0} had a duplicate tileImage value to \"{1}\"",
 518						count, tileImage));
 519					continue;
 520				}
 521
 522                if (color == String.Empty)
 523                {
 524                    errorLog.AppendLine(String.Format("Tile #{0} had no color attribute.", count));
 525                    continue;
 526                }
 527
 528                if (Global.TryParseColor(color, out useColor) == false)
 529				{
 530					if (!colors.ContainsKey(color))
 531					{
 532						errorLog.AppendLine(String.Format("Tile #{0} had a color attribute that was not a color or a color lookup name. Value=\"{1}\"",
 533							count, color));
 534						continue;
 535					}
 536					else
 537					{
 538						useColor = colors[color].color;
 539					}
 540				}
 541                else
 542                {
 543                    color = String.Empty;
 544                }
 545
 546                if (officialColor == String.Empty)
 547                {
 548                    //errorLog.AppendLine(String.Format("Tile #{0} had no officialColor attribute.", count));
 549                    officialColor = "#FF00FF";
 550//                    continue;
 551                }
 552
 553                if (Global.TryParseColor(officialColor, out useOfficialColor) == false)
 554                {
 555                    errorLog.AppendLine(String.Format("Tile #{0} had an officialColor attribute that was not a color. Value=\"{1}\"",
 556                        count, officialColor));
 557                    continue;
 558                }
 559                else
 560                {
 561                    officialColor = String.Empty;
 562                }
 563
 564				TileInfo tile = new TileInfo();
 565				tile.name = name;
 566				tile.colorName = color;
 567				tile.color = useColor;
 568                tile.important = important;
 569                tile.officialColor = useOfficialColor;
 570				tile.markerName = marker;
 571				tile.tileImage = tileImage;
 572
 573				tiles.Add(tileImage, tile);
 574			}
 575
 576		}
 577
 578		private void LoadItems(XmlNodeList itemNodes)
 579		{
 580			Int32 count = -1;
 581
 582			if ((itemNodes == null) || (itemNodes.Count == 0))
 583			{
 584				errorLog.AppendLine("There are no Item items to load.");
 585				return;
 586			}
 587
 588			foreach (XmlNode itemNode in itemNodes)
 589			{
 590				String name = String.Empty;
 591				String found = String.Empty;
 592
 593				Int32 netId = 0;
 594				Int32 imageId = -1;
 595				count++;
 596
 597				foreach (XmlAttribute att in itemNode.Attributes)
 598				{
 599					switch (att.Name)
 600					{
 601						case "name":
 602							name = att.Value;
 603							break;
 604						case "netId":
 605							if (Int32.TryParse(att.Value, out netId) == false)
 606							{
 607								errorLog.AppendLine(String.Format("Item #{0} has an invalid netId attribute. Value = \"{1}\"",
 608									count, att.Value));
 609								continue;
 610							}
 611							break;
 612						case "itemImage":
 613							if (Int32.TryParse(att.Value, out imageId) == false)
 614							{
 615								errorLog.AppendLine(String.Format("Item #{0} has an invalid itemImage attribute. Value = \"{1}\"",
 616									count, att.Value));
 617								continue;
 618							}
 619
 620							if (imageId < 0)
 621							{
 622								errorLog.AppendLine(String.Format("Item #{0} had a out of range itemImage attribute.  Value=\"{1}\"",
 623									count, imageId));
 624								continue;
 625							}
 626							break;
 627						case "foundIn":
 628							found = att.Value;
 629							break;
 630						default:
 631							errorLog.AppendLine(String.Format("Item #{0} has unknown attribute \"{1}\" has value \"{2}\"",
 632								count, att.Name, att.Value));
 633							break;
 634					}
 635				}
 636
 637				if (name == String.Empty)
 638				{
 639					errorLog.AppendLine(String.Format("Item #{0} had no name attribute.", count));
 640					continue;
 641				}
 642
 643				if (imageId == -1)
 644				{
 645					errorLog.AppendLine(String.Format("Item #{0} had no itemImage attribute.", count));
 646					continue;
 647				}
 648
 649				if (netId == 0)
 650					netId = imageId;
 651
 652				if (items.ContainsKey(name))
 653				{
 654					errorLog.AppendLine(String.Format("Item #{0} had a duplicate name to {1}.", count, name));
 655					continue;
 656				}
 657
 658				ItemInfo item = new ItemInfo();
 659				item.name = name;
 660				item.foundIn = found;
 661				item.netId = netId;
 662				item.imageId = imageId;
 663
 664				items.Add(name, item);
 665			}
 666		}
 667
 668		private void LoadRenames(XmlNodeList renameNodes)
 669		{
 670			Int32 count = -1;
 671
 672			if ((renameNodes == null) || (renameNodes.Count == 0))
 673			{
 674				errorLog.AppendLine("There are no Rename items to load.");
 675				return;
 676			}
 677
 678			foreach (XmlNode renameNode in renameNodes)
 679			{
 680				String name = String.Empty;
 681				String newName = String.Empty;
 682				count++;
 683
 684				foreach (XmlAttribute att in renameNode.Attributes)
 685				{
 686					switch (att.Name)
 687					{
 688						case "name":
 689							name = att.Value;
 690							break;
 691						case "newName":
 692							newName = att.Value;
 693							break;
 694						default:
 695							errorLog.AppendLine(String.Format("Rename #{0} has unknown attribute \"{1}\" has value \"{2}\"",
 696								count, att.Name, att.Value));
 697							break;
 698					}
 699				}
 700
 701				if (name == String.Empty)
 702				{
 703					errorLog.AppendLine(String.Format("Rename #{0} had no name attribute.", count));
 704					continue;
 705				}
 706
 707				if (newName == String.Empty)
 708				{
 709					errorLog.AppendLine(String.Format("Rename #{0} had no newName attribute.", count));
 710					continue;
 711				}
 712
 713				if (renames.ContainsKey(name))
 714				{
 715					errorLog.AppendLine(String.Format("Rename #{0} had a duplicate name to {1}.", count, name));
 716					continue;
 717				}
 718
 719				RenameInfo rename = new RenameInfo();
 720				rename.name = name;
 721				rename.newName = newName;
 722
 723				renames.Add(name, rename);
 724			}
 725
 726		}
 727
 728		private void LoadColors(XmlNodeList colorNodes)
 729		{
 730			Int32 count = -1;
 731
 732			if ((colorNodes == null) || (colorNodes.Count == 0))
 733			{
 734				errorLog.AppendLine("There are no Color items to load.");
 735				return;
 736			}
 737
 738			foreach (XmlNode colorNode in colorNodes)
 739			{
 740				String name = String.Empty;
 741				Int32 red = -1;
 742				Int32 green = -1;
 743				Int32 blue = -1;
 744				Color useColor = Color.Black;
 745				Boolean hasColor = false;
 746				count++;
 747
 748				foreach (XmlAttribute att in colorNode.Attributes)
 749				{
 750					switch (att.Name)
 751					{
 752						case "name":
 753							name = att.Value;
 754							break;
 755						case "red":
 756							if (Int32.TryParse(att.Value, out red) == false)
 757							{
 758								errorLog.AppendLine(String.Format("Color #{0} has an invalid red attribute.  Value=\"{1}\"",
 759									count, att.Value));
 760								continue;
 761							}
 762
 763							if ((red < 0) || (red > 255))
 764							{
 765								errorLog.AppendLine(String.Format("Color #{0} had a out of range red attribute.  Value=\"{1}\"",
 766									count, red));
 767								continue;
 768							}
 769							break;
 770						case "green":
 771							if (Int32.TryParse(att.Value, out green) == false)
 772							{
 773								errorLog.AppendLine(String.Format("Color #{0} has an invalid green attribute.  Value=\"{1}\"",
 774									count, att.Value));
 775								continue;
 776							}
 777
 778							if ((green < 0) || (green > 255))
 779							{
 780								errorLog.AppendLine(String.Format("Color #{0} had a out of range green attribute.  Value=\"{1}\"",
 781									count, green));
 782								continue;
 783							}
 784							break;
 785						case "blue":
 786							if (Int32.TryParse(att.Value, out blue) == false)
 787							{
 788								errorLog.AppendLine(String.Format("Color #{0} has an invalid blue attribute.  Value=\"{1}\"",
 789									count, att.Value));
 790								continue;
 791							}
 792
 793							if ((blue < 0) || (blue > 255))
 794							{
 795								errorLog.AppendLine(String.Format("Color #{0} had a out of range blue attribute.  Value=\"{1}\"",
 796									count, blue));
 797								continue;
 798							}
 799							break;
 800						case "colorString":
 801							hasColor = Global.TryParseColor(att.Value, out useColor);
 802
 803							if (hasColor == false)
 804							{
 805								errorLog.AppendLine(String.Format("Color #{0} has a bad colorString value.  Value={1}",
 806									count, att.Value));
 807								continue;
 808							}
 809							break;
 810						default:
 811							errorLog.AppendLine(String.Format("Color #{0} has unknown attribute \"{1}\" has value \"{2}\"",
 812								count, att.Name, att.Value));
 813							break;
 814					}
 815				}
 816
 817				if (name == String.Empty)
 818				{
 819					errorLog.AppendLine(String.Format("Color #{0} had no name attribute.", count));
 820					continue;
 821				}
 822
 823				if (hasColor == false)
 824				{
 825					if (red == -1)
 826					{
 827						errorLog.AppendLine(String.Format("Color #{0} had no colorString and no red attribute.", count));
 828						continue;
 829					}
 830
 831					if (green == -1)
 832					{
 833						errorLog.AppendLine(String.Format("Color #{0} had no colorString and no green attribute.", count));
 834						continue;
 835					}
 836
 837					if (blue == -1)
 838					{
 839						errorLog.AppendLine(String.Format("Color #{0} had no colorString and no blue attribute.", count));
 840						continue;
 841					}
 842					useColor = Color.FromArgb(red, green, blue);
 843				}
 844				else
 845				{
 846					if ((red != -1) && (useColor.R != red))
 847					{
 848						errorLog.AppendLine(String.Format("Color #{0} has both a colorString and a red attribute but they do not match.",
 849							count));
 850						continue;
 851					}
 852
 853					if ((green != -1) && (useColor.G != green))
 854					{
 855						errorLog.AppendLine(String.Format("Color #{0} has both a colorString and a green attribute but they do not match.",
 856							count));
 857						continue;
 858					}
 859
 860					if ((blue != -1) && (useColor.B != blue))
 861					{
 862						errorLog.AppendLine(String.Format("Color #{0} has both a colorString and a blue attribute but they do not match.",
 863							count));
 864						continue;
 865					}
 866				}
 867
 868				if (colors.ContainsKey(name))
 869				{
 870					errorLog.AppendLine(String.Format("Color #{0} had a duplicate name to {1}.", count, name));
 871					continue;
 872				}
 873
 874				ColorInfo color = new ColorInfo();
 875				color.name = name;
 876				color.color = useColor;
 877
 878				colors.Add(name, color);
 879			}
 880		}
 881
 882		private void LoadSpecialObjects(XmlNodeList soNodes)
 883		{
 884			Int32 count = -1;
 885
 886			if ((soNodes == null) || (soNodes.Count == 0))
 887			{
 888				errorLog.AppendLine("There are no Special Object items to load.");
 889				return;
 890			}
 891
 892			foreach (XmlNode objectNode in soNodes)
 893			{
 894				String name = String.Empty;
 895				String type = String.Empty;
 896				String color = String.Empty;
 897                String officialColor = String.Empty;
 898				Color useColor;
 899                Color useOfficialColor;
 900
 901				count++;
 902
 903				foreach (XmlAttribute att in objectNode.Attributes)
 904				{
 905
 906					switch (att.Name)
 907					{
 908						case "name":
 909							name = att.Value;
 910							break;
 911						case "type":
 912							type = att.Value;
 913							break;
 914						case "color":
 915							color = att.Value;
 916							break;
 917                        case "officialColor":
 918                            officialColor = att.Value;
 919                            break;
 920						default:
 921							errorLog.AppendLine(String.Format("Special Object #{0} has unknown attribute \"{1}\" has value \"{2}\"",
 922								count, att.Name, att.Value));
 923							break;
 924					}
 925				}
 926
 927				if (name == String.Empty)
 928				{
 929					errorLog.AppendLine(String.Format("Special Object #{0} had no name attribute.", count));
 930					continue;
 931				}
 932
 933				if (type == String.Empty)
 934				{
 935					errorLog.AppendLine(String.Format("Special Object #{0} had no type attribute.", count));
 936					continue;
 937				}
 938
 939                if (color == String.Empty)
 940                {
 941                    errorLog.AppendLine(String.Format("Special Object #{0} had no color attribute.", count));
 942                    continue;
 943                }
 944
 945                if (Global.TryParseColor(color, out useColor) == false)
 946                {
 947                    if (!colors.ContainsKey(color))
 948                    {
 949                        errorLog.AppendLine(String.Format("Special Object #{0} had a color attribute that was not a color or a color lookup name. Value=\"{1}\"",
 950                            count, color));
 951                        continue;
 952                    }
 953                    else
 954                    {
 955                        useColor = colors[color].color;
 956                    }
 957                }
 958                else
 959                {
 960                    color = String.Empty;
 961                }
 962
 963                if (officialColor == String.Empty)
 964                {
 965                    errorLog.AppendLine(String.Format("Special Object #{0} had no officialColor attribute.", count));
 966                    continue;
 967                }
 968
 969                if (Global.TryParseColor(officialColor, out useOfficialColor) == false)
 970                {
 971                    errorLog.AppendLine(String.Format("Special Object #{0} had a officialColor attribute that was not a color. Value=\"{1}\"",
 972                        count, officialColor));
 973                    continue;
 974                }
 975
 976                SpecialObjectInfo so = new SpecialObjectInfo();
 977				so.name = name;
 978				so.type = type;
 979				so.colorName = color;
 980				so.color = useColor;
 981                so.officialColor = useOfficialColor;
 982
 983                if (!specialobjects.ContainsKey(type))
 984					specialobjects.Add(type, new List<SpecialObjectInfo>());
 985
 986				specialobjects[type].Add(so);
 987			}
 988		}
 989
 990		private void SetupItemNames()
 991		{
 992			itemNames.Add(0, "Unknown Item");
 993
 994			foreach (KeyValuePair<String, ItemInfo> kvp in items)
 995			{
 996				if (itemNames.ContainsKey(kvp.Value.netId))
 997				{
 998					errorLog.AppendLine(String.Format("Item {0} had a duplicate netId: \"{1}\"",
 999						kvp.Value.name, kvp.Value.netId));
1000				}
1001				else
1002				{
1003					itemNames.Add(kvp.Value.netId, kvp.Value.name);
1004				}
1005			}
1006		}
1007#endregion
1008
1009#region Save Functions
1010        private void SaveTiles(StreamWriter writer)
1011        {
1012            Dictionary<int, TileInfo> tiles = Global.Instance.Info.Tiles;
1013            TileInfo ti;
1014            String tileXML;
1015
1016            writer.WriteLine("  <tiles>");
1017
1018
1019            for (int i = 0; i < tiles.Count; i++)
1020            {
1021                ti = tiles[i];
1022
1023                // Bit of a hack but this needs to stay in until it's coded properly.
1024                if (ti.name == "Gold Cache")
1025                {
1026                    writer.WriteLine();
1027                    writer.WriteLine("    <!-- Tiles after this are a hack and not meant to be kept past testing -->");
1028                }
1029
1030                tileXML = "    <tile ";
1031                if (ti.name != null)
1032                    tileXML = tileXML + "name=\"" + ti.name + "\" ";
1033
1034                tileXML = tileXML + "tileImage=\"" + i + "\" ";
1035
1036                if (ti.important)
1037                    tileXML = tileXML + "important=\"true\" ";
1038
1039                if (!String.IsNullOrEmpty(ti.colorName))
1040                    tileXML = tileXML + "color=\"" + ti.colorName + "\" ";
1041                else
1042                    tileXML = tileXML + String.Format("color=\"#{0:X2}{1:X2}{2:X2}\" ", ti.color.R, ti.color.G, ti.color.B);
1043
1044                tileXML = tileXML + String.Format("officialColor=\"#{0:X2}{1:X2}{2:X2}\" ", 
1045                    ti.officialColor.R, ti.officialColor.G, ti.officialColor.B);
1046
1047                if (!String.IsNullOrEmpty(ti.markerName))
1048                    tileXML = tileXML + "marker=\"" + ti.markerName + "\" ";
1049
1050                tileXML = tileXML + "/>";
1051
1052                writer.WriteLine(tileXML);
1053
1054                if (i % 10 == 9)
1055                    writer.WriteLine();
1056            }
1057            writer.WriteLine("  </tiles>");
1058        }
1059
1060        private void SaveWalls(StreamWriter writer)
1061        {
1062            Dictionary<int, WallInfo> walls = Global.Instance.Info.Walls;
1063            WallInfo wi;
1064            String wallXML;
1065
1066            writer.WriteLine("  <walls>");
1067
1068            for (int i = 1; i <= walls.Count; i++)
1069            {
1070                wi = walls[i];
1071
1072                wallXML = "    <wall ";
1073                if (wi.name != null)
1074                    wallXML = wallXML + "name=\"" + wi.name + "\" ";
1075
1076                wallXML = wallXML + "wallImage=\"" + i + "\" ";
1077
1078                if (!String.IsNullOrEmpty(wi.colorName))
1079                    wallXML = wallXML + "color=\"" + wi.colorName + "\" ";
1080                else
1081                    wallXML = wallXML + String.Format("color=\"#{0:X2}{1:X2}{2:X2}\" ", wi.color.R, wi.color.G, wi.color.B);
1082
1083                wallXML = wallXML + String.Format("officialColor=\"#{0:X2}{1:X2}{2:X2}\" ",
1084                    wi.officialColor.R, wi.officialColor.G, wi.officialColor.B);
1085
1086                if (wi.transparent)
1087                    wallXML = wallXML + "transparent=\"true\" ";
1088
1089                wallXML = wallXML + "/>";
1090
1091                writer.WriteLine(wallXML);
1092
1093                if (i % 10 == 9)
1094                    writer.WriteLine();
1095            }
1096
1097            writer.WriteLine("  </walls>");
1098        }
1099
1100        private void SaveItems(StreamWriter writer)
1101        {
1102            SortedDictionary<String, ItemInfo> sorted = new SortedDictionary<string,ItemInfo>();
1103            String itemXML;
1104            String prevLetter = "";
1105            String curLetter;
1106            String numbers = "1234567890";
1107
1108            foreach (KeyValuePair<String, ItemInfo> kvp in items)
1109            {
1110                sorted.Add(kvp.Key, kvp.Value);
1111            }
1112
1113            writer.WriteLine("  <items>");
1114
1115            foreach (KeyValuePair<String, ItemInfo> kvp in sorted)
1116            {
1117                curLetter = kvp.Value.name.Substring(0, 1);
1118
1119                if (numbers.IndexOf(curLetter) == -1)
1120                {
1121                    if (curLetter != prevLetter)
1122                    {
1123                        writer.WriteLine();
1124                        prevLetter = curLetter;
1125                    }
1126                }
1127
1128                itemXML = String.Format("    <item name=\"{0}\" ", kvp.Value.name);
1129                
1130                if (!String.IsNullOrEmpty(kvp.Value.foundIn))
1131                    itemXML = itemXML + String.Format("foundIn=\"{0}\" ", kvp.Value.foundIn);
1132
1133                itemXML = itemXML + String.Format("itemImage=\"{0}\" ", kvp.Value.imageId);
1134
1135                if (kvp.Value.netId != kvp.Value.imageId)
1136                    itemXML = itemXML + String.Format("netId=\"{0}\" ", kvp.Value.netId);
1137
1138                itemXML = itemXML + "/>";
1139                writer.WriteLine(itemXML);
1140
1141            }
1142
1143            writer.WriteLine("  </items>");
1144        }
1145
1146        private void SaveRenames(StreamWriter writer)
1147        {
1148            writer.WriteLine("  <namechanges>");
1149
1150            foreach (KeyValuePair<String, RenameInfo> kvp in renames)
1151            {
1152                writer.WriteLine(String.Format("    <item name=\"{0}\" newName=\"{1}\" />", kvp.Value.name, kvp.Value.newName));
1153            }
1154
1155            writer.WriteLine("  </namechanges>");
1156        }
1157
1158        private void SaveNPCs(StreamWriter writer)
1159        {
1160            writer.WriteLine("  <npcs>");
1161
1162            foreach (KeyValuePair<String, NpcInfo> kvp in npcs)
1163            {
1164                writer.WriteLine(String.Format("    <npc name=\"{0}\" npcImage=\"{1}\" />", kvp.Value.name, kvp.Value.imageId));
1165            }
1166
1167            writer.WriteLine("  </npcs>");
1168        }
1169
1170        private void SaveColors(StreamWriter writer)
1171        {
1172            String colorXML;
1173            writer.WriteLine("  <colors>");
1174
1175            foreach (KeyValuePair<String, ColorInfo> kvp in colors)
1176            {
1177                colorXML = String.Format("    <color name=\"{0}\" ", kvp.Value.name);
1178
1179                colorXML = colorXML + String.Format("red=\"{0}\" green=\"{1}\" blue=\"{2}\" ", 
1180                    kvp.Value.color.R, kvp.Value.color.G, kvp.Value.color.B);
1181
1182                colorXML = colorXML + "/>";
1183
1184                writer.WriteLine(colorXML);
1185            }
1186
1187            writer.WriteLine("  </colors>");
1188        }
1189
1190        private void SaveMarkers(StreamWriter writer)
1191        {
1192            writer.WriteLine("  <markers>");
1193            foreach (KeyValuePair<String, List<MarkerInfo>> kvp in markerSets)
1194            {
1195                writer.WriteLine("    <markerset name=\"{0}\">", kvp.Key);
1196
1197                foreach (MarkerInfo mi in kvp.Value)
1198                {
1199                    writer.WriteLine(String.Format("      <marker name=\"{0}\"  />", mi.name));
1200                }
1201                writer.WriteLine("    </markerset>");
1202            }
1203            writer.WriteLine("  </markers>");
1204        }
1205
1206        private void SaveSpecialObjects(StreamWriter writer)
1207        {
1208            String soXML;
1209            Boolean skipNewline = true;
1210
1211            writer.WriteLine("  <specialobjects>");
1212
1213            foreach (KeyValuePair<String, List<SpecialObjectInfo>> kvp in specialobjects)
1214            {
1215                if (skipNewline == true)
1216                    skipNewline = false;
1217                else
1218                    writer.WriteLine();
1219
1220                // I don't like hacking in the comments but neither do I like leaving them out.
1221                if (kvp.Key == "Wire")
1222                    writer.WriteLine("    <!-- Wire does not have an official color so it's copied over -->");
1223                else if (kvp.Key == "Background")
1224                    writer.WriteLine("    <!-- Backgrounds have to be last so they do not turn off the Lava & Water when Draw Walls is off.-->");
1225
1226                foreach (SpecialObjectInfo soi in kvp.Value)
1227                {
1228                    soXML = String.Format("    <object name=\"{0}\" type=\"{1}\" ", soi.name, soi.type);
1229
1230                    if (!String.IsNullOrEmpty(soi.colorName))
1231                        soXML = soXML + string.Format("color=\"{0}\" ", soi.colorName);
1232                    else
1233                        soXML = soXML + String.Format("color=\"#{0:X2}{1:X2}{2:X2}\" ",
1234                            soi.color.R, soi.color.G, soi.color.B);
1235
1236                    soXML = soXML + String.Format("officialColor=\"#{0:X2}{1:X2}{2:X2}\" ",
1237                        soi.officialColor.R, soi.officialColor.G, soi.officialColor.B);
1238
1239                    soXML = soXML + "/>";
1240
1241                    writer.WriteLine(soXML);
1242
1243                }
1244            }
1245
1246            writer.WriteLine("  </specialobjects>");
1247        }
1248#endregion
1249 
1250        public ItemInfo GetItem(String itemName)
1251		{
1252			if (!items.ContainsKey(itemName))
1253			{
1254				if (renames.ContainsKey(itemName))
1255				{
1256					String newName = renames[itemName].newName;
1257
1258					if (!items.ContainsKey(newName))
1259						return null;
1260
1261					return items[newName];
1262				}
1263				else
1264				{
1265					return null;
1266				}
1267			}
1268
1269			return items[itemName];
1270		}
1271
1272		public Dictionary<String, ItemInfo> Items
1273		{
1274			get
1275			{
1276				return items;
1277			}
1278		}
1279
1280		public Dictionary<Int32, TileInfo> Tiles
1281		{
1282			get
1283			{
1284				return tiles;
1285			}
1286		}
1287
1288		public Dictionary<Int32, WallInfo> Walls
1289		{
1290			get
1291			{
1292				return walls;
1293			}
1294		}
1295
1296        public Dictionary<String, List<MarkerInfo>> MarkerSets
1297        {
1298            get
1299            {
1300                return markerSets;
1301            }
1302        }
1303
1304		public Dictionary<Int32, MarkerInfo> Markers
1305		{
1306			get
1307			{
1308				return markers;
1309			}
1310		}
1311
1312		public Dictionary<String, List<SpecialObjectInfo>> SpecialObjects
1313		{
1314			get
1315			{
1316				return specialobjects;
1317			}
1318		}
1319
1320		public Dictionary<String, ColorInfo> Colors
1321		{
1322			get
1323			{
1324				return colors;
1325			}
1326		}
1327
1328		public String MarkerImageToName(String findName)
1329		{
1330			foreach (KeyValuePair<Int32, MarkerInfo> kvp in markers)
1331			{
1332				if (kvp.Value.markerImage == findName)
1333					return kvp.Value.name;
1334			}
1335
1336			return String.Empty;
1337		}
1338
1339        public MarkerInfo GetMarkerByName(String markerName)
1340        {
1341            foreach (KeyValuePair<Int32, MarkerInfo> kvp in markers)
1342                if (kvp.Value.name == markerName)
1343                    return kvp.Value;
1344
1345            return null;
1346        }
1347
1348		public String GetItemName(Int32 netId)
1349		{
1350			if (itemNames.ContainsKey(netId))
1351				return itemNames[netId];
1352
1353			return "Unknown Item";
1354		}
1355
1356		public ItemEnum GetItemEnum(String itemName)
1357		{
1358			ItemInfo ii;
1359
1360			if (items.ContainsKey(itemName))
1361			{
1362				ii = items[itemName];
1363
1364				if (ii.foundIn == "Chest")
1365					return ItemEnum.InChest;
1366
1367				return ItemEnum.Normal;
1368			}
1369			else
1370			{
1371				return ItemEnum.NotFound;
1372			}
1373		}
1374
1375		public void AddCustomColor(String colorName, Color newColor)
1376		{
1377			if (colors.ContainsKey(colorName))
1378				return;
1379
1380			ColorInfo ci = new ColorInfo();
1381
1382			ci.name = colorName;
1383			ci.color = newColor;
1384			ci.isCustom = true;
1385
1386			colors.Add(colorName, ci);
1387		}
1388
1389		public void RemoveCustomColor(String colorName)
1390		{
1391			if (!colors.ContainsKey(colorName))
1392				return;
1393
1394			if (colors[colorName].isCustom == true)
1395				colors.Remove(colorName);
1396		}
1397
1398		public ColorInfo GetColor(String colorName)
1399		{
1400			if (colors.ContainsKey(colorName))
1401				return colors[colorName];
1402
1403			return null;
1404		}
1405
1406	}
1407
1408	#region Helper enumerations
1409	public enum ItemEnum
1410	{
1411		NotFound = 0,
1412		InChest,
1413		Normal
1414	}
1415	#endregion
1416}