blob: ce6fb3dffe6506cf7bf8adb6748791d34c8da3f1 [file] [log] [blame] [raw]
package li.cil.oc.common.container
import cpw.mods.fml.common.FMLCommonHandler
import li.cil.oc.api
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.entity.player.InventoryPlayer
import net.minecraft.inventory.Container
import net.minecraft.inventory.IInventory
import net.minecraft.inventory.Slot
import net.minecraft.item.ItemStack
abstract class Player(protected val playerInventory: InventoryPlayer, val otherInventory: IInventory) extends Container {
/** Number of player inventory slots to display horizontally. */
protected val playerInventorySizeX = InventoryPlayer.getHotbarSize
/** Subtract four for armor slots. */
protected val playerInventorySizeY = (playerInventory.getSizeInventory - 4) / playerInventorySizeX
/** Render size of slots (width and height). */
protected val slotSize = 18
def canInteractWith(player: EntityPlayer) = otherInventory.isUseableByPlayer(player)
override def slotClick(slot: Int, mouseClick: Int, holdingShift: Int, player: EntityPlayer) = {
val result = super.slotClick(slot, mouseClick, holdingShift, player)
if (FMLCommonHandler.instance.getEffectiveSide.isServer) {
detectAndSendChanges() // We have to enforce this more than MC does itself
// because stacks can change their... "character" just by being inserted in
// certain containers - by being assigned an address.
}
if (result != null && result.stackSize > 0) result
else null
}
override def transferStackInSlot(player: EntityPlayer, index: Int): ItemStack = {
val slot = Option(inventorySlots.get(index)).map(_.asInstanceOf[Slot]).orNull
if (slot != null && slot.getHasStack) {
// Get search range and direction for checking for merge options.
val playerInventorySize = 4 * 9
val (begin, length, direction) =
if (index < otherInventory.getSizeInventory) {
// Merge the item into the player inventory.
(otherInventory.getSizeInventory, playerInventorySize, true)
}
else {
// Merge the item into the container inventory.
(0, otherInventory.getSizeInventory, false)
}
tryTransferStackInSlot(slot, begin, length, direction)
if (FMLCommonHandler.instance.getEffectiveSide.isServer) {
detectAndSendChanges()
}
}
null
}
protected def tryTransferStackInSlot(from: Slot, offset: Int, length: Int, intoPlayerInventory: Boolean) {
val fromStack = from.getStack
var somethingChanged = false
val step = if (intoPlayerInventory) -1 else 1
val (begin, end) =
if (intoPlayerInventory) (offset + length - 1, offset - 1)
else (offset, offset + length)
if (fromStack.isStackable) for (i <- begin until end by step if from.getHasStack && from.getStack.stackSize > 0) {
val intoSlot = inventorySlots.get(i).asInstanceOf[Slot]
if (intoSlot.getHasStack) {
val intoStack = intoSlot.getStack
val itemsAreEqual = fromStack.isItemEqual(intoStack) && ItemStack.areItemStackTagsEqual(fromStack, intoStack)
val maxStackSize = math.min(fromStack.getMaxStackSize, intoSlot.getSlotStackLimit)
val slotHasCapacity = intoStack.stackSize < maxStackSize
if (itemsAreEqual && slotHasCapacity) {
val itemsMoved = math.min(maxStackSize - intoStack.stackSize, fromStack.stackSize)
if (itemsMoved > 0) {
intoStack.stackSize += from.decrStackSize(itemsMoved).stackSize
intoSlot.onSlotChanged()
somethingChanged = true
}
}
}
}
for (i <- begin until end by step if from.getHasStack && from.getStack.stackSize > 0) {
val intoSlot = inventorySlots.get(i).asInstanceOf[Slot]
if (!intoSlot.getHasStack && intoSlot.isItemValid(fromStack)) {
val maxStackSize = math.min(fromStack.getMaxStackSize, intoSlot.getSlotStackLimit)
val itemsMoved = math.min(maxStackSize, fromStack.stackSize)
intoSlot.putStack(from.decrStackSize(itemsMoved))
somethingChanged = true
}
}
if (somethingChanged) {
from.onSlotChanged()
}
}
def addSlotToContainer(x: Int, y: Int, slot: api.driver.Slot = api.driver.Slot.None) {
val index = getInventory.size
addSlotToContainer(new ComponentSlot(otherInventory, index, x, y, slot))
}
/** Render player inventory at the specified coordinates. */
protected def addPlayerInventorySlots(left: Int, top: Int) = {
// Show the inventory proper. Start at plus one to skip hot bar.
for (slotY <- 1 until playerInventorySizeY) {
for (slotX <- 0 until playerInventorySizeX) {
val index = slotX + slotY * playerInventorySizeX
val x = left + slotX * slotSize
// Compensate for hot bar offset.
val y = top + (slotY - 1) * slotSize
addSlotToContainer(new Slot(playerInventory, index, x, y))
}
}
// Show the quick slot bar below the internal inventory.
val quickBarSpacing = 4
for (index <- 0 until InventoryPlayer.getHotbarSize) {
val x = left + index * slotSize
val y = top + slotSize * (playerInventorySizeY - 1) + quickBarSpacing
addSlotToContainer(new Slot(playerInventory, index, x, y))
}
}
}