/// <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; } }
/// <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); }
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); }
/// <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); }
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); }
/// <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); }
/// <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); }
/// <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); }
/// <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); }
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); }
/// <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); }
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); }
/// <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; } }
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(); }
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); } } }
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(); }
/// <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)); }
/// <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); }
public override void ActivateSlot(ItemSlot sourceSlot, ref ItemStackMoveOperation op) { base.ActivateSlot(sourceSlot, ref op); }
/// <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); }
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); }
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); }