Exemple #1
0
        private void MapToMapMovement(IOperationContext context, ITile sourceTile, ITile destinationTile, bool isTeleport)
        {
            var requestor = this.GetRequestor(context.CreatureManager);

            IThing thingMoving = this.ThingMovingId == CreatureConstants.CreatureTypeId ? sourceTile.TopCreature : sourceTile.TopItem;

            // Declare some pre-conditions.
            var sourceTileIsNull         = sourceTile == null;
            var destinationHasGround     = destinationTile?.Ground != null;
            var thingExists              = thingMoving != null;
            var locationsMatch           = thingMoving?.Location == this.FromLocation;
            var isIntendedThing          = this.ThingMovingId != CreatureConstants.CreatureTypeId ? thingMoving?.TypeId == this.ThingMovingId : (thingMoving as ICreature)?.Id == this.FromCreatureId;
            var requestorInRange         = requestor == null || (requestor.Location - this.FromLocation).MaxValueIn2D <= 1;
            var canThrowBetweenLocations = isTeleport || requestor == null || context.Map.CanThrowBetweenLocations(this.FromLocation, this.ToLocation, checkLineOfSight: true);

            if (sourceTileIsNull || !locationsMatch || !isIntendedThing)
            {
                // Silent fail.
                return;
            }
            else if (!thingExists)
            {
                this.DispatchTextNotification(context, OperationMessage.MayNotMoveThis);
            }
            else if (!destinationHasGround || !canThrowBetweenLocations)
            {
                this.DispatchTextNotification(context, OperationMessage.MayNotThrowThere);
            }
            else if (thingMoving is ICreature creature)
            {
                var distanceBetweenLocations = this.FromLocation - this.ToLocation;

                // More pre-conditions.
                var creatureCanBeMoved        = (thingMoving == requestor && requestor.CanWalk) || requestor.CanPush(creature);
                var canThrowThatFar           = isTeleport || requestor == null || (distanceBetweenLocations.MaxValueIn2D <= 1 && distanceBetweenLocations.Z == 0);
                var creatureAvoidsDestination = !isTeleport && requestor != null && requestor != creature && destinationTile.IsPathBlocking(/*this.Requestor.DamageTypesToAvoid*/);
                var destinationIsObstructed   = !isTeleport && distanceBetweenLocations.Z == 0 && (destinationTile.BlocksLay || destinationTile.BlocksPass);

                if (creatureAvoidsDestination)
                {
                    this.DispatchTextNotification(context, OperationMessage.NotEnoughRoom);
                }
                else if (destinationIsObstructed)
                {
                    if (requestor != null && creature.Id == this.RequestorId && creature is IPlayer player)
                    {
                        this.SendNotification(context, new PlayerCancelWalkNotification(player));
                    }

                    this.DispatchTextNotification(context, OperationMessage.NotEnoughRoom);
                }
                else if (!requestorInRange)
                {
                    this.DispatchTextNotification(context, OperationMessage.TooFarAway);
                }
                else if (!canThrowThatFar)
                {
                    this.DispatchTextNotification(context, OperationMessage.DestinationTooFarAway);
                }
                else if (!this.PerformCreatureMovement(context, creature, this.ToLocation, isTeleport, requestorCreature: requestor))
                {
                    // Something else went wrong.
                    this.DispatchTextNotification(context);
                }
                else if (requestor is IPlayer player && this.ToLocation != player.Location && player != thingMoving)
                {
                    var directionToDestination = player.Location.DirectionTo(this.ToLocation);

                    context.Scheduler.ScheduleEvent(new TurnToDirectionOperation(player, directionToDestination));
                }
            }
            else if (thingMoving is IItem item)
            {
                var distanceBetweenLocations = (requestor?.Location ?? this.FromLocation) - this.ToLocation;
                var distanceFromSource       = (requestor?.Location ?? this.FromLocation) - this.FromLocation;

                // More pre-conditions.
                var itemCanBeMoved = item.CanBeMoved;
                var sourceTileHasEnoughItemAmount = this.ThingMovingId == item.TypeId && item.Amount >= this.Amount;
                var destinationIsObstructed       = destinationTile.BlocksLay || (item.BlocksPass && destinationTile.BlocksPass);
                var movementInRange = requestor == null || (distanceFromSource.MaxValueIn2D <= 1 && distanceFromSource.Z == 0 && (!item.Type.HasItemFlag(ItemFlag.BlocksWalk) || (distanceBetweenLocations.MaxValueIn2D <= 2 && distanceBetweenLocations.Z == 0)));

                if (!itemCanBeMoved)
                {
                    this.DispatchTextNotification(context, OperationMessage.MayNotMoveThis);
                }
                else if (destinationIsObstructed)
                {
                    this.DispatchTextNotification(context, OperationMessage.MayNotThrowThere);
                }
                else if (!movementInRange)
                {
                    this.DispatchTextNotification(context, OperationMessage.DestinationTooFarAway);
                }
                else if (!sourceTileHasEnoughItemAmount)
                {
                    this.DispatchTextNotification(context, OperationMessage.NotEnoughQuantity);
                }
                else if (!this.PerformItemMovement(context, item, sourceTile, destinationTile, this.FromIndex, amountToMove: this.Amount, requestorCreature: requestor))
                {
                    // Something else went wrong.
                    this.DispatchTextNotification(context);
                }
                else if (requestor is IPlayer player && this.ToLocation != player.Location && player != thingMoving)
                {
                    var directionToDestination = player.Location.DirectionTo(this.ToLocation);

                    context.Scheduler.ScheduleEvent(new TurnToDirectionOperation(player, directionToDestination));
                }

                // TODO: Check if the item is an IContainerItem and, if it got moved, check if there are players that have it open that now are too far away from it.
            }
        }