예제 #1
0
        /// <summary>
        /// Called when a player has clicked on this slot.  The source slot is the mouse cursor slot.  This handles the logic of either taking, putting or exchanging items.
        /// </summary>
        /// <param name="sourceSlot"></param>
        /// <param name="op"></param>
        public virtual void ActivateSlot(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            if (Empty && sourceSlot.Empty)
            {
                return;
            }

            switch (op.MouseButton)
            {
            case EnumMouseButton.Left:
                ActivateSlotLeftClick(sourceSlot, ref op);
                return;

            case EnumMouseButton.Middle:
                ActivateSlotMiddleClick(sourceSlot, ref op);
                return;

            case EnumMouseButton.Right:
                ActivateSlotRightClick(sourceSlot, ref op);
                return;

            case EnumMouseButton.Wheel:
                if (op.WheelDir > 0)
                {
                    sourceSlot.TryPutInto(this, ref op);
                }
                else
                {
                    TryPutInto(sourceSlot, ref op);
                }
                return;
            }
        }
예제 #2
0
        /// <summary>
        /// Activates the right click functions of the given slot.
        /// </summary>
        /// <param name="sourceSlot"></param>
        /// <param name="op"></param>
        protected virtual void ActivateSlotRightClick(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            // 1. Current slot empty: Take 1 item
            if (Empty)
            {
                if (CanHold(sourceSlot))
                {
                    itemstack = (ItemStack)sourceSlot.TakeOut(1);
                    sourceSlot.OnItemSlotModified(itemstack);
                    OnItemSlotModified(itemstack);
                }
                return;
            }

            // 2. Current slot non empty, source slot empty: Put half items
            if (sourceSlot.Empty)
            {
                op.RequestedQuantity = (int)Math.Ceiling(itemstack.StackSize / 2f);
                TryPutInto(sourceSlot, ref op);
                return;
            }

            // 3. Both slots not empty, and they are stackable: Fill slot with 1 item
            op.RequestedQuantity = 1;
            sourceSlot.TryPutInto(this, ref op);
            if (op.MovedQuantity > 0)
            {
                return;
            }


            // 4. Both slots not empty and not stackable: Exchange items
            TryFlipWith(sourceSlot);
        }
예제 #3
0
        protected override void ActivateSlotMiddleClick(ItemSlot sinkSlot, ref ItemStackMoveOperation op)
        {
            if (Empty)
            {
                return;
            }

            sinkSlot.Itemstack           = Itemstack.Clone();
            sinkSlot.Itemstack.StackSize = Itemstack.Collectible.MaxStackSize;
            op.MovedQuantity             = Itemstack.Collectible.MaxStackSize;
            sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);
        }
예제 #4
0
        /// <summary>
        /// Returns the quantity of items that were not merged (left over in the source slot)
        /// </summary>
        /// <param name="sinkSlot"></param>
        /// <param name="op"></param>
        /// <returns>Amount of moved items</returns>
        public virtual int TryPutInto(ItemSlot sinkSlot, ref ItemStackMoveOperation op)
        {
            if (!sinkSlot.CanTakeFrom(this) || !CanTake() || itemstack == null)
            {
                return(0);
            }

            if (sinkSlot.inventory?.CanContain(sinkSlot, this) == false)
            {
                return(0);
            }


            // Fill the destination slot with as many items as we can
            if (sinkSlot.Itemstack == null)
            {
                int q = Math.Min(sinkSlot.GetRemainingSlotSpace(itemstack), op.RequestedQuantity);

                if (q > 0)
                {
                    sinkSlot.Itemstack = TakeOut(q);

                    // Has to be above the modified calls because e.g. when moving stuff into the ground slot this will eject the item
                    // onto the ground and sinkSlot.StackSize is 0 right after
                    op.MovedQuantity = op.MovableQuantity = Math.Min(sinkSlot.StackSize, q);

                    sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);
                    OnItemSlotModified(sinkSlot.Itemstack);
                }

                return(op.MovedQuantity);
            }

            ItemStackMergeOperation mergeop = op.ToMergeOperation(sinkSlot, this);

            op = mergeop;
            int origRequestedQuantity = op.RequestedQuantity;

            op.RequestedQuantity = Math.Min(sinkSlot.GetRemainingSlotSpace(itemstack), op.RequestedQuantity);

            sinkSlot.Itemstack.Collectible.TryMergeStacks(mergeop);

            if (mergeop.MovedQuantity > 0)
            {
                sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);
                OnItemSlotModified(sinkSlot.Itemstack);
            }

            op.RequestedQuantity = origRequestedQuantity; //ensures op.NotMovedQuantity will be correct in calling code if used with slots with limited slot maxStackSize, e.g. InventorySmelting with a cooking container has slots with maxStackSize == 6
            return(mergeop.MovedQuantity);
        }
