public virtual bool AddNPC(bool isNpcCodeLine, CString lvlDat, CStringList words, string type)
		{
			if (isNpcCodeLine)
			{
				if (type == "NPCEND")
				{
					isNpcCodeLine = false;
				}
				else
				{
					GraalLevelNPC npc = this.NpcList[this.NpcList.Count];
					npc.Script += lvlDat.Text;
					npc.Script += "\n";

					this.NpcList[this.NpcList.Count] = npc;
				}
			}
			else
			{
				GraalLevelNPC npc = new GraalLevelNPC(this, this.NpcList.Count + 1);
				npc.Image = words.Get(1).Text;

				if (npc.Image == "-")
					npc.Image = "";

				float rx, ry;
				float.TryParse(words.Get(2).Text, out rx);
				float.TryParse(words.Get(3).Text, out ry);
				npc.GMapX = (byte)rx;
				npc.GMapY = (byte)ry;
				npc.PixelX = Convert.ToInt32(npc.GMapX * 16.0);
				npc.PixelY = Convert.ToInt32(npc.GMapY * 16.0);
				isNpcCodeLine = true;

				this.NpcList.Add(this.NpcList.Count + 1, npc);
			}
			return isNpcCodeLine;
		}
		private bool LoadNW(CStringList levelData)
		{
			bool isNpcCodeLine = false, isSignCodeLine = false;
			int line = 0;
			foreach (CString lvlDat in levelData)
			{
				line++;

				CStringList words = new CStringList();
				words.Load(lvlDat.Text, ' ');
				if (words.Count <= 0)
					continue;

				string type = words.Get(0).Text;
				if (type != NW_LEVEL_VERSION && line == 1)
				{
					throw new Exception("load_nw_level() failed: Version mismatch (" + type + " != " + NW_LEVEL_VERSION + ")");
				}
				if (type == "BOARD")
				{
					#region BOARD code
					if (words.Count <= 5)
						continue;

					int start_x, start_y, width, layer;
					int.TryParse(words.Get(1).Text, out start_x);
					int.TryParse(words.Get(2).Text, out start_y);
					int.TryParse(words.Get(3).Text, out width);
					int.TryParse(words.Get(4).Text, out layer);
					CString data = words.Get(5);

					bool layerExists = false;

					foreach (KeyValuePair<int, GraalLevelTileList> l in this.layers)
						if (l.Key == layer)
							layerExists = true;

					if (!layerExists)
						this.layers[layer] = new GraalLevelTileList();

					for (int i = 0; i < width * 2; i += 2)
					{
						int tile_index = this.Base64Decode(data.Text.Substring(i, 2));
						int x = start_x + i / 2;

						GraalLevelTile tile = this.layers[layer].AddTile(x, start_y, width, tile_index);
					}
					#endregion
				}
				else if (type == "LINK")
				{
					#region LINK code
					GraalLevelLink link = new GraalLevelLink();
					int linkX, linkY, width, height;
					link.Destination = words.Get(1).Text;
					int.TryParse(words.Get(2).Text, out linkX);
					int.TryParse(words.Get(3).Text, out linkY);
					link.X = linkX;
					link.Y = linkY;

					int.TryParse(words.Get(4).Text, out width);
					int.TryParse(words.Get(5).Text, out height);
					link.Width = width;
					link.Height = width;

					link.NewX = words.Get(6).Text;
					link.NewY = words.Get(7).Text;

					this.LinkList.Add(this.LinkList.Count + 1, link);
					#endregion
				}
				else if (type == "SIGN" || isSignCodeLine) // read npcs
				{
					#region SIGN code
					if (isSignCodeLine)
					{
						if (type == "SIGNEND")
						{
							isSignCodeLine = false;
						}
						else
						{
							GraalLevelSign sign = this.SignList[this.SignList.Count];
							sign.Text += lvlDat.Text;
							sign.Text += "\n";

							this.SignList[this.SignList.Count] = sign;
						}
					}
					else
					{
						GraalLevelSign sign = new GraalLevelSign();
						int signX, signY;
						int.TryParse(words.Get(1).Text, out signX);
						int.TryParse(words.Get(2).Text, out signY);
						sign.X = signX;
						sign.Y = signY;

						isSignCodeLine = true;

						this.SignList.Add(this.SignList.Count + 1, sign);
					}
					#endregion
				}
				else if (type == "NPC" || isNpcCodeLine) // read npcs
				{
					#region NPC code
					isNpcCodeLine = this.AddNPC(isNpcCodeLine, lvlDat, words, type);
					#endregion
				}
			}

			return true;
		}
		public bool Load(CString pFileName)
		{
			CStringList levelData = new CStringList();
			if (!levelData.Load(pFileName.Text))
				return false;

			if (levelData.Count < 1)
				return false;

			// Grab file version.
			string fileVersion = levelData.Get(0).ReadChars(8);

			// Determine the level type.
			int v = -1;
			if (fileVersion == "GLEVNW01")
				v = 0;
			else if (fileVersion == "GR-V1.03" || fileVersion == "GR-V1.02" || fileVersion == "GR-V1.01")
				v = 1;
			else if (fileVersion == "Z3-V1.04" || fileVersion == "Z3-V1.03")
				v = 2;

			// Not a level.
			if (v == -1)
				return false;

			// Load the correct level.
			if (v == 0)
				return this.LoadNW(levelData);
			if (v == 1)
				return this.LoadGraal(levelData.Join("\n"), fileVersion);
			if (v == 2)
				return this.LoadZelda(levelData.Join("\n"), fileVersion);
			return false;

		}
		private bool LoadZelda(CString levelData, string fileVersion)
		{
			// Get the appropriate filesystem.
			//CFileSystem* fileSystem = server->getFileSystem();
			//if (server->getSettings()->getBool("nofoldersconfig", false) == false)
			//	fileSystem = server->getFileSystem(FS_LEVEL);

			// Path-To-File
			//actualLevelName = levelName = pLevelName;
			//fileName = fileSystem->find(pLevelName);
			//modTime = fileSystem->getModTime(pLevelName);

			// Check if it is actually a .graal level.  The 1.39-1.41r1 client actually
			// saved .zelda as .graal.
			if (fileVersion.Substring(0, 2) == "GR")
				return this.LoadGraal(levelData, fileVersion);

			int v = -1;
			if (fileVersion == "Z3-V1.03")
				v = 3;
			else if (fileVersion == "Z3-V1.04")
				v = 4;
			if (v == -1)
				return false;

			#region Load tiles.
			bool layerExists = false;

			foreach (KeyValuePair<int, GraalLevelTileList> l in this.layers)
				if (l.Key == 0)
					layerExists = true;

			if (!layerExists)
				this.layers[0] = new GraalLevelTileList();
			{
				int bits = (v > 4 ? 13 : 12);
				int read = 0;
				uint buffer = 0;
				long code = 0;
				int[] tiles = new int[2] { -1, -1 };
				int boardIndex = 0;
				int count = 1;
				bool doubleMode = false;

				// Read the tiles.
				while (boardIndex < 64 * 64 && levelData.BytesLeft != 0)
				{
					// Every control code/tile is either 12 or 13 bits.  WTF.
					// Read in the bits.
					while (read < bits)
					{
						buffer += ((uint)levelData.ReadGByte1()) << read;
						read += 8;
					}

					// Pull out a single 12/13 bit code from the buffer.
					code = buffer & (bits == 12 ? 0xFFF : 0x1FFF);
					buffer >>= bits;
					read -= bits;

					Console.WriteLine("Code&bits: " + (code & (bits == 12 ? 0x800 : 0x1000)));
					// See if we have an RLE control code.
					// Control codes determine how the RLE scheme works.
					if ((code & (bits == 12 ? 0x800 : 0x1000)) != 0)
					{
						
						// If the 0x100 bit is set, we are in a double repeat mode.
						// {double 4}56 = 56565656
						if ((code & 0x100) != 0)
							doubleMode = true;

						// How many tiles do we count?
						count = (int)(code & 0xFF);
						continue;
					}

					// If our count is 1, just read in a tile.  This is the default mode.
					if (count == 1)
					{
						GraalLevelTile tile = this.layers[0].AddTile(boardIndex++, (int)code);
						continue;
					}

					// If we reach here, we have an RLE scheme.
					// See if we are in double repeat mode or not.
					if (doubleMode)
					{
						// Read in our first tile.
						if (tiles[0] == -1)
						{
							tiles[0] = (int)code;
							continue;
						}

						// Read in our second tile.
						tiles[1] = (int)code;

						// Add the tiles now.
						for (int i = 0; i < count && boardIndex < 64 * 64 - 1; ++i)
						{
							GraalLevelTile tile = this.layers[0].AddTile(boardIndex++, tiles[0]);
							GraalLevelTile tile2 = this.layers[0].AddTile(boardIndex++, tiles[1]);
						}

						// Clean up.
						tiles[0] = tiles[1] = -1;
						doubleMode = false;
						count = 1;
					}
					// Regular RLE scheme.
					else
					{
						GraalLevelTile tile = null;
						for (int i = 0; i < count && boardIndex < 64 * 64; ++i)
							tile = this.layers[0].AddTile(boardIndex++, (int)code);

						count = 1;
					}
				}
			}
			#endregion

			#region Load the links.
			{
				while (levelData.BytesLeft != 0)
				{
					CString line = levelData.ReadString('\n');
					if (line.Length == 0 || line.Text == "#")
						break;

					// Assemble the level string.

					CStringList vline = new CStringList();
					vline.Load(line.Text, ' ');
					CString level = vline.Get(0);
					if (vline.Count > 7)
					{
						for (int i = 0; i < vline.Count - 7; ++i)
							level += " " + vline.Get(1 + i);
					}

					int offset = vline.Count - 7;

					//GraalLevelLink link = new GraalLevelLink(vline.Get(0).Text, vline.Get(1).ToInt(), vline.Get(2).ToInt(), vline.Get(3).ToInt(), vline.Get(4).ToInt(),vline.Get(5).Text, vline.Get(6).Text);
					
					//this.LinkList.Add(this.LinkList.Count + 1, link);
				}
			}
			#endregion

			#region Load the baddies.
			{
				while (levelData.BytesLeft != 0)
				{
					int x = levelData.ReadGUByte1();
					int y = levelData.ReadGUByte1();
					int type = levelData.ReadGUByte1();

					// Ends with an invalid baddy.
					if (x == -1 && y == -1 && type == -1)
					{
						levelData.ReadString('\n');	// Empty verses.
						break;
					}
					/*
					// Add the baddy.
					TLevelBaddy* baddy = addBaddy((float)x, (float)y, type);
					if (baddy == 0)
						continue;

					// Only v1.04+ baddies have verses.
					if (v > 3)
					{
						// Load the verses.
						std::vector<CString> bverse = fileData.readString("\n").tokenize("\\");
						CString props;
						for (char j = 0; j < (char)bverse.size(); ++j)
							props >> (char)(BDPROP_VERSESIGHT + j) >> (char)bverse[j].length() << bverse[j];
						if (props.length() != 0) baddy->setProps(props);
					}
					*/
				}
			}
			#endregion

			#region Load signs.
			{
				while (levelData.BytesLeft != 0)
				{
					CString line = levelData.ReadString('\n');
					if (line.Length == 0)
						break;

					byte x = line.ReadGUByte1();
					byte y = line.ReadGUByte1();
					CString text = line.ReadString();

					this.SignList.Add(this.SignList.Count + 1, new GraalLevelSign(x, y, text.Text));
				}
			}
			#endregion

			return true;
		}
		public bool LoadTypeDefinitions(CString pFileName)
		{
			CStringList typeDefs = new CStringList();
			if (!typeDefs.Load(pFileName.Text))
				return false;

			if (typeDefs.Count < 1)
				return false;

			foreach (CString typeDefLine in typeDefs)
			{
				for (var i = 0; i < typeDefLine.Text.Length; i++)
				{
					//Console.WriteLine("TileId: " + i.ToString() + " - TileType: " + Enum.GetName(typeof(TileType), typeDefLine.ReadByte()).ToString());
					this.TileTypeDefinitions.Add(i, typeDefLine.ReadByte());
				}
			}
			return true;
		}