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);
			    }
		    }
	    }
 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);
     }
 }
	    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();
	    }
	    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);
	    }
        // 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;
        }
	    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);
	    }
	    private static void activateObelisk(int index) {
		    if (obeliskActivated[index])
			    return;

		    Location[] obeliskLocations = getLocations(index);
		    for (int i = 0; i < 4; i++) {
			    WorldObject obj = new WorldObject(OBELISK_ID[index], ACTIVATED_ID, obeliskLocations[i], 0, 10);
			    obj.setSecondForm(true);
			    Server.getGlobalObjects().add(obj);
			    foreach(Player p in Server.getPlayerList()) {
				    p.getPackets().createObject(ACTIVATED_ID, obeliskLocations[i], 0, 10);
			    }
		    }
		    obeliskActivated[index] = true;
            Event activateObeliskEvent = new Event(4000 + (misc.random(4)) * 1000);
            activateObeliskEvent.setAction(() => {
				activateObeliskEvent.stop();
				int randomOb = index;
				while(randomOb == index) {
					// While loop so if the random one is the same one, it picks a new one
					randomOb = misc.random(OBELISK_ID.Length);
				}
				int random = randomOb;
				foreach(Player p in Server.getPlayerList()) {
					if (p != null) {
						if (p.getLocation().inArea(OBELISK_LOCATIONS[index][0] - 2, OBELISK_LOCATIONS[index][1] - 2, OBELISK_LOCATIONS[index][0] + 2, OBELISK_LOCATIONS[index][1] + 2)) {
							// TODO get the big purple graphic
							p.setLastGraphics(new Graphics(1690));
							p.setLastAnimation(new Animation(8939));
							Player p2 = p;

                            Event obeliskTeleportEvent = new Event(1200);
                            obeliskTeleportEvent.setAction(() => {
								obeliskTeleportEvent.stop();
								p2.teleport(new Location((OBELISK_LOCATIONS[random][0] - 1) + misc.random(2), (OBELISK_LOCATIONS[random][1] - 1) + misc.random(2), 0));
								
                                Event obeliskAnimationEvent = new Event(500);
                                obeliskAnimationEvent.setAction(() => {
                                    obeliskAnimationEvent.stop();
									p2.setLastAnimation(new Animation(8941));
								});
                                Server.registerEvent(obeliskAnimationEvent);
							});
                            Server.registerEvent(obeliskTeleportEvent);
						}
					}
				}

				for (int i = 0; i < 4; i++) {
					WorldObject obj = Server.getGlobalObjects().getObject(OBELISK_ID[index], obeliskLocations[i]);
					Server.getGlobalObjects().restoreObject(obj);
				}
				obeliskActivated[index] = false;
		    });
	    }
 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);
	    }
 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 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);
        }
 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);
     }
 }
 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);
     }
 }
 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 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 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 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);
 }
	    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 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);
	    }
	    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);
	    }
        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);

	    }
	    public static void crossDitch(Player p, int x, int y) {
		    if (p.getTemporaryAttribute("unmovable") != null) {
			    return;
		    }
                AreaEvent crossDitchAreaEvent = new AreaEvent(p, x, y - 1, x, y + 2);
                crossDitchAreaEvent.setAction(() => {
				    p.getPackets().closeInterfaces();
				    p.getWalkingQueue().resetWalkingQueue();
				    p.setTemporaryAttribute("unmovable", true);
				    int newY = p.getLocation().getY() >= 3523 ? p.getLocation().getY()-3 : p.getLocation().getY()+3;
				    int dir = newY == 3 ? 0 : 4;
				    Location faceLocation = new Location(p.getLocation().getX(), dir == 3 ? 3523 : 3520, 0);
				    p.setFaceLocation(faceLocation);
                    Event crossDitchMoveEvent = new Event(500);
                    crossDitchMoveEvent.setAction(() => {
					    crossDitchMoveEvent.stop();
					    p.setLastAnimation(new Animation(6132));
					    int regionX = p.getUpdateFlags().getLastRegion().getRegionX();
					    int regionY = p.getUpdateFlags().getLastRegion().getRegionY();
					    int lX = (p.getLocation().getX() - ((regionX - 6) * 8));
					    int lY = (p.getLocation().getY() - ((regionY - 6) * 8));
					    ForceMovement movement = new ForceMovement(lX, lY, lX, newY, 33, 60, dir);
					    p.setForceMovement(movement);		
					    p.setFaceLocation(new Location(x, y, 0));
                        Event crossDitchTeleportEvent = new Event(1250);
                        crossDitchTeleportEvent.setAction(() => {
						    crossDitchTeleportEvent.stop();
						    int playerY = p.getLocation().getY();
						    int nY = playerY >= 3523 ? 3520 : 3523;
						    p.teleport(new Location(p.getLocation().getX(), nY, 0));
						    p.removeTemporaryAttribute("unmovable");
				        });
                        Server.registerEvent(crossDitchTeleportEvent);
			    });
                Server.registerEvent(crossDitchMoveEvent);
		    });
            Server.registerCoordinateEvent(crossDitchAreaEvent);
	    }
        private static void lightFire(Player p, int logIndex, bool colouredFire, int slot)
        {
            //if (!World.getInstance().getObjectLocations().tileAvailable(new Location(p.getLocation().getX() - 1, p.getLocation().getY(), p.getLocation().getZ()))) {
                //return;
            //}
            // TODO clip this
            p.getPackets().closeInterfaces();
            int log = colouredFire ? COLOURED_LOGS[logIndex] : LOGS[logIndex];

            if (!canMakeFire(p, logIndex, colouredFire))
                return;

            if (slot != -1) {
                //item in inventory wasn't a log (you may have swapped it/banked it quickly).
                if(!p.getInventory().deleteItem(log, slot, 1))
                    return;

                Server.getGroundItems().newEntityDrop(new GroundItem(log, 1, (Location)p.getLocation().Clone(), p));
            } else { //light fire using logs already placed on ground.
                //check if there is a log on the ground in our current location, if not we can't make fire.
                GroundItem gi = Server.getGroundItems().itemExists(p.getLocation(), log);
                if (gi == null)
                    return; //so we quit here.
            }

            int delay = getDelay(p, logIndex);
            p.getWalkingQueue().resetWalkingQueue();
            p.getPackets().clearMapFlag();
            if (delay == START_DELAY)
                p.setLastAnimation(new Animation(733));
            p.getPackets().sendMessage("You attempt to light the logs.");
            ushort fireObject = colouredFire ? COLOURED_FIRES[logIndex] : FIRE_OBJECT;
            p.setTemporaryAttribute("unmovable", true);
            Event lightFireEvent = new Event(delay);
            lightFireEvent.setAction(() => {
                lightFireEvent.stop();
                p.setTemporaryAttribute("lastFiremake", Environment.TickCount);
                p.setLastAnimation(new Animation(65535));
                p.getWalkingQueue().forceWalk(-1, 0);
                Event finishFireEvent = new Event(1000);
                finishFireEvent.setAction(() => {
                    finishFireEvent.stop();
                    Location fireLocation = new Location((p.getLocation().getX() + 1), p.getLocation().getY(), p.getLocation().getZ());
                    if (Server.getGroundItems().deleteItem(log, fireLocation)) {
                        p.getPackets().sendMessage("The fire catches and the logs begin to burn.");
                        p.setFaceLocation(fireLocation);
                        p.getSkills().addXp(Skills.SKILL.FIREMAKING, FIRE_XP[logIndex]);
                        Server.getGlobalObjects().newFire(p, fireObject, fireLocation);
                    }
                    p.removeTemporaryAttribute("unmovable");
                });
                Server.registerEvent(finishFireEvent);
            });
            Server.registerEvent(lightFireEvent);
        }
	    private static void travel(Player p, int index, bool returning) {
		    p.setTemporaryAttribute("unmovable", true);
		    p.getPackets().displayInterface(120);
		    if (returning) {
			    p.getPackets().sendMessage("You sail off back to Oo'glog..");
		    } else {
			    p.getPackets().sendMessage("You climb aboard Captain Bentley's boat and set sail to " + DESTINATION_NAMES[index] + ".");
		    }
            Event travelEvent = new Event(2000);
            int travelCounter = 0;
		    travelEvent.setAction(() => {
                if (travelCounter == 0)
                {
                    travelCounter++;
					travelEvent.setTick(600);
					if (returning) {
						p.teleport(new Location(2622, 2857, 0));
					} else {
						p.teleport(new Location(LOCATIONS[index][0], LOCATIONS[index][1], LOCATIONS[index][2]));
					}
				} else {
					travelEvent.stop();
					p.getPackets().sendOverlay(170);
					p.removeTemporaryAttribute("unmovable");
					p.getPackets().sendMessage(returning ? "The boat arrives back in Oo'glog." : DESTINATION_MESSAGES[index]);
					p.getPackets().closeInterfaces();
                    Event removeOverlayEvent = new Event(2000);
                    removeOverlayEvent.setAction(() => {
                        removeOverlayEvent.stop();
						p.getPackets().sendRemoveOverlay();
						if (index == 1) {
							p.removeTemporaryAttribute("snowInterface");
						}
					});
                    Server.registerEvent(removeOverlayEvent);
				}
		    });
            Server.registerEvent(travelEvent);
	    }