예제 #5
0
        public override int TryPutInto(ItemSlot sinkSlot, ref ItemStackMoveOperation op)
        {
            if (!sinkSlot.CanTakeFrom(this) || !CanTake() || Itemstack == null)
            {
                return(0);
            }

            // Fill up sink slot
            if (op.ShiftDown)
            {
                if (Empty)
                {
                    return(0);
                }

                int maxstacksize = Itemstack.Collectible.MaxStackSize;

                if (sinkSlot.Itemstack == null)
                {
                    op.RequestedQuantity = maxstacksize;
                }
                else
                {
                    op.RequestedQuantity = maxstacksize - sinkSlot.StackSize;
                }
            }

            // Fill the destination slot with as many items as we can
            if (sinkSlot.Itemstack == null)
            {
                sinkSlot.Itemstack = TakeOut(op.RequestedQuantity);
                sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);
                op.MovedQuantity = sinkSlot.StackSize;
                return(op.MovedQuantity);
            }

            ItemStack ownStack = Itemstack.Clone();

            ItemStackMergeOperation mergeop = op.ToMergeOperation(sinkSlot, this);

            op = mergeop;

            sinkSlot.Itemstack.Collectible.TryMergeStacks(mergeop);

            // Ignore any changes made to our slot
            Itemstack = ownStack;

            sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);

            return(op.MovedQuantity);
        }
예제 #6
0
        /// <summary>
        /// Activates the left click functions of the given slot.
        /// </summary>
        /// <param name="sourceSlot"></param>
        /// <param name="op"></param>
        protected virtual void ActivateSlotLeftClick(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            // 1. Current slot empty: Take items
            if (Empty)
            {
                if (!CanHold(sourceSlot))
                {
                    return;
                }

                int q = Math.Min(sourceSlot.StackSize, MaxSlotStackSize);
                q = Math.Min(q, GetRemainingSlotSpace(sourceSlot.itemstack));

                itemstack        = sourceSlot.TakeOut(q);
                op.MovedQuantity = itemstack.StackSize;
                OnItemSlotModified(itemstack);
                return;
            }

            // 2. Current slot non empty, source slot empty: Put items
            if (sourceSlot.Empty)
            {
                op.RequestedQuantity = StackSize;
                TryPutInto(sourceSlot, ref op);
                return;
            }

            // 3. Both slots not empty, and they are stackable: Fill slot
            int maxq = itemstack.Collectible.GetMergableQuantity(itemstack, sourceSlot.itemstack, op.CurrentPriority);

            if (maxq > 0)
            {
                int origRequestedQuantity = op.RequestedQuantity;
                op.RequestedQuantity = GameMath.Min(maxq, sourceSlot.itemstack.StackSize, GetRemainingSlotSpace(sourceSlot.itemstack));

                ItemStackMergeOperation mergeop = op.ToMergeOperation(this, sourceSlot);
                op = mergeop;

                itemstack.Collectible.TryMergeStacks(mergeop);

                sourceSlot.OnItemSlotModified(itemstack);
                OnItemSlotModified(itemstack);

                op.RequestedQuantity = origRequestedQuantity; //ensures op.NotMovedQuantity will be correct in calling code if used with slots with limited slot maxStackSize, e.g. InventorySmelting with a cooking container has slots with maxStackSize == 6
                return;
            }

            // 4. Both slots not empty and not stackable: Exchange items
            TryFlipWith(sourceSlot);
        }
