public static void createAmmo(Player p, int sets, int type, bool bolt, bool newFletch)
 {
     Ammo item = null;
     if (newFletch || Fletching.getFletchItem(p) == null) {
         item = getAmmo(type, bolt, sets);
         Fletching.setFletchItem(p, item);
     }
     item = (Ammo) Fletching.getFletchItem(p);
     if (item == null || p == null) {
         return;
     }
     if (!canFletch(p, item)) {
         p.getPackets().closeInterfaces();
         return;
     }
     int amt = getArrowAmount(p, item);
     if (amt <= 0) {
         return;
     }
     if (p.getInventory().deleteItem(item.getItemOne(), amt) && p.getInventory().deleteItem(item.getItemTwo(), amt)) {
         p.getInventory().addItem(item.getFinishedItem(), amt);
         p.getSkills().addXp(Skills.SKILL.FLETCHING, item.getXp() * amt);
         p.getPackets().sendMessage(getMessage(item, amt));
         item.decreaseAmount();
         p.getPackets().closeInterfaces();
     }
     if (item.getAmount() >= 1) {
         Event createMoreAmmoEvent = new Event(1500);
         createMoreAmmoEvent.setAction(() => {
             createAmmo(p, -1, -1, false, false);
             createMoreAmmoEvent.stop();
         });
         Server.registerEvent(createMoreAmmoEvent);
     }
 }
	    private void newGlobalItem(GroundItem item) {
		    if (item == null) {
			    return;
		    }
		    item = itemExists(item);
		    if (item != null) {
			    item.setGlobal(true);
			    foreach(Player p in Server.getPlayerList()) {
				    if (p == null || (item.getDefinition().isPlayerBound() && !item.getOwner().Equals(p))) {
					    continue;
				    }
				    if (p.getLocation().withinDistance(item.getLocation(), 60)) {
					    if(item.getOwner() != null) {
						    p.getPackets().createGroundItem2(item);
					    } else {
						    p.getPackets().createGroundItem(item);
					    }
				    }
			    }
			    if (!item.getDefinition().isPlayerBound()) {
				    item.setOwner(null);
			    }
			    GroundItem i = item;
			    if (!item.isRespawn()) {
                    Event removeGlobalItemEvent = new Event(60000);
				    removeGlobalItemEvent.setAction(() => {
						clearGlobalItem(i);
						removeGlobalItemEvent.stop();
				    });
                    Server.registerEvent(removeGlobalItemEvent);
			    }
		    }
	    }
	    protected void spawnMonsters() {
		    if (monstersSpawned || !gameInProgress) {
			    return;
		    }
		    monstersSpawned = true;
            Event spawnMonstersEvent = new Event(3000);
            spawnMonstersEvent.setAction(() => {
				if (!monstersSpawned || playersPlaying.Count() <= 1) {
					spawnMonstersEvent.stop();
					foreach(Npc n in Server.getNpcList()) {
						if (Location.inFightPits(n.getLocation())) {
							n.setVisible(false);
							Server.getNpcList().Remove(n);
						}
					}
					return;
				}
		    });
            Server.registerEvent(spawnMonstersEvent);

		    foreach(Player p in playersPlaying) {
			    teleportToWaitingRoom(p, false);
			    sendNPCMessage(p, "You took to long in defeating your enemies.");
		    }
		    playersPlaying.Clear();
	    }
	    public ShopManager() {
            if (!File.Exists(misc.getServerPath() + @"\data\shops.xml"))
            {
                misc.WriteError(@"Missing data\shops.xml");
                return;
            }
            try
            {
                //Deserialize text file to a new object.
                StreamReader objStreamReader = new StreamReader(misc.getServerPath() + @"\data\shops.xml");
                XmlSerializer serializer = new XmlSerializer(typeof(List<Shop>));

                List<Shop> listShops = (List<Shop>)serializer.Deserialize(objStreamReader);
                shops = new Dictionary<int, Shop>();
                foreach (Shop shop in listShops)
                {
                    shops.Add(shop.id, shop);
                }
            }
            catch (Exception e)
            {
                misc.WriteError((e.InnerException == null ? e.ToString() : e.InnerException.ToString()));
            }

		    //shops = (Map<Integer, Shop>) XStreamUtil.getXStream().fromXML(new FileInputStream("data/shops.xml"));
            Event updateShopAmountsEvent = new Event(60000);
            updateShopAmountsEvent.setAction(() => {
		        updateShopAmounts();
		    });
            Server.registerEvent(updateShopAmountsEvent);
		    Console.WriteLine("Loaded " + shops.Count + " shops.");
	    }
	    private void startArena() {
            Event startArenaEvent = new Event(0);
            startArenaEvent.setAction(() => {
				currentPillar = misc.random(AGILITY_ARENA_PILLARS.Length - 1);
				updateArrow();
				startArenaEvent.setTick(30000 + misc.random(30000));
		    });
            Server.registerEvent(startArenaEvent);
	    }
	    public void enterChannel(Player p, string owner) {
		    if (p.getClan() != null) {
			    return;
		    }
		    p.getPackets().sendMessage("Attempting to join channel...:clan:");
		    if (owner.Equals(p.getLoginDetails().getUsername())) {
			    Clan newClan = new Clan(p, owner, owner);
			    addChannel(newClan);
		    }
            Event enterChannelEvent = new Event(700);
            enterChannelEvent.setAction(() => {
				enterChannelEvent.stop();
				foreach(Clan c in clans) {
					if (c != null) {
						if (c.getClanOwner().Equals(owner)) {
							if(c.getUserList().Count >= 100) {
								p.getPackets().sendMessage("The channel is full.");
								return;
							}
							if (!owner.Equals(p.getLoginDetails().getUsername())) {
								if (c.getEnterRights() != Clan.ClanRank.NO_RANK) {
									if (c.getEnterRights() == Clan.ClanRank.FRIEND) {
										if (!c.isFriendOfOwner(p) && !c.userHasRank(p.getLoginDetails().getUsername())) {
											p.getPackets().sendMessage("You do not have a high enough rank to enter this clan chat.");
											return;
										}
									} else {
										bool canEnter = true;
										foreach (KeyValuePair<string, Clan.ClanRank> u in c.getUsersWithRank()) {
											if(u.Key.Equals(p.getLoginDetails().getUsername())) {
												if (u.Value < c.getEnterRights()) {
													canEnter = false;
													break;
												}
											}
										}
										if (!canEnter) {
											p.getPackets().sendMessage("You do not have a high enough rank to enter this clan chat.");
											return;
										}
									}
								}
							}
							c.addUser(p);
							updateClan(c);
							p.getPackets().sendMessage("Now talking in channel : " + misc.formatPlayerNameForDisplay(c.getClanName() + ":clan:"));
							p.getPackets().sendMessage("To talk, start each line of chat with the / symbol. :clan:");
							return;
						}
					}
				}
				p.getPackets().sendMessage("The channel you tried to join does not exist. :clan:");
		    });
            Server.registerEvent(enterChannelEvent);
	    }
 public static void craftDragonHide(Player p, int amount, int itemIndex, int leatherType, bool newCraft)
 {
     if (newCraft) {
         itemIndex = leatherType != 0 ? itemIndex += leatherType : itemIndex;
         p.setTemporaryAttribute("craftItem", new CraftItem(leatherType, itemIndex, amount, (double) LEATHER_ITEMS[itemIndex][2], (int) LEATHER_ITEMS[itemIndex][0], (string) LEATHER_ITEMS[itemIndex][4], (int) LEATHER_ITEMS[itemIndex][1]));
     }
     CraftItem item = (CraftItem) p.getTemporaryAttribute("craftItem");
     if (item == null || p == null || item.getAmount() <= 0) {
         Crafting.resetCrafting(p);
         return;
     }
     p.getPackets().closeInterfaces();
     int index = item.getCraftItem();
     if (p.getSkills().getGreaterLevel(Skills.SKILL.CRAFTING) < item.getLevel()) {
         p.getPackets().sendMessage("You need a Crafting level of " + item.getLevel() + " to craft that item.");
         Crafting.resetCrafting(p);
         return;
     }
     if (!p.getInventory().hasItemAmount(TANNED_HIDE[item.getCraftType()], (int) LEATHER_ITEMS[index][3])) {
         p.getPackets().sendMessage("You need " + (int) LEATHER_ITEMS[index][3] + " dragonhide to craft that.");
         Crafting.resetCrafting(p);
         return;
     }
     if (!p.getInventory().hasItem(NEEDLE)) {
         p.getPackets().sendMessage("You need a needle if you wish to craft leather.");
         Crafting.resetCrafting(p);
         return;
     }
     if (!p.getInventory().hasItemAmount(THREAD, (int)LEATHER_ITEMS[index][3])) {
         p.getPackets().sendMessage("You need " + (int)LEATHER_ITEMS[index][3] + " thread to craft that.");
         Crafting.resetCrafting(p);
         return;
     }
     string s = index < 4 ? "a" : "a pair of";
     for (int j = 0; j < (int) LEATHER_ITEMS[index][3]; j++) {
         if (!p.getInventory().deleteItem(TANNED_HIDE[item.getCraftType()])) {
             return;
         }
     }
     p.getInventory().deleteItem(THREAD, (int) LEATHER_ITEMS[index][3]);
     p.getInventory().addItem(item.getFinishedItem());
     p.getSkills().addXp(Skills.SKILL.CRAFTING, item.getXp());
     p.setLastAnimation(new Animation(1249));
     p.getPackets().sendMessage("You craft " + s + " " + item.getMessage() + ".");
     item.decreaseAmount();
     if (item.getAmount() >= 1) {
         Event craftMoreDragonHide = new Event(1500);
         craftMoreDragonHide.setAction(() => {
                 craftDragonHide(p, -1, -1, -1, false);
                 craftMoreDragonHide.stop();
         });
         Server.registerEvent(craftMoreDragonHide);
     }
 }
	    public static void exitCave(Player p, int objectX, int objectY) {
            AreaEvent exitCaveAreaEvent = new AreaEvent(p, objectX, objectY - 1, objectX + 2, objectY - 1);
            exitCaveAreaEvent.setAction(() => {
				p.setTemporaryAttribute("unmovable", true);
                Event teleFromCaveEvent = new Event(600);
                teleFromCaveEvent.setAction(() => {
					teleFromCaveEvent.stop();
					p.getFightCave().teleFromCave(true);
				});
                Server.registerEvent(teleFromCaveEvent);
		    });
            Server.registerCoordinateEvent(exitCaveAreaEvent);
	    }
	    public void newEntityDrop(GroundItem item) {
		    lock(items) {
			    items.Add(item);
		    }
		    if (item.getOwner() != null && !item.getOwner().isDestroyed()) {
			    item.getOwner().getPackets().createGroundItem(item);
		    }
            Event showItemDropGloballyEvent = new Event(60000); //60 seconds to show dropped item to all players.
		    showItemDropGloballyEvent.setAction(() => {
				    newGlobalItem(item);
				    showItemDropGloballyEvent.stop();
		    });
            Server.registerEvent(showItemDropGloballyEvent);
	    }
	    private void startCloseDoorEvent() {

            Event closeDoorEvent = new Event(CHANGE_CYCLE_TIME);
            closeDoorEvent.setAction(() => {
				foreach(Door door in doors) {
					if (door != null) {
						if (door.isDoorOpen() && !door.isInstantClose() && misc.random(1) == 0) {
							changeDoor(door);
						}
					}
				}
		    });
            Server.registerEvent(closeDoorEvent);
	    }
 public static void craftClay(Player p, int amount, int craftType, int craftItem, bool newCraft)
 {
     if (newCraft) {
         if ((craftType != 1 && craftType != 2) || craftItem < 0 || craftItem > 4) {
             return;
         }
         int index = craftItem;
         int endItem = craftType == 1 ? 0 : 1;
         int xp = craftType == 1 ? 3 : 4;
         p.setTemporaryAttribute("craftItem", new CraftItem(craftType, craftItem, amount, (double) CLAY_ITEMS[index][xp], (int) CLAY_ITEMS[index][endItem], (string) CLAY_ITEMS[index][5], (int) CLAY_ITEMS[index][2]));
     }
     CraftItem item = (CraftItem) p.getTemporaryAttribute("craftItem");
     if (item == null || p == null || item.getAmount() <= 0) {
         Crafting.resetCrafting(p);
         return;
     }
     int neededItem = item.getCraftType() == 1 ? CLAY : (int) CLAY_ITEMS[item.getCraftItem()][0];
     string s = item.getCraftType() == 1 ? "You mould the clay into a " + item.getMessage() : "You bake the " + item.getMessage() + " in the oven";
     string s1 = item.getCraftType() == 1 ? "You need some soft clay to mould a " + item.getMessage() : "You need a pre-made " + item.getMessage() + " to put in the oven";
     int animation = item.getCraftType() == 1 ? 883 : 899;
     if (p.getSkills().getGreaterLevel(Skills.SKILL.CRAFTING) < item.getLevel()) {
         p.getPackets().sendMessage("You need a Crafting level of " + item.getLevel() + " to make a " + item.getMessage() + ".");
         Crafting.resetCrafting(p);
         return;
     }
     if (!p.getInventory().hasItem(neededItem)) {
         p.getPackets().sendMessage(s1 + ".");
         Crafting.resetCrafting(p);
         return;
     }
     p.getPackets().closeInterfaces();
     if (p.getInventory().deleteItem(neededItem)) {
         if (p.getInventory().addItem(item.getFinishedItem())) {
             p.getSkills().addXp(Skills.SKILL.CRAFTING, item.getXp());
             p.getPackets().sendMessage(s + ".");
             p.setLastAnimation(new Animation(animation));
         }
     }
     item.decreaseAmount();
     if (item.getAmount() >= 1) {
         Event craftMoreClayEvent = new Event(1500);
         craftMoreClayEvent.setAction(() =>
         {
             craftClay(p, -1, -1, -1, false);
             craftMoreClayEvent.stop();
         });
         Server.registerEvent(craftMoreClayEvent);
     }
 }
 public static void completePotion(Player p, int amount, bool newMix)
 {
     if (newMix && p.getTemporaryAttribute("completePotion") == null) {
         return;
     }
     if (!newMix && p.getTemporaryAttribute("herbloreItem") == null) {
         return;
     }
     if (newMix) {
         if (p.getTemporaryAttribute("completePotion") == null) {
             return;
         }
         int index = (int) p.getTemporaryAttribute("completePotion");
         p.setTemporaryAttribute("herbloreItem", new Potion(END_POTION[index], UNFINISHED[index], SECONDARY[index], POTION_LEVEL[index], POTION_XP[index], amount));
     }
     Potion item = (Potion) p.getTemporaryAttribute("herbloreItem");
     if (item == null || p == null || item.getAmount() <= 0) {
         resetAllHerbloreVariables(p);
         return;
     }
     if (!p.getInventory().hasItem(item.getSecondary()) || !p.getInventory().hasItem(item.getUnfinished())) {
         resetAllHerbloreVariables(p);
         return;
     }
     if (p.getSkills().getGreaterLevel(Skills.SKILL.HERBLORE) < item.getLevel()) {
         p.getPackets().sendMessage("You need a Herblore level of " + item.getLevel() + " to make that potion.");
         resetAllHerbloreVariables(p);
         return;
     }
     string s = ItemData.forId(item.getFinished()).getName().Replace("(3)", "");
     if (p.getInventory().deleteItem(item.getUnfinished()) && p.getInventory().deleteItem(item.getSecondary())) {
         if (p.getInventory().addItem(item.getFinished())) {
             item.decreaseAmount();
             p.setLastAnimation(new Animation(MIX_ANIMATION));
             p.getSkills().addXp(Skills.SKILL.HERBLORE, item.getXp());
             p.getPackets().sendMessage("You add the ingredient into the murky vial, you have completed the potion.");
             p.getPackets().closeInterfaces();
         }
     }
     if (item.getAmount() >= 1) {
         Event completeMorePotionsEvent = new Event(750);
         completeMorePotionsEvent.setAction(() => {
             completePotion(p, item.getAmount(), false);
             completeMorePotionsEvent.stop();
         });
         Server.registerEvent(completeMorePotionsEvent);
     }
 }
 public static void cutGem(Player p, int index, int amount, bool newCut)
 {
     index -= 50;
     if (newCut) {
         p.setTemporaryAttribute("craftItem", new CraftItem(5, index, amount, (double) GEMS[index][3], (int) GEMS[index][1], (string) GEMS[index][4], (int) GEMS[index][2]));
     }
     CraftItem item = (CraftItem) p.getTemporaryAttribute("craftItem");
     if (item == null || p == null || item.getAmount() <= 0 || item.getCraftType() != 5) {
         Crafting.resetCrafting(p);
         return;
     }
     p.getPackets().closeInterfaces();
     if (!p.getInventory().hasItem(CHISEL)) {
         p.getPackets().sendMessage("You cannot cut gems without a chisel.");
         Crafting.resetCrafting(p);
         return;
     }
     if (!p.getInventory().hasItem((int)GEMS[item.getCraftItem()][0])) {
         if (newCut) {
             p.getPackets().sendMessage("You have no " + item.getMessage() + " to cut.");
         } else {
             p.getPackets().sendMessage("You have no more " + item.getMessage() + "'s to cut.");
         }
         Crafting.resetCrafting(p);
         return;
     }
     if (p.getSkills().getGreaterLevel(Skills.SKILL.CRAFTING) < item.getLevel()) {
         p.getPackets().sendMessage("You need a Crafting level of " + item.getLevel() + " to cut that gem.");
         Crafting.resetCrafting(p);
         return;
     }
     if (p.getInventory().deleteItem((int)GEMS[item.getCraftItem()][0])) {
         p.getInventory().addItem(item.getFinishedItem());
         p.getSkills().addXp(Skills.SKILL.CRAFTING, item.getXp());
         p.setLastAnimation(new Animation((int) GEMS[item.getCraftItem()][5]));
         p.getPackets().sendMessage("You cut the " + item.getMessage() + ".");
     }
     item.decreaseAmount();
     if (item.getAmount() >= 1) {
         Event cutMoreGemEvent = new Event(1500);
         cutMoreGemEvent.setAction(() => {
             cutGem(p, -1, -1, false);
             cutMoreGemEvent.stop();
         });
         Server.registerEvent(cutMoreGemEvent);
     }
 }
 public static void cutLog(Player p, int amount, int logType, int itemType, bool isStringing, bool newFletch)
 {
     Bow item = null;
     if (newFletch) {
         item = getBow(itemType, logType, amount, isStringing);
         Fletching.setFletchItem(p, item);
     }
     item = (Bow) Fletching.getFletchItem(p);
     if (item == null || p == null) {
         return;
     }
     bool stringing = item.isStringing();
     if (!canFletch(p, item, stringing)) {
         p.getPackets().closeInterfaces();
         return;
     }
     int animation = getAnimation(item);
     if (!stringing) {
         int amt = item.getItemType() == 2 ? ARROW_AMOUNT : 1;
         if (p.getInventory().deleteItem(LOGS[item.getLogType()])) {
             p.getInventory().addItem(item.getFinishedItem(), amt);
             p.getSkills().addXp(Skills.SKILL.FLETCHING, item.getXp());
             item.decreaseAmount();
             p.getPackets().sendMessage("You carefully cut the wood into " + MESSAGE[item.getItemType()] + ".");
             p.setLastAnimation(new Animation(animation));
         }
     } else {
         int[] bows = item.getItemType() == 0 ? UNSTRUNG_SHORTBOW : UNSTRUNG_LONGBOW;
         if (p.getInventory().deleteItem(BOWSTRING) && p.getInventory().deleteItem(bows[item.getLogType()])) {
             p.getInventory().addItem(item.getFinishedItem());
             p.getSkills().addXp(Skills.SKILL.FLETCHING, item.getXp());
             item.decreaseAmount();
             p.getPackets().sendMessage("You add a string to the bow.");
             p.setLastAnimation(new Animation(animation));
         }
     }
     p.getPackets().closeInterfaces();
     if (item.getAmount() >= 1) {
         Event cutMoreLogsEvent = new Event(1500);
         cutMoreLogsEvent.setAction(() => {
             cutLog(p, -1, -1, -1, false, false);
             cutMoreLogsEvent.stop();
         });
         Server.registerEvent(cutMoreLogsEvent);
     }
 }
 public static void newSilverItem(Player p, int amount, int index, bool newCraft)
 {
     index -= 120;
     if (newCraft) {
         p.setTemporaryAttribute("craftItem", new CraftItem(3, index, amount, (double) SILVER_ITEMS[index][3], (int) SILVER_ITEMS[index][0], (string) SILVER_ITEMS[index][4], (int) SILVER_ITEMS[index][2]));
     }
     CraftItem item = (CraftItem) p.getTemporaryAttribute("craftItem");
     if (item == null || p == null || item.getAmount() <= 0 || item.getCraftType() != 3) {
         Crafting.resetCrafting(p);
         return;
     }
     p.getPackets().closeInterfaces();
     string s = item.getCraftItem() == 0 ? "an" : "a";
     if (!p.getInventory().hasItem((int)SILVER_ITEMS[item.getCraftItem()][1])) {
         p.getPackets().sendMessage("You need " + s + " " + item.getMessage() + " mould to make that.");
         Crafting.resetCrafting(p);
         return;
     }
     if (!p.getInventory().hasItem(SILVER_BAR)) {
         p.getPackets().sendMessage("You don't have a Silver bar.");
         Crafting.resetCrafting(p);
         return;
     }
     if (p.getSkills().getGreaterLevel(Skills.SKILL.CRAFTING) < item.getLevel()) {
         p.getPackets().sendMessage("You need a Crafting level of " + item.getLevel() + " to smelt that.");
         Crafting.resetCrafting(p);
         return;
     }
     if (p.getInventory().deleteItem(SILVER_BAR)) {
         p.getInventory().addItem(item.getFinishedItem());
         p.getSkills().addXp(Skills.SKILL.CRAFTING, item.getXp());
         p.setLastAnimation(new Animation(3243));
         p.getPackets().sendMessage("You smelt the Silver bar in to " + s + " " + item.getMessage() + ".");
     }
     item.decreaseAmount();
     if (item.getAmount() >= 1) {
         Event makeMoreSilverItemEvent = new Event(1500);
         makeMoreSilverItemEvent.setAction(() =>
         {
             newSilverItem(p, -1, -1, false);
             makeMoreSilverItemEvent.stop();
         });
         Server.registerEvent(makeMoreSilverItemEvent);
     }
 }
	    private void startGame() {
            Event startFightCaveGameEvent = new Event(3000);
            startFightCaveGameEvent.setAction(() => {
				if (completed) {
					startFightCaveGameEvent.stop();
					return;
				}
				if (mobAmount > 0 || currentWave > 63) {
					return;
				}
				if (gamePaused && currentWave != 63) {
					startFightCaveGameEvent.stop();
					p.getPackets().forceLogout();
					return;
				}
				if (currentWave == 62) {
					startFightCaveGameEvent.setTick(8000);
					currentWave++;
					showJadMessage();
					return;
				} else if (currentWave < 62){
					currentWave++;
				}
				int[] mobs = decryptWave(currentWave);
				int amount = 0;
				for (int i = 0; i < mobs.Length; i++) {
					if (mobs[i] > 0) {
						Npc npc = new Npc(mobs[i]);
						Location minCoords = new Location(((20000 + 2363) + (200 * p.getIndex())), 25051, 0);
						Location maxCoords = new Location(((20000 + 2430) + (200 * p.getIndex())), 25123, 0);
						npc.setMinimumCoords(minCoords);
						npc.setMaximumCoords(maxCoords);
						npc.setLocation(new Location((20000 + 2387) + (200 * p.getIndex()) + misc.random(22), 20000 + 5069 + misc.random(33), 0));
						npc.setEntityFocus(p.getClientIndex());
						npc.setOwner(p);
						npc.setTarget(p);
						npc.getFollow().setFollowing(p);
						Server.getNpcList().Add(npc);
						amount++;
					}
				}
				mobAmount = (byte)amount;
		    });
            Server.registerEvent(startFightCaveGameEvent);
	    }
 public static void craftGlass(Player p, int amount, int index, bool newCraft)
 {
     if (newCraft) {
         p.setTemporaryAttribute("craftItem", new CraftItem(3, index, amount, (double) GLASS_ITEMS[index][2], (int) GLASS_ITEMS[index][0], (string) GLASS_ITEMS[index][3], (int) GLASS_ITEMS[index][1]));
     }
     CraftItem item = (CraftItem) p.getTemporaryAttribute("craftItem");
     if (item == null || p == null || item.getAmount() <= 0 || item.getCraftType() != 3) {
         Crafting.resetCrafting(p);
         return;
     }
     p.getPackets().closeInterfaces();
     if (!p.getInventory().hasItem(MOLTEN_GLASS)) {
         p.getPackets().sendMessage("You have no molten glass.");
         Crafting.resetCrafting(p);
         return;
     }
     if (!p.getInventory().hasItem(GLASSBLOWING_PIPE)) {
         p.getPackets().sendMessage("You need a glassblowing pipe if you wish to make a glass item.");
         Crafting.resetCrafting(p);
         return;
     }
     if (p.getSkills().getGreaterLevel(Skills.SKILL.CRAFTING) < item.getLevel()) {
         p.getPackets().sendMessage("You need a Crafting level of " + item.getLevel() + " to craft that item.");
         Crafting.resetCrafting(p);
         return;
     }
     if (p.getInventory().deleteItem(MOLTEN_GLASS)) {
         p.getInventory().addItem(item.getFinishedItem());
         p.getSkills().addXp(Skills.SKILL.CRAFTING, item.getXp());
         p.setLastAnimation(new Animation(884));
         p.getPackets().sendMessage("You blow through the pipe, shaping the molten glass into a " + item.getMessage() + ".");
     }
     item.decreaseAmount();
     if (item.getAmount() >= 1) {
         Event craftMoreGlassEvent = new Event(1500);
         craftMoreGlassEvent.setAction(() =>
         {
             craftGlass(p, -1, -1, false);
             craftMoreGlassEvent.stop();
         });
         Server.registerEvent(craftMoreGlassEvent);
     }
 }
        // TODO make this use an AreaEvent so itll work from a distance.
        /**
         * Will fill vials in a continuous motion from a water source.
         */
        public static bool fillingVial(Player p, Location loc)
        {
            if (!p.getInventory().hasItem(VIAL) || !p.getLocation().withinDistance(loc, 2))
            {
                return true;
            }
            if (p.getTemporaryAttribute("fillVialTimer") != null) {
                long lastFillTime = (int) p.getTemporaryAttribute("fillVialTimer");
                if (Environment.TickCount - lastFillTime < 600) {
                    return true;
                }
            }
            p.setTemporaryAttribute("fillingVials", true);
            p.setFaceLocation(loc);

            Event fillVialEvent = new Event(500);
            fillVialEvent.setAction(() => {
                int amountFilled = 0;
                string s = amountFilled == 1 ? "vial" : "vials";
                if (p.getTemporaryAttribute("fillingVials") == null || !p.getLocation().withinDistance(loc, 2) || !p.getInventory().hasItem(229)) {
                    p.setLastAnimation(new Animation(65535));
                    if (amountFilled > 0) {
                        p.getPackets().sendMessage("You fill up the " + s + " with water.");
                    }
                    fillVialEvent.stop();
                    return;
                }
                if (p.getInventory().replaceSingleItem(VIAL, VIAL_OF_WATER))
                {
                    p.setLastAnimation(new Animation(832));
                    amountFilled++;
                    p.setTemporaryAttribute("fillVialTimer", Environment.TickCount);
                } else {
                    if (amountFilled > 0) {
                        p.setLastAnimation(new Animation(65535));
                        p.getPackets().sendMessage("You fill up the " + s + " with water.");
                    }
                    fillVialEvent.stop();
                }
            });
            Server.registerEvent(fillVialEvent);
            return true;
        }
	    private void startWaitingEvent() {
            Event gameWaitingEvent = new Event(10000);
            gameWaitingEvent.setAction(() => {
				if (!gameInProgress) {
					if (playersWaiting.Count() >= 2 || (playersWaiting.Count() >= 1 && playersPlaying.Count() == 1)) {
						startGame();
						gameWaitingEvent.setTick(1000);
					}
				} else {
					if (playersPlaying.Count() <= 1) {
						gameInProgress = false;
						gameWaitingEvent.setTick(40000);
						setWinner();
					} else {
						if (Environment.TickCount - gameStartedTime >= (MAX_GAME_LENGTH * 60000)) {
							spawnMonsters();
						}
					}
				}
		    });
            Server.registerEvent(gameWaitingEvent);
	    }
 public static void craftSpinning(Player p, int amount, int index, bool newCraft)
 {
     if (newCraft) {
         p.setTemporaryAttribute("craftItem", new CraftItem(6, index, amount, (double) SPINNING_ITEMS[index][3], (int) SPINNING_ITEMS[index][0], (string) SPINNING_ITEMS[index][4], (int) SPINNING_ITEMS[index][2]));
     }
     CraftItem item = (CraftItem) p.getTemporaryAttribute("craftItem");
     if (item == null || p == null || item.getAmount() <= 0 || item.getCraftType() != 6) {
         Crafting.resetCrafting(p);
         return;
     }
     p.getPackets().closeInterfaces();
     int i = item.getCraftItem();
     if (!p.getInventory().hasItem((int) SPINNING_ITEMS[i][1])) {
         p.getPackets().sendMessage("You have no " + item.getMessage() + ".");
         Crafting.resetCrafting(p);
         return;
     }
     if (p.getSkills().getGreaterLevel(Skills.SKILL.CRAFTING) < item.getLevel()) {
         p.getPackets().sendMessage("You need a Crafting level of " + item.getLevel() + " to spin that.");
         Crafting.resetCrafting(p);
         return;
     }
     if (p.getInventory().deleteItem((int) SPINNING_ITEMS[i][1])) {
         p.getInventory().addItem(item.getFinishedItem());
         p.getSkills().addXp(Skills.SKILL.CRAFTING, item.getXp());
         p.setLastAnimation(new Animation(894));
         p.getPackets().sendMessage("You spin the " + item.getMessage() + " into a " + SPIN_FINISH[i] + ".");
     }
     item.decreaseAmount();
     if (item.getAmount() >= 1) {
         Event craftMoreSpinningEvent = new Event(750);
         craftMoreSpinningEvent.setAction(() => {
             craftSpinning(p, -1, -1, false);
             craftMoreSpinningEvent.stop();
         });
         Server.registerEvent(craftMoreSpinningEvent);
     }
 }
 public static void burnBoil(Player p, int x, int y)
 {
     AreaEvent burnBoilAreaEvent = new AreaEvent(p, x-1, y-1, x +3, y+2);
     burnBoilAreaEvent.setAction(() => {
         if (!p.getInventory().hasItem(590)) {
             p.getPackets().sendMessage("You need a tinderbox to get past this obstacle.");
             return;
         }
         p.setFaceLocation(new Location(x + 1, y, 0));
         p.setLastAnimation(new Animation(733));
         p.setTemporaryAttribute("unmovable", true);
         Event burnBoilEvent = new Event(1900);
         burnBoilEvent.setAction(() => {
             int status = 0;
             int[] BOIL = {7165, 7166, 7167};
             if (status < 3) {
                 p.getPackets().createObject(BOIL[status], new Location(x, y, 0), x == 3060 ? 3 : 1, 10);
             }
             status++;
             if (status == 1) {
                 burnBoilEvent.setTick(1300);
             }
             if (status == 3) {
                 p.setLastAnimation(new Animation(65535));
                 burnBoilEvent.setTick(1000);
             }
             if (status == 4) {
                 burnBoilEvent.stop();
                 teleportPastObstacle(p);
                 p.removeTemporaryAttribute("unmovable");
             }
         });
         Server.registerEvent(burnBoilEvent);
         return;
     });
     Server.registerCoordinateEvent(burnBoilAreaEvent);
 }
 public static void createXbow(Player p, int amount, int xbowType, bool isStringing, bool newFletch)
 {
     SkillItem item = null;
     if (newFletch || Fletching.getFletchItem(p) == null) {
         item = getXbow(xbowType, isStringing, amount);
         Fletching.setFletchItem(p, item);
     }
     item = (SkillItem) Fletching.getFletchItem(p);
     if (item == null || p == null) {
         return;
     }
     bool stringing = item.getItemTwo() == XBOW_STRING ? true : false;
     if (!canFletch(p, item)) {
         p.getPackets().closeInterfaces();
         return;
     }
     if (p.getInventory().deleteItem(item.getItemOne()) &&  p.getInventory().deleteItem(item.getItemTwo())) {
         p.getInventory().addItem(item.getFinishedItem());
         p.getSkills().addXp(Skills.SKILL.FLETCHING, item.getXp());
         item.decreaseAmount();
         p.getPackets().closeInterfaces();
         if (!stringing) {
             p.getPackets().sendMessage("You attach some limbs to the Crossbow.");
         } else {
             p.setLastAnimation(new Animation(6677));
             p.getPackets().sendMessage("You add a Crossbow String to the Crossbow, you have completed the " + ItemData.forId(item.getFinishedItem()).getName() + ".");
         }
     }
     if (item.getAmount() >= 1) {
         Event createMoreXBowEvent = new Event(1500);
         createMoreXBowEvent.setAction(() => {
             createXbow(p, -1, -1, false, false);
             createMoreXBowEvent.stop();
         });
         Server.registerEvent(createMoreXBowEvent);
     }
 }
	    public static void enterCave(Player p) {
            AreaEvent enterCaveAreaEvent = new AreaEvent(p, 2438, 5168, 2439, 5168);
            enterCaveAreaEvent.setAction(() => {
				/*
				 * Fight cave is 20k squares from the original place, then another (200 * playerIndex) squares west.
				 */
				Location instanceLocation = new Location((20000 + 2413) + (200 * p.getIndex()), 20000 + 5116, 0);
				p.teleport(instanceLocation);
				p.setFightCave(new FightCaveSession(p));
				
                Event caveNpcEvent = new Event(600);
                caveNpcEvent.setAction(() => {
						caveNpcEvent.stop();
						p.getPackets().sendNPCHead(2617, 242, 1);
						p.getPackets().modifyText("TzHaar-Mej-Jal", 242, 3);
						p.getPackets().modifyText("You're on your own now, JalYt.", 242, 4);
						p.getPackets().modifyText("Pepare to fight for your life!", 242, 5);
						p.getPackets().animateInterface(9827, 242, 1);
						p.getPackets().sendChatboxInterface2(242);
				});
                Server.registerEvent(caveNpcEvent);
		    });
            Server.registerCoordinateEvent(enterCaveAreaEvent);
	    }
	    private void changeObject(WorldObject worldObject) {
		    if (worldObject != null) {
			    worldObject.setSecondForm(true);
			    foreach(Player p in Server.getPlayerList()) {
				    if (p != null) {
					    if (p.getLocation().withinDistance(worldObject.getLocation(), 60)) {
						    if (!worldObject.isFire()) {
							    p.getPackets().removeObject(worldObject.getLocation(), worldObject.getFace(), worldObject.getType());
							    p.getPackets().createObject(worldObject.getSecondaryId(), worldObject.getLocation(), worldObject.getFace(), worldObject.getType());
						    } else {
							    p.getPackets().createObject(worldObject.getOriginalId(), worldObject.getLocation(), worldObject.getFace(), worldObject.getType());
						    }
					    }
				    }
			    }
			    int delay = worldObject.isFire() ? (60000 + misc.random(90000)) : worldObject.getRestoreDelay(); 
                Event restoreObjectEvent = new Event(delay);
                restoreObjectEvent.setAction(() => {
					    restoreObject(worldObject);
					    restoreObjectEvent.stop();
			    });
                Server.registerEvent(restoreObjectEvent);
		    }
	    }
	    public void teleFromCave(bool quit) {
		    p.teleport(new Location(2439, 5169, 0));
		    Server.removeAllPlayersNPCs(p);
            Event teleFromCaveEvent = new Event(600);
            teleFromCaveEvent.setAction(() => {
                teleFromCaveEvent.stop();
				string s = "You have defeated TzTok-Jad, I am most impressed!";
				string s1 = "Please accept this gift as a reward.";
				if (quit) {
					if (currentWave > 1) {
						s = "Well done in the cave, here, take TokKul as a reward.";
						s1 = null;
						p.getInventory().addItemOrGround(6529, getTokkulReward());
					} else {
						s = "Well I suppose you tried... better luck next time.";
						s1 = null;
					}
				} else {
					p.getInventory().addItemOrGround(6570);
					p.getInventory().addItemOrGround(6529, 16064);
				}
				if (s1 != null) {
					p.getPackets().sendNPCHead(2617, 242, 1);
					p.getPackets().modifyText("TzHaar-Mej-Jal", 242, 3);
					p.getPackets().modifyText(s, 242, 4);
					p.getPackets().modifyText(s1, 242, 5);
					p.getPackets().animateInterface(9827, 242, 1);
					p.getPackets().sendChatboxInterface2(242);
				} else {
					p.getPackets().sendNPCHead(2617, 241, 1);
					p.getPackets().modifyText("TzHaar-Mej-Jal", 241, 3);                    
					p.getPackets().modifyText(s, 241, 4);
					p.getPackets().animateInterface(9827, 241, 1);
					p.getPackets().sendChatboxInterface2(241);
				}
				p.clearKillersHits();
				p.setLastAttackType(1);
				p.setLastAttack(0);
				p.setTarget(null);
				p.setAttacker(null);
                p.getSkills().setCurLevel(Skills.SKILL.HITPOINTS, p.getSkills().getMaxLevel(Skills.SKILL.HITPOINTS));
                p.getPackets().sendSkillLevel(Skills.SKILL.HITPOINTS);
				p.setSkullCycles(0);
				p.setEntityFocus(65535);
				p.getSpecialAttack().resetSpecial();
				p.getEquipment().setWeapon();
				p.setLastkiller(null);
				Combat.resetCombat(p, 1);
				p.setDead(false);
				p.setLastVengeanceTime(0);
				p.setVengeance(false);
				p.removeTemporaryAttribute("willDie");
				p.setFrozen(false);
				p.removeTemporaryAttribute("unmovable");
				p.setAntifireCycles(0);
				p.setSuperAntipoisonCycles(0);
				Prayer.deactivateAllPrayers(p);
				p.setTeleblockTime(0);
				p.removeTemporaryAttribute("teleblocked");
				p.removeTemporaryAttribute("autoCastSpell");
                foreach (Skills.SKILL skill in Enum.GetValues(typeof(Skills.SKILL)))
					p.getSkills().setCurLevel(skill, p.getSkills().getMaxLevel(skill));
				p.getPackets().sendSkillLevels();
				p.setFightCave(null);
		    });
            Server.registerEvent(teleFromCaveEvent);
	    }
	    public static void leverTeleport(Player p, int option) {
		    p.getPackets().closeInterfaces();
		    Location teleLocation = new Location(LEVER_COORDINATES[option][0], LEVER_COORDINATES[option][1], LEVER_COORDINATES[option][2]);
		    
            Event leverTeleportEvent = new Event(200);
            leverTeleportEvent.setAction(() => {
				leverTeleportEvent.stop();
				if (p.getTemporaryAttribute("teleblocked") != null) {
					p.getPackets().sendMessage("A magical force prevents you from teleporting!");
					return;
				} else if ((p.getTemporaryAttribute("teleporting") != null )) {
					return;
				}
				p.setLastAnimation(new Animation(2140));
				p.getPackets().closeInterfaces();
				p.setTemporaryAttribute("teleporting", true);
                p.getWalkingQueue().resetWalkingQueue();
				p.getPackets().clearMapFlag();
				SkillHandler.resetAllSkills(p);
                Event levelTeleportStartEvent = new Event(700);
                levelTeleportStartEvent.setAction(() => {
					levelTeleportStartEvent.stop();
					p.setLastAnimation(new Animation(8939, 0));
					p.setLastGraphics(new Graphics(1576, 0));
                    Event levelTeleportFinishEvent = new Event(1800);
                    levelTeleportFinishEvent.setAction(() => {
                        levelTeleportFinishEvent.stop();
						p.teleport(teleLocation);
						p.setLastAnimation(new Animation(8941, 0));
						p.setLastGraphics(new Graphics(1577, 0));
						Teleport.resetTeleport(p);
					});
                    Server.registerEvent(levelTeleportFinishEvent);
				});
                Server.registerEvent(levelTeleportStartEvent);
		    });
            Server.registerEvent(leverTeleportEvent);
	    }
        public void fireCannon()
        {
            if (firing) {
                loadCannon();
                return;
            }

            firing = true;
            int cannonTurnAnimation = 515;
            Event attemptFireCannonEvent = new Event(1000);
            attemptFireCannonEvent.setAction(() => {
                if (!firing)
                {
                    attemptFireCannonEvent.stop();
                    return;
                }
                p.getPackets().newObjectAnimation(cannonLocation, cannonTurnAnimation);
                Event fireCannonEvent = new Event(600);
                fireCannonEvent.setAction(() => {
                    if (!firing)
                    {
                        fireCannonEvent.stop();
                        return;
                    }
                    if (stopCannon && cannonTurnAnimation == 514)
                    {
                        cannonTurnAnimation = 514;
                        fireCannonEvent.stop();
                        firing = false;
                        return;
                    }
                    if (!stopCannon) {
                        if (checkHitTarget())
                            checkCannonballs();
                    }
                    if (direction++ == 7)
                        direction = 0;
                    if (++cannonTurnAnimation > 521)
                        cannonTurnAnimation = 514;
                   fireCannonEvent.stop();
                });
                Server.registerEvent(fireCannonEvent);
            });
            Server.registerEvent(attemptFireCannonEvent);
        }
        protected bool checkHitTarget()
        {
            int cannonX = fakeCannonLocation.getX();
            int cannonY = fakeCannonLocation.getY();
            Npc[] npcsToAttack = new Npc[npcsInArea.Count];
            bool hit = false;
            foreach(Npc n in Server.getNpcList()) {
                hit = false;
                Location l = n.getLocation();
                if (n == null || !n.isVisible() || n.isDead() || !n.getLocation().withinDistance(fakeCannonLocation, 8)) {
                    continue;
                }
                switch(direction) {
                    case 0: // North
                        hit = l.inArea(cannonX-1, cannonY, cannonX+1, cannonY+8);
                        break;

                    case 1: // North east
                        break;

                    case 2: // East:
                        hit = l.inArea(cannonX, cannonY-1, cannonX+8, cannonY+1);
                        break;

                    case 3: // South east
                        break;

                    case 4: // South
                        hit = l.inArea(cannonX-1, cannonY-8, cannonX+1, cannonY);
                        break;

                    case 5: // South west
                        break;

                    case 6: // West
                        hit = l.inArea(cannonX-8, cannonY-1, cannonX, cannonY+1);
                        break;

                    case 7: // North west
                        break;
                }
                if (hit) {
                    Npc npc = n;
                    p.getPackets().sendProjectile(fakeCannonLocation, n.getLocation(), 30, 53, 50, 38, 38, 40, n);
                    Event doCannonHitEvent = new Event(1000);
                    doCannonHitEvent.setAction(() => {
                        doCannonHitEvent.stop();
                        double damage = misc.randomDouble(30);
                        p.getSkills().addXp(Skills.SKILL.RANGE, damage * 2);
                        npc.hit(damage);
                        npc.setLastAnimation(new Animation(npc.getDefenceAnimation()));
                    });
                    Server.registerEvent(doCannonHitEvent);
                    return true;
                }
            }
            return false;
        }
 public void newCannon()
 {
     setupTime = Environment.TickCount;
     Event setupNewCannonEvent = new Event(1000);
     setupNewCannonEvent.setAction(() => {
         string prefixMsg = (constructionStage == 0) ? "You place the " : "You add the ";
         string suffixMsg = (constructionStage == 0) ? " on the ground." : ".";
         if (p.getInventory().deleteItem(CANNON_PIECES[constructionStage]))
         {
             p.getPackets().createObject(CANNON_OBJECTS[constructionStage], cannonLocation, 0, 10);
             p.getPackets().sendMessage(prefixMsg + CONSTRUCTION_MESSAGE[constructionStage] + suffixMsg);
             if (++constructionStage >= 4) {
                 constructionStage--;
                 setupNewCannonEvent.stop();
                 return;
             }
             p.setLastAnimation(new Animation(827));
         } else {
             setupNewCannonEvent.stop();
         }
     });
     Server.registerEvent(setupNewCannonEvent);
 }
        public static void slashWeb(Player p, ushort webId, Location webLocation)
        {
            AreaEvent slashWebAreaEvent = new AreaEvent(p, webLocation.getX() - 1, webLocation.getY() - 1, webLocation.getX() + 1, webLocation.getY() + 1);
            slashWebAreaEvent.setAction(() => {
				long lastSlash = 0;
				p.setFaceLocation(webLocation);
				if (p.getTemporaryAttribute("lastWebSlash") != null) {
					lastSlash = (int)p.getTemporaryAttribute("lastWebSlash");
				}
				if (Environment.TickCount - lastSlash <= 800) {
					return;
				}
				if (Server.getGlobalObjects().originalObjectExists(webId, webLocation)) {
					p.setLastAnimation(new Animation(p.getAttackAnimation()));
					p.setTemporaryAttribute("lastWebSlash", Environment.TickCount);
                    Event attemptCutWebEvent = new Event(500);
                    attemptCutWebEvent.setAction(() => {
                        attemptCutWebEvent.stop();
						bool webExists = Server.getGlobalObjects().originalObjectExists(webId, webLocation);
						Server.getGlobalObjects().lowerHealth(webId, webLocation);
						if (Server.getGlobalObjects().originalObjectExists(webId, webLocation)) {
							p.getPackets().sendMessage("You fail to cut through the web.");
						} else {
							if (webExists) { // This means we slashed it, if !webExists, someone else slashed it in the last 500ms
                                p.getPackets().sendMessage("You slash through the web!");
							}
						}
					});
                    Server.registerEvent(attemptCutWebEvent);
				}
		    });
            Server.registerCoordinateEvent(slashWebAreaEvent);

	    }