Exemplo n.º 1
0
        /// <summary>
        /// Immediately attempts to perform an item movement between two containers.
        /// </summary>
        /// <param name="context">A reference to the operation context.</param>
        /// <param name="item">The item being moved.</param>
        /// <param name="fromContainer">The container from which the movement is being performed.</param>
        /// <param name="toContainer">The container to which the movement is being performed.</param>
        /// <param name="fromIndex">Optional. The index within the container to move the item from.</param>
        /// <param name="toIndex">Optional. The index within the container to move the item to.</param>
        /// <param name="amountToMove">Optional. The amount of the thing to move. Defaults to 1.</param>
        /// <param name="requestorCreature">Optional. The creature that this movement is being performed in behalf of, if any.</param>
        /// <returns>True if the movement was successfully performed, false otherwise.</returns>
        /// <remarks>Changes game state, should only be performed after all pertinent validations happen.</remarks>
        private bool PerformItemMovement(IOperationContext context, IItem item, IItemsContainer fromContainer, IItemsContainer toContainer, byte fromIndex = byte.MaxValue, byte toIndex = byte.MaxValue, byte amountToMove = 1, ICreature requestorCreature = null)
        {
            const byte FallbackIndex = byte.MaxValue;

            if (item == null || fromContainer == null || toContainer == null)
            {
                return(false);
            }

            var sameContainer = fromContainer == toContainer;

            if (sameContainer && fromIndex == toIndex)
            {
                // no change at all.
                return(true);
            }

            // Edge case, check if the moving item is the target container.
            if (item is IContainerItem containerItem && toContainer is IContainerItem targetContainer && targetContainer.IsDescendantOf(containerItem))
            {
                return(false);
            }

            (bool removeSuccessful, IThing removeRemainder) = fromContainer.RemoveItem(context.ItemFactory, ref item, amountToMove, fromIndex);

            if (!removeSuccessful)
            {
                // Failing to remove the item from the original container stops the entire operation.
                return(false);
            }

            if (fromContainer is ITile fromTile)
            {
                this.SendNotification(context, new TileUpdatedNotification(context.Map.FindPlayersThatCanSee(fromTile.Location), fromTile));
            }

            /* context.EventRulesApi.EvaluateRules(this, EventRuleType.Separation, new SeparationEventRuleArguments(fromThingContainer.Location, item, requestorCreature)); */

            IItem remainder = item;

            if (sameContainer && removeRemainder == null && fromIndex < toIndex)
            {
                // If the move happens within the same container, we need to adjust the index of where we're adding, depending if it is before or after.
                toIndex--;
            }

            if (!toContainer.AddItemToContainerRecursively(context.ItemFactory, ref remainder, toIndex, includeTileAsFallback: false) || remainder != null)
            {
                // There is some rollback to do, as we failed to add the entire thing.
                IItem rollbackRemainder = remainder ?? item;

                if (!fromContainer.AddItemToContainerRecursively(context.ItemFactory, ref rollbackRemainder, FallbackIndex, includeTileAsFallback: true))
                {
                    context.Logger.LogError($"Rollback failed on {nameof(this.PerformItemMovement)}. Thing: {rollbackRemainder.DescribeForLogger()}");
                }
            }

            return(true);
        }