예제 #7
0
        /// <summary>
        /// Activates the middle click functions of the given slot.
        /// </summary>
        /// <param name="sinkSlot"></param>
        /// <param name="op"></param>
        protected virtual void ActivateSlotMiddleClick(ItemSlot sinkSlot, ref ItemStackMoveOperation op)
        {
            if (Empty)
            {
                return;
            }

            if (op.ActingPlayer?.WorldData?.CurrentGameMode == EnumGameMode.Creative)
            {
                sinkSlot.Itemstack = Itemstack.Clone();
                op.MovedQuantity   = Itemstack.StackSize;
                sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);
            }
        }
        protected override void ActivateSlotRightClick(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            ItemSlotLiquidOnly liquidSlot = inventory[1] as ItemSlotLiquidOnly;
            IWorldAccessor     world      = inventory.Api.World;

            if (sourceSlot?.Itemstack?.Collectible is ILiquidSink sink && !liquidSlot.Empty && sink.AllowHeldLiquidTransfer)
            {
                ItemStack liqSlotStack         = liquidSlot.Itemstack;
                var       curTargetLiquidStack = sink.GetContent(sourceSlot.Itemstack);

                bool liquidstackable = curTargetLiquidStack == null || liqSlotStack.Equals(world, curTargetLiquidStack, GlobalConstants.IgnoredStackAttributes);

                if (liquidstackable)
                {
                    var lprops = BlockLiquidContainerBase.GetContainableProps(liqSlotStack);

                    float curSourceLitres = liqSlotStack.StackSize / lprops.ItemsPerLitre;
                    float curTargetLitres = sink.GetCurrentLitres(sourceSlot.Itemstack);

                    float toMoveLitres = op.CtrlDown ? sink.TransferSizeLitres : (sink.CapacityLitres - curTargetLitres);

                    toMoveLitres *= sourceSlot.StackSize;
                    toMoveLitres  = Math.Min(curSourceLitres, toMoveLitres);

                    if (toMoveLitres > 0)
                    {
                        op.MovedQuantity = sink.TryPutLiquid(sourceSlot.Itemstack, liqSlotStack, toMoveLitres / sourceSlot.StackSize);

                        liquidSlot.Itemstack.StackSize -= op.MovedQuantity * sourceSlot.StackSize;
                        if (liquidSlot.Itemstack.StackSize <= 0)
                        {
                            liquidSlot.Itemstack = null;
                        }
                        liquidSlot.MarkDirty();
                        sourceSlot.MarkDirty();

                        var pos = op.ActingPlayer?.Entity?.Pos;
                        if (pos != null)
                        {
                            op.World.PlaySoundAt(lprops.PourSound, pos.X, pos.Y, pos.Z);
                        }
                    }
                }

                return;
            }

            base.ActivateSlotRightClick(sourceSlot, ref op);
        }
예제 #9
0
        /// <summary>
        /// Call when a player has clicked on this slot. The source slot is the mouse cursor slot. This handles the logic of either taking, putting or exchanging items.
        /// </summary>
        /// <param name="slotId"></param>
        /// <param name="sourceSlot"></param>
        /// <param name="op"></param>
        /// <returns>The appropriate packet needed to reflect the changes on the opposing side</returns>
        public virtual object ActivateSlot(int slotId, ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            object packet = InvNetworkUtil.GetActivateSlotPacket(slotId, op);

            if (op.ShiftDown)
            {
                sourceSlot           = this[slotId];
                op.RequestedQuantity = sourceSlot.StackSize;
                op.ActingPlayer.InventoryManager.TryTransferAway(sourceSlot, ref op, false);
            }
            else
            {
                this[slotId].ActivateSlot(sourceSlot, ref op);
            }

            return(packet);
        }
