try exact trade first before item type only check

again closes #2788
This commit is contained in:
payonel 2018-09-23 21:14:52 -07:00
parent 89eeae875b
commit c57dc9ae48

View File

@ -10,6 +10,7 @@ import li.cil.oc.common.EventHandler
import li.cil.oc.util.InventoryUtils
import net.minecraft.entity.Entity
import net.minecraft.entity.IMerchant
import net.minecraft.inventory.IInventory
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.TileEntity
@ -70,39 +71,16 @@ class Trade(val info: TradeInfo) extends AbstractValue {
if (recipe.isRecipeDisabled) {
result(false, "trade is disabled")
} else {
// Now we'll check if we have enough items to perform the trade, caching first
val firstInputStack = recipe.getItemToBuy
val secondInputStack = if (recipe.hasSecondItemToBuy) Option(recipe.getSecondItemToBuy) else None
def containsAccumulativeItemStack(stack: ItemStack) =
InventoryUtils.extractFromInventory(stack, inventory, ForgeDirection.UNKNOWN, simulate = true, exact = false).stackSize == 0
def hasRoomForItemStack(stack: ItemStack) = {
val remainder = stack.copy()
InventoryUtils.insertIntoInventory(remainder, inventory, None, remainder.stackSize, simulate = true)
remainder.stackSize == 0
}
// Check if we have enough to perform the trade.
if (containsAccumulativeItemStack(firstInputStack) && secondInputStack.forall(containsAccumulativeItemStack)) {
// Now we need to check if we have enough inventory space to accept the item we get for the trade.
val outputStack = recipe.getItemToSell.copy()
if (hasRoomForItemStack(outputStack)) {
// We established that out inventory allows to perform the trade, now actually do the trade.
InventoryUtils.extractFromInventory(firstInputStack, inventory, ForgeDirection.UNKNOWN, exact = false)
secondInputStack.map(InventoryUtils.extractFromInventory(_, inventory, ForgeDirection.UNKNOWN, exact = false))
InventoryUtils.insertIntoInventory(outputStack, inventory, None, outputStack.stackSize)
// Tell the merchant we used the recipe, so MC can disable it and/or enable more recipes.
info.merchant.get.orNull.useRecipe(recipe)
if (!hasRoomForRecipe(inventory, recipe)) {
result(false, "not enough inventory space to trade")
} else {
if (completeTrade(inventory, recipe, exact = true) || completeTrade(inventory, recipe, exact = false)) {
result(true)
} else {
result(false, "not enough inventory space to trade")
}
} else {
result(false, "not enough items to trade")
}
}
}
case _ => result(false, "trade has become invalid")
}
}
@ -111,6 +89,37 @@ class Trade(val info: TradeInfo) extends AbstractValue {
case _ => result(false, "trading requires an inventory upgrade to be installed")
}
}
def hasRoomForRecipe(inventory: IInventory, recipe: MerchantRecipe) : Boolean = {
val remainder = recipe.getItemToSell.copy()
InventoryUtils.insertIntoInventory(remainder, inventory, None, remainder.stackSize, simulate = true)
remainder.stackSize == 0
}
def completeTrade(inventory: IInventory, recipe: MerchantRecipe, exact: Boolean) : Boolean = {
// Now we'll check if we have enough items to perform the trade, caching first
val firstInputStack = recipe.getItemToBuy
val secondInputStack = if (recipe.hasSecondItemToBuy) Option(recipe.getSecondItemToBuy) else None
def containsAccumulativeItemStack(stack: ItemStack) =
InventoryUtils.extractFromInventory(stack, inventory, ForgeDirection.UNKNOWN, simulate = true, exact = exact).stackSize == 0
// Check if we have enough to perform the trade.
if (!containsAccumulativeItemStack(firstInputStack) || !secondInputStack.forall(containsAccumulativeItemStack))
return false
// Now we need to check if we have enough inventory space to accept the item we get for the trade.
val outputStack = recipe.getItemToSell.copy()
// We established that out inventory allows to perform the trade, now actually do the trade.
InventoryUtils.extractFromInventory(firstInputStack, inventory, ForgeDirection.UNKNOWN, exact = exact)
secondInputStack.map(InventoryUtils.extractFromInventory(_, inventory, ForgeDirection.UNKNOWN, exact = exact))
InventoryUtils.insertIntoInventory(outputStack, inventory, None, outputStack.stackSize)
// Tell the merchant we used the recipe, so MC can disable it and/or enable more recipes.
info.merchant.get.orNull.useRecipe(recipe)
true
}
}
class TradeInfo(var host: Option[EnvironmentHost], var merchant: WeakReference[IMerchant], var recipeID: Int) {