public Creature GetDirectionalTarget(Xml.Direction direction) { VisibleObject obj; switch (direction) { case Xml.Direction.East: { obj = Map.EntityTree.FirstOrDefault(x => x.X == X + 1 && x.Y == Y && x is Creature); } break; case Xml.Direction.West: { obj = Map.EntityTree.FirstOrDefault(x => x.X == X - 1 && x.Y == Y && x is Creature); } break; case Xml.Direction.North: { obj = Map.EntityTree.FirstOrDefault(x => x.X == X && x.Y == Y - 1 && x is Creature); } break; case Xml.Direction.South: { obj = Map.EntityTree.FirstOrDefault(x => x.X == X && x.Y == Y + 1 && x is Creature); } break; default: throw new ArgumentOutOfRangeException(nameof(direction), direction, null); } if (obj is Creature) { return(obj as Creature); } return(null); }
public void AssailAttack(Xml.Direction direction, Creature target = null) { if (target == null) { var obj = GetDirectionalTarget(direction); var monster = obj as Monster; if (monster != null) { target = monster; } var user = obj as User; if (user != null) { target = user; } var npc = obj as Merchant; if (npc != null) { target = npc; } //try to get the creature we're facing and set it as the target. } // A monster's assail is just a straight attack, no skills involved. SimpleAttack(target); //animation handled here as to not repeatedly send assails. var assail = new ServerPacketStructures.PlayerAnimation() { Animation = 1, Speed = 20, UserId = this.Id }; //Enqueue(assail.Packet()); //Enqueue(sound.Packet()); SendAnimation(assail.Packet()); PlaySound(1); }
public virtual bool Walk(Xml.Direction direction) { lock (_lock) { int oldX = X, oldY = Y, newX = X, newY = Y; Rectangle arrivingViewport = Rectangle.Empty; Rectangle departingViewport = Rectangle.Empty; Rectangle commonViewport = Rectangle.Empty; var halfViewport = Constants.VIEWPORT_SIZE / 2; Warp targetWarp; switch (direction) { // Calculate the differences (which are, in all cases, rectangles of height 12 / width 1 or vice versa) // between the old and new viewpoints. The arrivingViewport represents the objects that need to be notified // of this object's arrival (because it is now within the viewport distance), and departingViewport represents // the reverse. We later use these rectangles to query the quadtree to locate the objects that need to be // notified of an update to their AOI (area of interest, which is the object's viewport calculated from its // current position). case Xml.Direction.North: --newY; arrivingViewport = new Rectangle(oldX - halfViewport, newY - halfViewport, Constants.VIEWPORT_SIZE, 1); departingViewport = new Rectangle(oldX - halfViewport, oldY + halfViewport, Constants.VIEWPORT_SIZE, 1); break; case Xml.Direction.South: ++newY; arrivingViewport = new Rectangle(oldX - halfViewport, oldY + halfViewport, Constants.VIEWPORT_SIZE, 1); departingViewport = new Rectangle(oldX - halfViewport, newY - halfViewport, Constants.VIEWPORT_SIZE, 1); break; case Xml.Direction.West: --newX; arrivingViewport = new Rectangle(newX - halfViewport, oldY - halfViewport, 1, Constants.VIEWPORT_SIZE); departingViewport = new Rectangle(oldX + halfViewport, oldY - halfViewport, 1, Constants.VIEWPORT_SIZE); break; case Xml.Direction.East: ++newX; arrivingViewport = new Rectangle(oldX + halfViewport, oldY - halfViewport, 1, Constants.VIEWPORT_SIZE); departingViewport = new Rectangle(oldX - halfViewport, oldY - halfViewport, 1, Constants.VIEWPORT_SIZE); break; } var isWarp = Map.Warps.TryGetValue(new Tuple <byte, byte>((byte)newX, (byte)newY), out targetWarp); // Now that we know where we are going, perform some sanity checks. // Is the player trying to walk into a wall, or off the map? if (newX >= Map.X || newY >= Map.Y || newX < 0 || newY < 0) { Refresh(); return(false); } if (Map.IsWall[newX, newY]) { Refresh(); return(false); } else { // Is the player trying to walk into an occupied tile? foreach (var obj in Map.GetTileContents((byte)newX, (byte)newY)) { GameLog.DebugFormat("Collsion check: found obj {0}", obj.Name); if (obj is Creature) { GameLog.DebugFormat("Walking prohibited: found {0}", obj.Name); Refresh(); return(false); } } // Is this user entering a forbidden (by level or otherwise) warp? if (isWarp) { if (targetWarp.MinimumLevel > Stats.Level) { Refresh(); return(false); } else if (targetWarp.MaximumLevel < Stats.Level) { Refresh(); return(false); } } } // Calculate the common viewport between the old and new position commonViewport = new Rectangle(oldX - halfViewport, oldY - halfViewport, Constants.VIEWPORT_SIZE, Constants.VIEWPORT_SIZE); commonViewport.Intersect(new Rectangle(newX - halfViewport, newY - halfViewport, Constants.VIEWPORT_SIZE, Constants.VIEWPORT_SIZE)); GameLog.DebugFormat("Moving from {0},{1} to {2},{3}", oldX, oldY, newX, newY); GameLog.DebugFormat("Arriving viewport is a rectangle starting at {0}, {1}", arrivingViewport.X, arrivingViewport.Y); GameLog.DebugFormat("Departing viewport is a rectangle starting at {0}, {1}", departingViewport.X, departingViewport.Y); GameLog.DebugFormat("Common viewport is a rectangle starting at {0}, {1} of size {2}, {3}", commonViewport.X, commonViewport.Y, commonViewport.Width, commonViewport.Height); X = (byte)newX; Y = (byte)newY; Direction = direction; // Objects in the common viewport receive a "walk" (0x0C) packet // Objects in the arriving viewport receive a "show to" (0x33) packet // Objects in the departing viewport receive a "remove object" (0x0E) packet foreach (var obj in Map.EntityTree.GetObjects(commonViewport)) { if (obj != this && obj is User) { var user = obj as User; GameLog.DebugFormat("Sending walk packet for {0} to {1}", Name, user.Name); var x0C = new ServerPacket(0x0C); x0C.WriteUInt32(Id); x0C.WriteUInt16((byte)oldX); x0C.WriteUInt16((byte)oldY); x0C.WriteByte((byte)direction); x0C.WriteByte(0x00); user.Enqueue(x0C); } } Map.EntityTree.Move(this); foreach (var obj in Map.EntityTree.GetObjects(arrivingViewport).Distinct()) { obj.AoiEntry(this); AoiEntry(obj); } foreach (var obj in Map.EntityTree.GetObjects(departingViewport).Distinct()) { obj.AoiDeparture(this); AoiDeparture(obj); } } HasMoved = true; return(true); }