예제 #10
0
        /// <summary>
        /// Activates the left click functions of the given slot.
        /// </summary>
        /// <param name="sourceSlot"></param>
        /// <param name="op"></param>
        protected virtual void ActivateSlotLeftClick(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            // 1. Current slot empty: Take items
            if (Empty)
            {
                if (!CanHold(sourceSlot))
                {
                    return;
                }

                itemstack        = sourceSlot.TakeOut(Math.Min(sourceSlot.StackSize, MaxSlotStackSize));
                op.MovedQuantity = itemstack.StackSize;
                OnItemSlotModified(itemstack);
                return;
            }

            // 2. Current slot non empty, source slot empty: Put items
            if (sourceSlot.Empty)
            {
                op.RequestedQuantity = StackSize;
                TryPutInto(sourceSlot, ref op);
                return;
            }

            // 3. Both slots not empty, and they are stackable: Fill slot
            int maxq = itemstack.Collectible.GetMergableQuantity(itemstack, sourceSlot.itemstack, op.CurrentPriority);

            if (maxq > 0)
            {
                op.RequestedQuantity = GameMath.Min(maxq, sourceSlot.itemstack.StackSize, RemainingSlotSpace);

                ItemStackMergeOperation mergeop = op.ToMergeOperation(this, sourceSlot);
                op = mergeop;

                itemstack.Collectible.TryMergeStacks(mergeop);

                sourceSlot.OnItemSlotModified(itemstack);
                OnItemSlotModified(itemstack);

                return;
            }

            // 4. Both slots not empty and not stackable: Exchange items
            TryFlipWith(sourceSlot);
        }
예제 #11
0
        protected override void ActivateSlotRightClick(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            // 1. Current slot empty: Take 1 item
            if (Empty)
            {
                return;
            }

            // 2. Current slot non empty, source slot empty: Put half items
            if (sourceSlot.Empty)
            {
                op.RequestedQuantity = 1;
                sourceSlot.TryPutInto(this, ref op);
                return;
            }

            // 3. Both slots not empty, and they are stackable: Fill slot with 1 item
            sourceSlot.TakeOut(1);
        }
예제 #12
0
        /// <summary>
        /// Returns the quantity of items that were not merged (left over in the source slot)
        /// </summary>
        /// <param name="sinkSlot"></param>
        /// <param name="op"></param>
        /// <returns>Amount of moved items</returns>
        public virtual int TryPutInto(ItemSlot sinkSlot, ref ItemStackMoveOperation op)
        {
            if (!sinkSlot.CanTakeFrom(this) || !CanTake() || itemstack == null)
            {
                return(0);
            }


            // Fill the destination slot with as many items as we can
            if (sinkSlot.Itemstack == null)
            {
                int q = Math.Min(sinkSlot.RemainingSlotSpace, op.RequestedQuantity);

                if (q > 0)
                {
                    sinkSlot.Itemstack = TakeOut(q);

                    // Has to be above the modified calls because e.g. when moving stuff into the ground slot this will eject the item
                    // onto the ground and sinkSlot.StackSize is 0 right after
                    op.MovedQuantity = op.MovableQuantity = Math.Min(sinkSlot.StackSize, q);

                    sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);
                    OnItemSlotModified(sinkSlot.Itemstack);
                }

                return(op.MovedQuantity);
            }

            ItemStackMergeOperation mergeop = op.ToMergeOperation(sinkSlot, this);

            op = mergeop;
            op.RequestedQuantity = Math.Min(sinkSlot.RemainingSlotSpace, op.RequestedQuantity);

            sinkSlot.Itemstack.Collectible.TryMergeStacks(mergeop);

            if (mergeop.MovedQuantity > 0)
            {
                sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);
                OnItemSlotModified(sinkSlot.Itemstack);
            }

            return(mergeop.MovedQuantity);
        }
예제 #13
0
        public override bool TryGiveItemStack(ItemStack itemstack)
        {
            if (itemstack == null || itemstack.StackSize == 0)
            {
                return(false);
            }

            ItemSlot dummySlot = new DummySlot(null);

            dummySlot.Itemstack = itemstack.Clone();

            ItemStackMoveOperation op = new ItemStackMoveOperation(World, EnumMouseButton.Left, 0, EnumMergePriority.AutoMerge, itemstack.StackSize);

            if (GearInventory != null)
            {
                WeightedSlot wslot = GearInventory.GetBestSuitedSlot(dummySlot, new List <ItemSlot>());
                if (wslot.weight > 0)
                {
                    dummySlot.TryPutInto(wslot.slot, ref op);
                    itemstack.StackSize -= op.MovedQuantity;
                    WatchedAttributes.MarkAllDirty();
                    return(op.MovedQuantity > 0);
                }
            }

            if (LeftHandItemSlot?.Inventory != null)
            {
                WeightedSlot wslot = LeftHandItemSlot.Inventory.GetBestSuitedSlot(dummySlot, new List <ItemSlot>());
                if (wslot.weight > 0)
                {
                    dummySlot.TryPutInto(wslot.slot, ref op);
                    itemstack.StackSize -= op.MovedQuantity;
                    WatchedAttributes.MarkAllDirty();
                    return(op.MovedQuantity > 0);
                }
            }

            return(false);
        }
