public static void displayEmptyRockMessage(Player player, Location rockLocation)
 {
     AreaEvent displayEmptyRockMessageAreaEvent = new AreaEvent(player, rockLocation.getX() - 1, rockLocation.getY() - 1, rockLocation.getX() + 1, rockLocation.getY() + 1);
     displayEmptyRockMessageAreaEvent.setAction(() => {
         player.getPackets().sendMessage("There is currently no ore available from this rock.");
     });
 }
	    public static bool leaveCrypt(Player player, int stairs, int x, int y) {
		    if (stairs != 6707 && stairs != 6703 && stairs != 6702 && stairs != 6704 && stairs != 6705 && stairs != 6706) {
			    return false;
		    }
		    Player p = player;
		    Location stairLocation;
		    Location moundLocation;
		    int cryptIndex = getCryptIndex(p);
		    if (cryptIndex == -1) {
			    return false;
		    }
            stairLocation = new Location(STAIR_COORDS[cryptIndex][0], STAIR_COORDS[cryptIndex][1], 3);
		    moundLocation = new Location(MOUND_COORDS[cryptIndex][0] + misc.random(3), MOUND_COORDS[cryptIndex][1] + misc.random(3), 0);
		    if (p.getLocation().Equals(stairLocation)) {
			    p.setFaceLocation(new Location(x, y, 3));
			    p.teleport(moundLocation);
			    return true;
		    }
            CoordinateEvent teleportMoundCoordinateEvent = new CoordinateEvent(p, stairLocation);
            teleportMoundCoordinateEvent.setAction(() => {
				    p.teleport(moundLocation);
		    });
            Server.registerCoordinateEvent(teleportMoundCoordinateEvent);
		    return true;
	    }
	    public bool useDoor(Player p, int doorId, int doorX, int doorY, int doorHeight) {
		    Location doorLocation = new Location(doorX, doorY, doorHeight);
		    foreach(Door door in doors) {
			    int id = door.isDoorOpen() ? door.getOpenDoorId() : door.getClosedDoorId();
			    if (id == doorId) {
				    if (door.getDoorLocation().Equals(doorLocation)) {
					    if (door.isDoorOpen() && (Environment.TickCount - door.getLastChangeTime() <= PLAYER_CHANGE_DELAY)) {
						    // door was opened in the last PLAYER_CHANGE_DELAY ms..cant be instantly closed
						    return true;
					    } else if (!door.isClosable() && door.isDoorOpen()) {
						    // door cannot be closed by a player
						    return true;
					    }
					    Door d = door;
                        AreaEvent useDoorAreaEvent = new AreaEvent(p, doorLocation.getX() - 1, doorLocation.getY() - 1, doorLocation.getX() + 1, doorLocation.getY() + 1);
                        useDoorAreaEvent.setAction(() => {
							changeDoor(p, d);
					    });
                        Server.registerCoordinateEvent(useDoorAreaEvent);
					    return true;
				    }
			    }
		    }
		    return false;
	    }
 public WorldObject(ushort id, Location location, int face, int type)
 {
     this.originalId = id;
     this.location = location;
     this.face = face;
     this.type = type;
     this.objectType = 0;
 }
 public WorldObject(Location location, int face, int type, bool deleteObject)
 {
     this.location = location;
     this.face = face;
     this.type = type; // default
     this.objectType = 0;
     this.deleteObject = deleteObject;
 }
 public WorldObject(ushort id, Location location, int face, int type, bool spawned)
 {
     this.originalId = id;
     this.location = location;
     this.face = face;
     this.type = type;
     this.objectType = 0;
     this.spawnedObject = true;
 }
 public HeightObject(int objectId, Location loc, Location teleLoc, Location minCoords, Location maxCoords)
 {
     this.objectId = objectId;
     this.objectLocation = loc;
     this.teleportLocation = teleLoc;
     this.minCoords = minCoords;
     this.maxCoords = maxCoords;
     this.type = Event_Type.AREA_POSITION;
 }
 public HeightObject(int objectId, Location objectLocation, Location standLocation, Location teleportLocation, int animation)
 {
     this.objectId = objectId;
     this.objectLocation = objectLocation;
     this.teleportLocation = teleportLocation;
     this.animation = animation;
     this.standLocation = standLocation;
     this.type = Event_Type.COORDINATE_POSITION;
 }
	    protected static void createdAnimatedArmour(Player p, int index) {
		    if (p.getTemporaryAttribute("warriorGuildAnimator") == null) {
			    return;
		    }
		    p.setLastAnimation(new Animation(827));
		    p.setTemporaryAttribute("unmovable", true);
		    for (int i = 0; i < ARMOUR_SETS[index].Length; i++) {
			    p.getInventory().deleteItem(ARMOUR_SETS[index][i]);
		    }
		    p.getPackets().sendChatboxInterface(211);
		    p.getPackets().modifyText("You place the armour onto the platform where it", 211, 1);
		    p.getPackets().modifyText("dissapears...", 211, 2);
		    int animatorIndex = (int) p.getTemporaryAttribute("warriorGuildAnimator");
            Event createAnimatedArmourEvent = new Event(1500);
            int createAnimatedArmourCounter = 0;
            Npc npc = null;
            createAnimatedArmourEvent.setAction(() => {
                if (createAnimatedArmourCounter == 0)
                {
					p.getPackets().sendChatboxInterface(211);
					p.getPackets().modifyText("The animator hums, something appears to be working.", 211, 1);
					p.getPackets().modifyText("You stand back.", 211, 2);
					createAnimatedArmourEvent.setTick(500);
                }
                else if (createAnimatedArmourCounter == 1)
                {
					p.getWalkingQueue().forceWalk(0, + 3);
					createAnimatedArmourEvent.setTick(2000);
                }
                else if (createAnimatedArmourCounter == 2)
                {
					createAnimatedArmourEvent.setTick(500);
					Location minCoords = new Location(2849, 3534, 0);
					Location maxCoords = new Location(2861, 3545, 0);
					npc = new Npc(ANIMATED_ARMOUR[index]);
					npc.setMinimumCoords(minCoords);
					npc.setMaximumCoords(maxCoords);
					npc.setLocation(new Location(ANIMATOR_LOCATIONS[animatorIndex][0], ANIMATOR_LOCATIONS[animatorIndex][1], 0));
					npc.setWalkType(WalkType.STATIC);
					npc.setForceText("I'm ALIVE!");
					npc.setLastAnimation(new Animation(4166));
					npc.setEntityFocus(p.getClientIndex());
					npc.setOwner(p);
					npc.setTarget(p);
					p.getPackets().setArrowOnEntity(1, npc.getClientIndex());
					Server.getNpcList().Add(npc);
				} else {
					p.setEntityFocus(npc.getClientIndex());
					p.getPackets().softCloseInterfaces();
					createAnimatedArmourEvent.stop();
					p.removeTemporaryAttribute("unmovable");
					npc.getFollow().setFollowing(p);
				}
                createAnimatedArmourCounter++;
		    });
            Server.registerEvent(createAnimatedArmourEvent);
	    }
 public HeightObject(int objectId, Location objectLocation, Location teleportLocation, Location minCoords, Location maxCoords, int animation)
 {
     this.objectId = objectId;
     this.objectLocation = objectLocation;
     this.teleportLocation = teleportLocation;
     this.animation = animation;
     this.minCoords = minCoords;
     this.maxCoords = maxCoords;
     this.type = Event_Type.AREA_POSITION;
 }
	    public bool fireExists(Location location) {
		    foreach(WorldObject o in objects) {
			    if (o != null) {
				    if(o.getLocation().Equals(location) && o.isFire()) {
					    return true;
				    }
			    }
		    }
		    return false;
	    }
 public CoordinateEvent(Player player, Location location)
     : base(0)
 {
     this.player = player;
     this.location = location;
     this.oldLocation = location;
     if (player != null)
     {
         player.setDistanceEvent(this);
     }
 }
 public Rock(int index, ushort rockId, Location loc, int ore, int level, string name, double xp)
 {
     this.rockIndex = index;
     this.rockLocation = loc;
     this.ore = ore;
     this.rockId = rockId;
     this.level = level;
     this.xp = xp;
     this.name = name;
     this.continueMine = index == 0 || index == 9;
 }
 public Tree(int index, ushort treeId, Location loc, int log, int level, string name, double xp, int distance)
 {
     this.treeIndex = index;
     this.treeLocation = loc;
     this.log = log;
     this.treeId = treeId;
     this.level = level;
     this.xp = xp;
     this.name = name;
     this.distance = distance;
 }
 public WorldObject(ushort originalId, int secondaryId, int face, Location location, int delay, int health)
 {
     this.originalId = originalId;
     this.secondaryId = secondaryId;
     this.location = location;
     this.face = face;
     this.restoreDelay = delay;
     this.objectHealth = health;
     this.secondForm = false;
     this.type = 10; // default
     this.objectType = 0;
 }
 public DwarfCannon(Player player)
 {
     p = player;
     cannonLocation = p.getLocation();
     fakeCannonLocation = new Location(cannonLocation.getX()+1, cannonLocation.getY()+1, cannonLocation.getY());
     firing = false;
     cannonballs = 0;
     constructionStage = 0;
     direction = 0;
     setNpcsInArea();
     newCannon();
 }
 public GroundItem(int id, int amount, Location location, Player owner)
     : base(id, amount)
 {
     this.location = location;
     this.owner = owner;
     respawn = false;
     this.dropTime = Environment.TickCount;
     if (owner != null)
     {
         ownerId = owner.getIndex();
     }
 }
 public Spot(int[] spotFish, int[] spotLevel, int spotindex, int spotId, double[] spotXp, Location spotLocation, int primaryItem, int secondaryItem, string primaryName, string secondaryName, bool secondOption)
 {
     this.fish = spotFish;
     this.level = spotLevel;
     this.spotindex = spotindex;
     this.spotId = spotId;
     this.fishingXp = spotXp;
     this.spotLocation = spotLocation;
     this.secondaryItem = secondaryItem;
     this.primaryItem = primaryItem;
     this.primaryName = primaryName;
     this.secondaryName = secondaryName;
     this.secondOption = secondOption;
 }
	    public static bool useWildernessObelisk(Player p, int id, Location loc) {
		    for(int i = 0; i < OBELISK_ID.Length; i++) {
			    if (id == OBELISK_ID[i]) {
				    if (loc.inArea(OBELISK_LOCATIONS[i][0] - 2, OBELISK_LOCATIONS[i][1] - 2, OBELISK_LOCATIONS[i][0] + 2, OBELISK_LOCATIONS[i][1] + 2)) {
                        AreaEvent useWildernessObeliskAreaEvent = new AreaEvent(p, loc.getX() - 1, loc.getY() - 1, loc.getX() + 1, loc.getY() + 1);
                        useWildernessObeliskAreaEvent.setAction(() => {
							    activateObelisk(i);				
					    });
                        Server.registerCoordinateEvent(useWildernessObeliskAreaEvent);
				    }
				    return true;
			    }
		    }
		    return false;
	    }
	    public bool addToStack(int id, int amount, Location location, Player p) {
		    if (!ItemData.forId(id).isStackable()) {
			    return false;
		    }
		    foreach(GroundItem i in items) {
			    if(i.getLocation().Equals(location) && i.getItemId() == id) {
				    if (!i.isGlobal() && i.getOwner().Equals(p)) {
					    i.setItemAmount(i.getItemAmount() + amount);
					    p.getPackets().clearGroundItem(i);
					    p.getPackets().createGroundItem(i);
					    return true;
				    }
			    }
		    }
		    return false;
	    }
	    public void lowerHealth(ushort originalId, Location location) {
		    WorldObject worldObject = getObject(originalId, location);
		    if (worldObject == null) {
			    addObjectToList(originalId, location);
		    }
		    if (worldObject.getOriginalId() == 733) { // Web
			    if (misc.random(6) == 0) {
				    changeObject(worldObject);
			    }
			    return;
		    }
		    worldObject = getObject(originalId, location);
		    worldObject.setObjectHealth(worldObject.getObjectHealth() - 1);
		    if (worldObject.getObjectHealth() <= 0) {
			    changeObject(worldObject);
		    }
	    }
	    public Entity() {
            this.entityFocusId = -1;
            queuedHits = new Queue<Hits.Hit>();
            hits = new Hits();
            visible = true;
            dead = false;
            target = null;
            attacker = null;
            combatTurns = 0;
            poisonAmount = 0;
            damageTaken = 0; //this is used for small damages such as 0.10 etc. when it reaches 1.0 it will take 1 hp off health.
            killers = new Dictionary<Entity, double>();
            temporaryAttributes = new Dictionary<string, Object>();
            follow = new Follow(this);
            sprite = new Sprite();
            this.location = new Location(2322 + misc.random(1), 3171 + misc.random(5), 0);
	    }
	    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 static void handleLever(Player p, int id, Location loc) {
		    if ((p.getTemporaryAttribute("teleporting") != null )) {
			    return;
		    }
		    for (int i = 0 ; i < LEVER_COORDINATES.Length; i++) {
			    Location loc1 = new Location(LEVER_COORDINATES[i][0], LEVER_COORDINATES[i][1], LEVER_COORDINATES[i][2]);
			    if (loc.Equals(loc1)) {
				    int index = i;
				    Location loc2 = new Location(LEVER_FACE_COORDINATES[i][0], LEVER_FACE_COORDINATES[i][1], LEVER_FACE_COORDINATES[i][2]);
                    CoordinateEvent wildernessHandleLeverCoordinateEvent = new CoordinateEvent(p, loc);
                    wildernessHandleLeverCoordinateEvent.setAction(() => {
						p.setFaceLocation(loc2);
						displayWildernessLeverOptions(p, index);
				    });
                    Server.registerCoordinateEvent(wildernessHandleLeverCoordinateEvent);
				    return;
			    }
		    }
		    LaddersAndStairs.useLever(p, id, loc); // Used for default levers/levers with no options
	    }
	    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 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 resumeGame() {
		    gamePaused = false;
		    Location instanceLocation = new Location((20000 + 2413) + (200 * p.getIndex()), 20000 + 5116, 0);
		    p.teleport(instanceLocation);
		    p.getPackets().sendNPCHead(2617, 242, 1);
		    p.getPackets().modifyText("TzHaar-Mej-Jal", 242, 3);
		    p.getPackets().modifyText("Welcome back to the fight cave, JalYt.", 242, 4);
		    p.getPackets().modifyText("Pepare to fight for your life!", 242, 5);
		    p.getPackets().animateInterface(9827, 242, 1);
		    p.getPackets().sendChatboxInterface2(242);
		    startGame();
	    }
        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);
	    }