context: /*************************************************************************
   *
   *   file		: NPCCommands.cs
   *   copyright		: (C) The WCell Team
   *   email		: info@wcell.org
   *   last changed	: $LastChangedDate: 2010-01-14 20:38:52 +0100 (to, 14 jan 2010) $
  
   *   revision		: $Rev: 1195 $
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *************************************************************************/
  
  using System.Linq;
  using WCell.Constants;
  using WCell.Constants.NPCs;
  using WCell.Constants.Spells;
  using WCell.Constants.Updates;
  using WCell.Constants.World;
  using WCell.RealmServer.AI.Brains;
  using WCell.RealmServer.Entities;
  using WCell.RealmServer.Instances;
  using WCell.RealmServer.NPCs;
  using WCell.RealmServer.NPCs.Spawns;
  using WCell.Util.Commands;
  using WCell.Util;
  using WCell.RealmServer.AI;
  using WCell.RealmServer.NPCs.Vehicles;
  using WCell.RealmServer.Global;
  
  namespace WCell.RealmServer.Commands
  {
  	public class NPCCommand : RealmServerCommand
  	{
  		protected NPCCommand() { }
  
  		protected override void Initialize()
  		{
  			Init("NPC");
  		}
  
  		public override ObjectTypeCustom TargetTypes
  		{
  			get { return ObjectTypeCustom.None; }
  		}
  
  		#region GetNPCSpawnEntry
  		public static NPCSpawnEntry GetNPCSpawnEntry(CmdTrigger<RealmServerCmdArgs> trigger, bool closest, out Map map)
  		{
  			var target = trigger.Args.Target;
  			NPCSpawnEntry entry;
  			map = null;
  			if (closest)
  			{
  				if (target == null)
  				{
  					trigger.Reply("Cannot use the -c switch without active Target.");
  					return null;
  				}
  
  				entry = NPCMgr.GetClosestSpawnEntry(target);
  				if (entry == null)
  				{
  					trigger.Reply("No Spawnpoint found.");
  					return null;
  				}
  			}
  			else
  			{
  				var word = trigger.Text.NextWord();
  				NPCId npcId;
  				if (!EnumUtil.TryParse(word, out npcId))
  				{
  					uint spawnId;
  					uint.TryParse(word, out spawnId);
  					entry = NPCMgr.GetSpawnEntry(spawnId);
  					if (entry == null)
  					{
  						trigger.Reply("Invalid SpawnId: " + spawnId);
  						return null;
  					}
  				}
  				else
  				{
  					var npcEntry = NPCMgr.GetEntry(npcId);
  					if (npcEntry == null)
  					{
  						trigger.Reply("Entry not found: " + npcId);
  						return null;
  					}
  					if (npcEntry.SpawnEntries.Count == 0)
  					{
  						trigger.Reply("Entry has no SpawnEntries: " + npcEntry);
  						return null;
  					}
  
  					entry = target != null ? npcEntry.SpawnEntries.GetClosestSpawnEntry(target) : npcEntry.SpawnEntries.First();
  				}
  			}
  
  			// found entry - now determine Map
  			map = entry.Map;
  			if (map == null)
  			{
  				if (target != null && entry.MapId == target.MapId)
  				{
  					// is in same map
  					map = target.Map;
  				}
  				else
  				{
  					// must create Map
  					if (World.IsInstance(entry.MapId))
  					{
  						// create instance
  						map = InstanceMgr.CreateInstance(target as Character, entry.MapId);
  						if (map == null)
  						{
  							trigger.Reply("Failed to create instance: " + entry.MapId);
  							return null;
  						}
  					}
  					else
  					{
  						trigger.Reply("Cannot spawn NPC for map: " + entry.MapId);
  						return null;
  					}
  				}
  			}
  			return entry;
  		}
  		#endregion
  
  		#region Add
  		public class AddNPCCommand : SubCommand
  		{
  			protected override void Initialize()
  			{
  				Init("Add", "A", "Create");
  				EnglishParamInfo = "[-[i][d <dest>]] <entry> [<amount>]";
  				EnglishDescription = "Creates one or more NPCs with the given entry id. NPCs are set to active by default." +
  					" Use -i to spawn an idle NPC." +
  					" Use -d <dest> to spawn an NPC at a given location.";
  			}
  
  			public override void Process(CmdTrigger<RealmServerCmdArgs> trigger)
  			{
  				var mod = trigger.Text.NextModifiers();
  				string destName = null;
  				if (mod.Contains("d"))
  				{
  					destName = trigger.Text.NextWord();
  				}
  
  				var entryId = trigger.Text.NextEnum(NPCId.End);
  				if (entryId == NPCId.End)
  				{
  					trigger.Reply("Invalid NPC.");
  					return;
  				}
  
  				var amount = trigger.Text.NextUInt(1);
  
  				if (amount < 1)
  				{
  					trigger.Reply("Invalid amount: " + amount);
  				}
  				else
  				{
  					string name = null;
  					var entry = NPCMgr.GetEntry(entryId);
  					if (entry == null)
  					{
  						trigger.Reply("Invalid NPCId: " + entryId);
  					}
  					else
  					{
  						NPC newNpc;
  						IWorldLocation dest;
  						if (!string.IsNullOrEmpty(destName))
  						{
  							dest = WorldLocationMgr.Get(destName);
  							if (dest == null)
  							{
  								trigger.Reply("Invalid destination: " + destName);
  								return;
  							}
  						}
  						else if (trigger.Args.Target == null)
  						{
  							trigger.Reply("No destination given.");
  							return;
  						}
  						else
  						{
  							dest = trigger.Args.Target;
  						}
  
  						for (var i = 0; i < amount; i++)
  						{
  							newNpc = entry.SpawnAt(dest);
  							name = newNpc.Name;
  							if (mod.Contains("i"))
  							{
  								newNpc.Brain.DefaultState = BrainState.Idle;
  							}
  							newNpc.Brain.EnterDefaultState();
  						}
  						// tricky way to make ourselves not welcome:
  						//trigger.Args.Owner.Reputations.SetValue(FactionRepListId.BootyBay, -30000);
  
  						trigger.Reply("Created {0}.", name);
  					}
  				}
  			}
  		}
  		#endregion
  
  		#region Spawn
  		public class NPCSpawnCommand : SubCommand
  		{
  			protected override void Initialize()
  			{
  				Init("AddSpawn", "Spawn");
  				EnglishParamInfo = "[-c]|[<NPCId or spawnid> [<amount>]]";
  				EnglishDescription = "Creates the NPC-spawnpoint with the given id. -c switch simply creates the spawnpoint that is closest to you";
  			}
  
  			public override void Process(CmdTrigger<RealmServerCmdArgs> trigger)
  			{
  				var mod = trigger.Text.NextModifiers();
  				Map map;
  				var spawnEntry = GetNPCSpawnEntry(trigger, mod == "c", out map);
  				if (spawnEntry == null) return;
  
  				var amount = trigger.Text.NextUInt(1);
  
  				if (amount < 1)
  				{
  					trigger.Reply("Invalid amount: " + amount);
  					return;
  				}
  
  				// create & teleport
  				map.AddNPCSpawnPoolLater(spawnEntry.PoolTemplate);
  				if (trigger.Args.Target != null)
  				{
  					trigger.Args.Target.TeleportTo(map, spawnEntry.Position);
  				}
  
  				trigger.Reply("Created spawn: {0}", spawnEntry);
  			}
  		}
  		#endregion
  
  		#region Goto
  		public class NPCGotoCommand : SubCommand
  		{
  			protected override void Initialize()
  			{
  				Init("Goto");
  				EnglishParamInfo = "[-c]|[<NPCId or spawnid>";
  				EnglishDescription = "Teleports the target to the first (or given spawn-index of) NPC of the given type.";
  			}
  
  			public override void Process(CmdTrigger<RealmServerCmdArgs> trigger)
  			{
  				var mod = trigger.Text.NextModifiers();
  				Map map;
  				var spawnEntry = GetNPCSpawnEntry(trigger, mod == "c", out map);
  				if (spawnEntry == null) return;
  
  				// teleport
  				if (trigger.Args.Target != null)
  				{
  					trigger.Args.Target.TeleportTo(map, spawnEntry.Position);
  				}
  
  				trigger.Reply("Created spawn: {0}", spawnEntry);
  			}
  		}
  		#endregion
  
  		#region Select
  		public class SelectNPCCommand : SubCommand
  		{
  			protected override void Initialize()
  			{
  				Init("Select", "Sel");
  				EnglishParamInfo = "[-[n][d] [<name>][<destination>]]";
  				EnglishDescription = "Selects the NPC whose name matches the given name and is closest to the given location. " +
  					"All arguments are optional. If no arguments are supplied, the first available NPC will be selected. " +
  					"If the destination is not given, it will search, starting at the current Target or oneself.";
  			}
  
  			public override void Process(CmdTrigger<RealmServerCmdArgs> trigger)
  			{
  				var mod = trigger.Text.NextModifiers();
  				var name = "";
  				uint phase;
  
  				if (mod.Contains("n"))
  				{
  					name = trigger.Text.NextWord();
  				}
  
  				Map rgn;
  				if (mod.Contains("d"))
  				{
  					var destName = trigger.Text.NextWord();
  
gt: 					var dest = WorldLocationMgr.Get(destName);