예제 #14
0
        /// <summary>
        /// Called when a player has clicked on this slot.  The source slot is the mouse cursor slot.  This handles the logic of either taking, putting or exchanging items.
        /// </summary>
        /// <param name="sourceSlot"></param>
        /// <param name="op"></param>
        public virtual void ActivateSlot(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            if (Empty && sourceSlot.Empty)
            {
                return;
            }

            switch (op.MouseButton)
            {
            case EnumMouseButton.Left:
                ActivateSlotLeftClick(sourceSlot, ref op);
                return;

            case EnumMouseButton.Middle:
                ActivateSlotMiddleClick(sourceSlot, ref op);
                return;

            case EnumMouseButton.Right:
                ActivateSlotRightClick(sourceSlot, ref op);
                return;
            }
        }
예제 #15
0
        protected override void ActivateSlotLeftClick(ItemSlot sinkSlot, ref ItemStackMoveOperation op)
        {
            // 1. Current slot empty: Remove items
            if (Empty)
            {
                sinkSlot.TakeOutWhole();
                return;
            }

            // 2. Current slot non empty, source slot empty: Put items
            if (sinkSlot.Empty)
            {
                op.RequestedQuantity = StackSize;
                TryPutInto(sinkSlot, ref op);
                return;
            }

            // 3. Both slots not empty, and they are stackable: Fill source slot
            int maxq = Itemstack.Collectible.GetMergableQuantity(sinkSlot.Itemstack, Itemstack, op.CurrentPriority);

            if (maxq > 0)
            {
                op.RequestedQuantity = 1;
                ItemStackMergeOperation mergeop = op.ToMergeOperation(sinkSlot, this);
                op = mergeop;

                ItemStack ownStack = Itemstack.Clone();

                sinkSlot.Itemstack.Collectible.TryMergeStacks(mergeop);

                // Ignore any changes made to our slot
                Itemstack = ownStack;

                return;
            }

            // 4. Both slots not empty and not stackable: Remove items
            sinkSlot.TakeOutWhole();
        }
예제 #16
0
        public override void ActivateSlot(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            if (Empty)
            {
                return;
            }
            if (sourceSlot.CanHold(this))
            {
                if (sourceSlot.Itemstack != null && sourceSlot.Itemstack != null && sourceSlot.Itemstack.Collectible.GetMergableQuantity(sourceSlot.Itemstack, itemstack, op.CurrentPriority) < itemstack.StackSize)
                {
                    return;
                }

                op.RequestedQuantity = StackSize;

                TryPutInto(sourceSlot, ref op);

                if (op.MovedQuantity > 0)
                {
                    OnItemSlotModified(itemstack);
                }
            }
        }
예제 #17
0
        protected override void ActivateSlotLeftClick(ItemSlot sinkSlot, ref ItemStackMoveOperation op)
        {
            // 1. Current slot empty: Remove items
            if (Empty)
            {
                sinkSlot.TakeOutWhole();
                return;
            }

            // 2. Current slot non empty, source slot empty: Put items
            if (sinkSlot.Empty)
            {
                op.RequestedQuantity = StackSize;
                TryPutInto(sinkSlot, ref op);
                return;
            }

            // 3. Both slots not empty, and they are the same: Fill source slot
            if (sinkSlot.Itemstack.Equals(op.World, Itemstack, GlobalConstants.IgnoredStackAttributes))
            {
                op.RequestedQuantity = 1;
                ItemStackMergeOperation mergeop = op.ToMergeOperation(sinkSlot, this);
                op = mergeop;

                ItemStack ownStack = Itemstack.Clone();

                sinkSlot.Itemstack.Collectible.TryMergeStacks(mergeop);

                // Ignore any changes made to our slot
                Itemstack = ownStack;

                return;
            }

            // 4. Both slots not empty and not stackable: Remove items
            sinkSlot.TakeOutWhole();
        }
예제 #18
0
        /// <summary>
        /// Call when a player has clicked on this slot. The source slot is the mouse cursor slot. This handles the logic of either taking, putting or exchanging items.
        /// </summary>
        /// <param name="slotId"></param>
        /// <param name="sourceSlot"></param>
        /// <param name="op"></param>
        /// <returns>The appropriate packet needed to reflect the changes on the opposing side</returns>
        public virtual object ActivateSlot(int slotId, ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            object packet = InvNetworkUtil.GetActivateSlotPacket(slotId, op);

            if (op.ShiftDown)
            {
                sourceSlot = this[slotId];
                string stackName = sourceSlot.Itemstack?.GetName();
                string sourceInv = sourceSlot.Inventory?.InventoryID;

                StringBuilder shiftClickDebugText = new StringBuilder();

                op.RequestedQuantity = sourceSlot.StackSize;
                op.ActingPlayer.InventoryManager.TryTransferAway(sourceSlot, ref op, false, shiftClickDebugText);

                Api.World.Logger.Audit("{0} shift clicked slot {1} in {2}. Moved {3}x{4} to ({5})", op.ActingPlayer?.PlayerName, slotId, sourceInv, op.MovedQuantity, stackName, shiftClickDebugText.ToString());
            }
            else
            {
                this[slotId].ActivateSlot(sourceSlot, ref op);
            }

            return(packet);
        }
 public override int TryPutInto(ItemSlot sinkSlot, ref ItemStackMoveOperation op)
 {
     return(base.TryPutInto(sinkSlot, ref op));
 }
예제 #20
0
        /// <summary>
        /// Attempts to move the item stack from the inventory to another slot.
        /// </summary>
        /// <param name="player">The player moving the items</param>
        /// <param name="invIds">The player inventory IDs</param>
        /// <param name="slotIds">The target Ids</param>
        /// <param name="op">The operation type.</param>
        public virtual bool TryMoveItemStack(IPlayer player, string[] invIds, int[] slotIds, ref ItemStackMoveOperation op)
        {
            // 0 = source slot
            // 1 = target slot
            ItemSlot[] slots = GetSlotsIfExists(player, invIds, slotIds);

            if (slots[0] == null || slots[1] == null)
            {
                return(false);
            }

            // 4. Try to move the item stack
            slots[0].TryPutInto(slots[1], ref op);

            return(op.MovedQuantity == op.RequestedQuantity);
        }
예제 #21
0
 public override void ActivateSlot(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
 {
     base.ActivateSlot(sourceSlot, ref op);
 }
예제 #22
0
        /// <summary>
        /// Attempts to place item in this slot into the target slot.
        /// </summary>
        /// <param name="world"></param>
        /// <param name="sinkSlot"></param>
        /// <param name="quantity"></param>
        /// <returns>Amount of moved items</returns>
        public virtual int TryPutInto(IWorldAccessor world, ItemSlot sinkSlot, int quantity = 1)
        {
            ItemStackMoveOperation op = new ItemStackMoveOperation(world, EnumMouseButton.Left, 0, EnumMergePriority.AutoMerge, quantity);

            return(TryPutInto(sinkSlot, ref op));
        }
        protected override void ActivateSlotLeftClick(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            if (sourceSlot.Empty)
            {
                base.ActivateSlotLeftClick(sourceSlot, ref op);
                return;
            }

            IWorldAccessor world = inventory.Api.World;

            if (sourceSlot.Itemstack.Collectible is ILiquidSource source && source.AllowHeldLiquidTransfer)
            {
                ItemSlotLiquidOnly liquidSlot = inventory[1] as ItemSlotLiquidOnly;

                ItemStack bucketContents = source.GetContent(sourceSlot.Itemstack);
                bool      stackable      = !liquidSlot.Empty && liquidSlot.Itemstack.Equals(world, bucketContents, GlobalConstants.IgnoredStackAttributes);

                if ((liquidSlot.Empty || stackable) && bucketContents != null)
                {
                    ItemStack bucketStack = sourceSlot.Itemstack;

                    var lprops = BlockLiquidContainerBase.GetContainableProps(bucketContents);

                    float toMoveLitres    = op.CtrlDown ? source.TransferSizeLitres : source.CapacityLitres;
                    float curSourceLitres = bucketContents.StackSize / lprops.ItemsPerLitre * bucketStack.StackSize;
                    float curDestLitres   = liquidSlot.StackSize / lprops.ItemsPerLitre;

                    // Cap by source amount
                    toMoveLitres = Math.Min(toMoveLitres, curSourceLitres);
                    // Cap by target capacity
                    toMoveLitres = Math.Min(toMoveLitres, liquidSlot.CapacityLitres - curDestLitres);

                    if (toMoveLitres > 0)
                    {
                        int       moveQuantity      = (int)(toMoveLitres * lprops.ItemsPerLitre);
                        ItemStack takenContentStack = source.TryTakeContent(bucketStack, moveQuantity / bucketStack.StackSize);

                        takenContentStack.StackSize *= bucketStack.StackSize;
                        takenContentStack.StackSize += liquidSlot.StackSize;

                        liquidSlot.Itemstack = takenContentStack;
                        liquidSlot.MarkDirty();
                        op.MovedQuantity = moveQuantity;

                        var pos = op.ActingPlayer?.Entity?.Pos;
                        if (pos != null)
                        {
                            op.World.PlaySoundAt(lprops.FillSound, pos.X, pos.Y, pos.Z);
                        }
                    }

                    return;
                }

                return;
            }



            string contentItemCode = sourceSlot.Itemstack?.ItemAttributes?["contentItemCode"].AsString();

            if (contentItemCode != null)
            {
                ItemSlot liquidSlot = inventory[1];

                ItemStack contentStack = new ItemStack(world.GetItem(new AssetLocation(contentItemCode)));
                bool      stackable    = !liquidSlot.Empty && liquidSlot.Itemstack.Equals(world, contentStack, GlobalConstants.IgnoredStackAttributes);

                if ((liquidSlot.Empty || stackable) && contentStack != null)
                {
                    if (stackable)
                    {
                        liquidSlot.Itemstack.StackSize++;
                    }
                    else
                    {
                        liquidSlot.Itemstack = contentStack;
                    }

                    liquidSlot.MarkDirty();

                    ItemStack bowlStack = new ItemStack(world.GetBlock(new AssetLocation(sourceSlot.Itemstack.ItemAttributes["emptiedBlockCode"].AsString())));
                    if (sourceSlot.StackSize == 1)
                    {
                        sourceSlot.Itemstack = bowlStack;
                    }
                    else
                    {
                        sourceSlot.Itemstack.StackSize--;
                        if (!op.ActingPlayer.InventoryManager.TryGiveItemstack(bowlStack))
                        {
                            world.SpawnItemEntity(bowlStack, op.ActingPlayer.Entity.Pos.XYZ);
                        }
                    }
                    sourceSlot.MarkDirty();
                }

                return;
            }

            base.ActivateSlotLeftClick(sourceSlot, ref op);
        }
예제 #24
0
        protected override void ActivateSlotLeftClick(ItemSlot sourceSlot, ref ItemStackMoveOperation op)
        {
            if (sourceSlot.Empty)
            {
                base.ActivateSlotLeftClick(sourceSlot, ref op);
                return;
            }

            IWorldAccessor world = inventory.Api.World;

            if (sourceSlot.Itemstack.Collectible is ILiquidSource)
            {
                ItemSlot      liquidSlot = inventory[1];
                ILiquidSource source     = sourceSlot.Itemstack.Collectible as ILiquidSource;

                ItemStack bucketContents = source.GetContent(world, sourceSlot.Itemstack);
                bool      stackable      = !liquidSlot.Empty && liquidSlot.Itemstack.Equals(world, bucketContents, GlobalConstants.IgnoredStackAttributes);

                if ((liquidSlot.Empty || stackable) && bucketContents != null)
                {
                    ItemStack bucketStack  = sourceSlot.Itemstack;
                    ItemStack takenContent = source.TryTakeContent(world, bucketStack, 1);
                    sourceSlot.Itemstack    = bucketStack;
                    takenContent.StackSize += liquidSlot.StackSize;
                    liquidSlot.Itemstack    = takenContent;
                    liquidSlot.MarkDirty();

                    op.MovedQuantity = 1;

                    return;
                }

                return;
            }



            string contentItemCode = sourceSlot.Itemstack?.ItemAttributes?["contentItemCode"].AsString();

            if (contentItemCode != null)
            {
                ItemSlot liquidSlot = inventory[1];

                ItemStack contentStack = new ItemStack(world.GetItem(new AssetLocation(contentItemCode)));
                bool      stackable    = !liquidSlot.Empty && liquidSlot.Itemstack.Equals(world, contentStack, GlobalConstants.IgnoredStackAttributes);

                if ((liquidSlot.Empty || stackable) && contentStack != null)
                {
                    if (stackable)
                    {
                        liquidSlot.Itemstack.StackSize++;
                    }
                    else
                    {
                        liquidSlot.Itemstack = contentStack;
                    }

                    liquidSlot.MarkDirty();

                    ItemStack bowlStack = new ItemStack(world.GetBlock(new AssetLocation(sourceSlot.Itemstack.ItemAttributes["emptiedBlockCode"].AsString())));
                    if (sourceSlot.StackSize == 1)
                    {
                        sourceSlot.Itemstack = bowlStack;
                    }
                    else
                    {
                        sourceSlot.Itemstack.StackSize--;
                        if (!op.ActingPlayer.InventoryManager.TryGiveItemstack(bowlStack))
                        {
                            world.SpawnItemEntity(bowlStack, op.ActingPlayer.Entity.Pos.XYZ);
                        }
                    }
                    sourceSlot.MarkDirty();
                }

                return;
            }

            base.ActivateSlotLeftClick(sourceSlot, ref op);
        }
예제 #25
0
        public override int TryPutInto(ItemSlot sinkSlot, ref ItemStackMoveOperation op)
        {
            if (!sinkSlot.CanTakeFrom(this) || !CanTake() || Itemstack == null)
            {
                return(0);
            }

            if (sinkSlot.Inventory?.CanContain(sinkSlot, this) == false)
            {
                return(0);
            }

            // Fill up sink slot
            if (op.ShiftDown)
            {
                if (Empty)
                {
                    return(0);
                }

                int maxstacksize = Itemstack.Collectible.MaxStackSize;

                if (sinkSlot.Itemstack == null)
                {
                    op.RequestedQuantity = maxstacksize;
                }
                else
                {
                    op.RequestedQuantity = maxstacksize - sinkSlot.StackSize;
                }
            }

            // Fill the destination slot with as many items as we can
            if (sinkSlot.Itemstack == null)
            {
                int q = Math.Min(sinkSlot.GetRemainingSlotSpace(itemstack), op.RequestedQuantity);

                sinkSlot.Itemstack = TakeOut(q);
                sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);
                op.MovedQuantity = sinkSlot.StackSize;
                return(op.MovedQuantity);
            }

            ItemStack ownStack = Itemstack.Clone();

            ItemStackMergeOperation mergeop = op.ToMergeOperation(sinkSlot, this);

            op = mergeop;
            int origRequestedQuantity = op.RequestedQuantity;

            op.RequestedQuantity = Math.Min(sinkSlot.GetRemainingSlotSpace(itemstack), op.RequestedQuantity);

            sinkSlot.Itemstack.Collectible.TryMergeStacks(mergeop);

            // Ignore any changes made to our slot
            Itemstack = ownStack;

            if (mergeop.MovedQuantity > 0)
            {
                sinkSlot.OnItemSlotModified(sinkSlot.Itemstack);
            }

            op.RequestedQuantity = origRequestedQuantity; //ensures op.NotMovedQuantity will be correct in calling code if used with slots with limited slot maxStackSize, e.g. InventorySmelting with a cooking container has slots with maxStackSize == 6
            return(op.MovedQuantity);
        }