diff --git a/src/main/java/li/cil/oc/api/driver/UpgradeContainer.java b/src/main/java/li/cil/oc/api/driver/UpgradeContainer.java index 307ff76b5..71305b61c 100644 --- a/src/main/java/li/cil/oc/api/driver/UpgradeContainer.java +++ b/src/main/java/li/cil/oc/api/driver/UpgradeContainer.java @@ -23,4 +23,15 @@ public interface UpgradeContainer extends Item { * @return the slot type provided by that dynamic slot upgrade. */ Slot providedSlot(ItemStack stack); + + /** + * The maximum item tier of the items that can be placed into the slot + * provided by the specified container. + *
+ * This will usually be equal to the container's tier. + * + * @param stack the item stack to the the supported tier for. + * @return the maximum tier supported by that dynamic slot upgrade. + */ + int providedTier(ItemStack stack); } diff --git a/src/main/resources/assets/opencomputers/textures/gui/button_scroll.png b/src/main/resources/assets/opencomputers/textures/gui/button_scroll.png new file mode 100644 index 000000000..952cb3591 Binary files /dev/null and b/src/main/resources/assets/opencomputers/textures/gui/button_scroll.png differ diff --git a/src/main/resources/assets/opencomputers/textures/gui/robot.png b/src/main/resources/assets/opencomputers/textures/gui/robot.png index 41907f10c..6d4200f7c 100644 Binary files a/src/main/resources/assets/opencomputers/textures/gui/robot.png and b/src/main/resources/assets/opencomputers/textures/gui/robot.png differ diff --git a/src/main/resources/assets/opencomputers/textures/gui/robot_assembler.png b/src/main/resources/assets/opencomputers/textures/gui/robot_assembler.png index 0cbf7ecdc..36d07fc48 100644 Binary files a/src/main/resources/assets/opencomputers/textures/gui/robot_assembler.png and b/src/main/resources/assets/opencomputers/textures/gui/robot_assembler.png differ diff --git a/src/main/scala/li/cil/oc/client/PacketHandler.scala b/src/main/scala/li/cil/oc/client/PacketHandler.scala index d9bfca2f5..31bd5eaaa 100644 --- a/src/main/scala/li/cil/oc/client/PacketHandler.scala +++ b/src/main/scala/li/cil/oc/client/PacketHandler.scala @@ -38,6 +38,7 @@ class PacketHandler extends CommonPacketHandler { case PacketType.RedstoneState => onRedstoneState(p) case PacketType.RobotAnimateSwing => onRobotAnimateSwing(p) case PacketType.RobotAnimateTurn => onRobotAnimateTurn(p) + case PacketType.RobotAssemblingState => onRobotAssemblingState(p) case PacketType.RobotEquippedItemChange => onRobotEquippedItemChange(p) case PacketType.RobotEquippedUpgradeChange => onRobotEquippedUpgradeChange(p) case PacketType.RobotMove => onRobotMove(p) @@ -197,6 +198,14 @@ class PacketHandler extends CommonPacketHandler { case _ => // Invalid packet. } + def onRobotAssemblingState(p: PacketParser) = + p.readTileEntity[RobotAssembler]() match { + case Some(t) => + if (p.readBoolean()) t.requiredEnergy = 9001 + else t.requiredEnergy = 0 + case _ => // Invalid packet. + } + def onRobotEquippedItemChange(p: PacketParser) = p.readTileEntity[RobotProxy]() match { case Some(t) => t.robot.equippedItem = Option(p.readItemStack()) diff --git a/src/main/scala/li/cil/oc/client/Textures.scala b/src/main/scala/li/cil/oc/client/Textures.scala index b64705f41..40c696ba9 100644 --- a/src/main/scala/li/cil/oc/client/Textures.scala +++ b/src/main/scala/li/cil/oc/client/Textures.scala @@ -13,6 +13,7 @@ object Textures extends ResourceManagerReloadListener { val guiButtonPower = new ResourceLocation(Settings.resourceDomain, "textures/gui/button_power.png") val guiButtonRange = new ResourceLocation(Settings.resourceDomain, "textures/gui/button_range.png") val guiButtonRun = new ResourceLocation(Settings.resourceDomain, "textures/gui/button_run.png") + val guiButtonScroll = new ResourceLocation(Settings.resourceDomain, "textures/gui/button_scroll.png") val guiButtonSide = new ResourceLocation(Settings.resourceDomain, "textures/gui/button_side.png") val guiComputer = new ResourceLocation(Settings.resourceDomain, "textures/gui/computer.png") val guiRange = new ResourceLocation(Settings.resourceDomain, "textures/gui/range.png") diff --git a/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala b/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala index 52067686b..d27dfb06d 100644 --- a/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala +++ b/src/main/scala/li/cil/oc/client/gui/DynamicGuiContainer.scala @@ -39,7 +39,9 @@ abstract class DynamicGuiContainer(container: Container) extends GuiContainer(co case component: ComponentSlot if component.tierIcon != null => mc.getTextureManager.bindTexture(TextureMap.locationItemsTexture) GL11.glDisable(GL11.GL_DEPTH_TEST) + GL11.glDisable(GL11.GL_LIGHTING) drawTexturedModelRectFromIcon(slot.xDisplayPosition, slot.yDisplayPosition, component.tierIcon, 16, 16) + GL11.glEnable(GL11.GL_LIGHTING) GL11.glEnable(GL11.GL_DEPTH_TEST) case _ => } diff --git a/src/main/scala/li/cil/oc/client/gui/Robot.scala b/src/main/scala/li/cil/oc/client/gui/Robot.scala index 09aab3e5a..f39401e0c 100644 --- a/src/main/scala/li/cil/oc/client/gui/Robot.scala +++ b/src/main/scala/li/cil/oc/client/gui/Robot.scala @@ -27,12 +27,17 @@ class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) exten protected var powerButton: ImageButton = _ + protected var scrollButton: ImageButton = _ + protected def buffer = { robot.components.collect { case Some(component: api.component.TextBuffer) => component }.headOption.orNull } + // Scroll offset for robot inventory. + private var inventoryOffset = 0 + private val bufferWidth = 242.0 private val bufferHeight = 128.0 private val bufferMargin = BufferRenderer.innerMargin @@ -60,13 +65,16 @@ class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) exten override def drawScreen(mouseX: Int, mouseY: Int, dt: Float) { powerButton.toggled = robot.isRunning + scrollButton.enabled = robot.inventorySize > 16 super.drawScreen(mouseX, mouseY, dt) } override def initGui() { super.initGui() powerButton = new ImageButton(0, guiLeft + 5, guiTop + 139, 18, 18, Textures.guiButtonPower, canToggle = true) + scrollButton = new ImageButton(1, guiLeft + 244, guiTop + 142, 6, 13, Textures.guiButtonScroll) add(buttonList, powerButton) + add(buttonList, scrollButton) } override def drawSlotInventory(slot: Slot) { @@ -77,7 +85,9 @@ class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) exten case component: StaticComponentSlot if component.tierIcon != null => mc.getTextureManager.bindTexture(TextureMap.locationItemsTexture) GL11.glDisable(GL11.GL_DEPTH_TEST) + GL11.glDisable(GL11.GL_LIGHTING) drawTexturedModelRectFromIcon(slot.xDisplayPosition, slot.yDisplayPosition, component.tierIcon, 16, 16) + GL11.glEnable(GL11.GL_LIGHTING) GL11.glEnable(GL11.GL_DEPTH_TEST) case _ => } @@ -129,7 +139,9 @@ class Robot(playerInventory: InventoryPlayer, val robot: tileentity.Robot) exten mc.renderEngine.bindTexture(Textures.guiRobot) drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize) drawPowerLevel() - drawSelection() + if (robot.inventorySize > 0) { + drawSelection() + } } protected override def keyTyped(char: Char, code: Int) { diff --git a/src/main/scala/li/cil/oc/client/gui/RobotAssembler.scala b/src/main/scala/li/cil/oc/client/gui/RobotAssembler.scala index 89ba90bb2..321a316f7 100644 --- a/src/main/scala/li/cil/oc/client/gui/RobotAssembler.scala +++ b/src/main/scala/li/cil/oc/client/gui/RobotAssembler.scala @@ -10,23 +10,32 @@ import net.minecraft.client.gui.GuiButton import net.minecraft.entity.player.InventoryPlayer import net.minecraft.util.StatCollector import org.lwjgl.opengl.GL11 +import net.minecraft.client.renderer.Tessellator class RobotAssembler(playerInventory: InventoryPlayer, val assembler: tileentity.RobotAssembler) extends DynamicGuiContainer(new container.RobotAssembler(playerInventory, assembler)) { xSize = 176 ySize = 192 + private def assemblerContainer = inventorySlots.asInstanceOf[container.RobotAssembler] + protected var runButton: ImageButton = _ + private val progressX = 28 + private val progressY = 92 + + private val progressWidth = 140 + private val progressHeight = 12 + def add[T](list: util.List[T], value: Any) = list.add(value.asInstanceOf[T]) protected override def actionPerformed(button: GuiButton) { - if (button.id == 0 && !assembler.isAssembling && assembler.complexity <= assembler.maxComplexity) { + if (button.id == 0 && !assemblerContainer.isAssembling && assembler.complexity <= assembler.maxComplexity) { ClientPacketSender.sendRobotAssemblerStart(assembler) } } override def drawScreen(mouseX: Int, mouseY: Int, dt: Float) { - runButton.enabled = assembler.complexity <= assembler.maxComplexity && !assembler.isAssembling + runButton.enabled = assembler.complexity <= assembler.maxComplexity && !assemblerContainer.isAssembling && assembler.isItemValidForSlot(0, assembler.getStackInSlot(0)) runButton.toggled = !runButton.enabled super.drawScreen(mouseX, mouseY, dt) } @@ -39,7 +48,7 @@ class RobotAssembler(playerInventory: InventoryPlayer, val assembler: tileentity override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = { GL11.glPushAttrib(0xFFFFFFFF) // Me lazy... prevents NEI render glitch. - if (!assembler.isAssembling) { + if (!assemblerContainer.isAssembling) { if (!inventorySlots.getSlot(0).getHasStack) { val message = if (api.Items.get(inventorySlots.getSlot(0).getStack) == api.Items.get("robot")) @@ -56,7 +65,7 @@ class RobotAssembler(playerInventory: InventoryPlayer, val assembler: tileentity 30, 94, if (assembler.complexity <= assembler.maxComplexity) 0x404040 else 0x804040) } } - if (runButton.func_82252_a && !assembler.isAssembling) { + if (runButton.func_82252_a && !assemblerContainer.isAssembling) { val tooltip = new java.util.ArrayList[String] tooltip.add(StatCollector.translateToLocal(Settings.namespace + "gui.RobotAssembler.Run")) drawHoveringText(tooltip, mouseX - guiLeft, mouseY - guiTop, fontRenderer) @@ -69,7 +78,30 @@ class RobotAssembler(playerInventory: InventoryPlayer, val assembler: tileentity super.drawGuiContainerBackgroundLayer(dt, mouseX, mouseY) mc.renderEngine.bindTexture(Textures.guiRobotAssembler) drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize) + if (assemblerContainer.isAssembling) { + drawProgress() + } } override def doesGuiPauseGame = false + + private def drawProgress() { + val level = assemblerContainer.assemblyProgress / 100.0 + + val u0 = 0 + val u1 = progressWidth / 256.0 * level + val v0 = 1 - progressHeight / 256.0 + val v1 = 1 + val x = guiLeft + progressX + val y = guiTop + progressY + val w = progressWidth * level + + val t = Tessellator.instance + t.startDrawingQuads() + t.addVertexWithUV(x, y, zLevel, u0, v0) + t.addVertexWithUV(x, y + progressHeight, zLevel, u0, v1) + t.addVertexWithUV(x + w, y + progressHeight, zLevel, u1, v1) + t.addVertexWithUV(x + w, y, zLevel, u1, v0) + t.draw() + } } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/common/InventorySlots.scala b/src/main/scala/li/cil/oc/common/InventorySlots.scala index 26431ac62..12b249af2 100644 --- a/src/main/scala/li/cil/oc/common/InventorySlots.scala +++ b/src/main/scala/li/cil/oc/common/InventorySlots.scala @@ -69,7 +69,7 @@ object InventorySlots { InventorySlot(Slot.Processor, Tier.One), InventorySlot(Slot.Memory, Tier.One), InventorySlot(Slot.Memory, Tier.One), - InventorySlot(Slot.Disk, Tier.One), + InventorySlot(Slot.Disk, Tier.Any), InventorySlot(Slot.HardDiskDrive, Tier.One), InventorySlot(Slot.None, Tier.None) ), @@ -94,7 +94,7 @@ object InventorySlots { InventorySlot(Slot.Processor, Tier.Two), InventorySlot(Slot.Memory, Tier.Two), InventorySlot(Slot.Memory, Tier.Two), - InventorySlot(Slot.Disk, Tier.One), + InventorySlot(Slot.Disk, Tier.Any), InventorySlot(Slot.HardDiskDrive, Tier.Two), InventorySlot(Slot.None, Tier.None) ), @@ -119,7 +119,7 @@ object InventorySlots { InventorySlot(Slot.Processor, Tier.Three), InventorySlot(Slot.Memory, Tier.Three), InventorySlot(Slot.Memory, Tier.Three), - InventorySlot(Slot.Disk, Tier.One), + InventorySlot(Slot.Disk, Tier.Any), InventorySlot(Slot.HardDiskDrive, Tier.Three), InventorySlot(Slot.HardDiskDrive, Tier.Two) ) diff --git a/src/main/scala/li/cil/oc/common/PacketType.scala b/src/main/scala/li/cil/oc/common/PacketType.scala index d4ddc4440..8af4c6d49 100644 --- a/src/main/scala/li/cil/oc/common/PacketType.scala +++ b/src/main/scala/li/cil/oc/common/PacketType.scala @@ -18,6 +18,7 @@ object PacketType extends Enumeration { RedstoneState, RobotAnimateSwing, RobotAnimateTurn, + RobotAssemblingState, RobotEquippedItemChange, RobotEquippedUpgradeChange, RobotMove, diff --git a/src/main/scala/li/cil/oc/common/block/Delegator.scala b/src/main/scala/li/cil/oc/common/block/Delegator.scala index 1fed95389..8aa0a9376 100644 --- a/src/main/scala/li/cil/oc/common/block/Delegator.scala +++ b/src/main/scala/li/cil/oc/common/block/Delegator.scala @@ -330,13 +330,15 @@ class Delegator[Child <: Delegate](id: Int) extends Block(id, Material.iron) { case Some(subBlock) => subBlock.tooltipLines(stack, player, tooltip, advanced) case _ => } - if (KeyBindings.showMaterialCosts) { - ItemCosts.addTooltip(stack, tooltip.asInstanceOf[util.List[String]]) - } - else { - tooltip.add(StatCollector.translateToLocalFormatted( - Settings.namespace + "tooltip.MaterialCosts", - input.Keyboard.getKeyName(KeyBindings.materialCosts.keyCode))) + if (ItemCosts.hasCosts(stack)) { + if (KeyBindings.showMaterialCosts) { + ItemCosts.addTooltip(stack, tooltip.asInstanceOf[util.List[String]]) + } + else { + tooltip.add(StatCollector.translateToLocalFormatted( + Settings.namespace + "tooltip.MaterialCosts", + input.Keyboard.getKeyName(KeyBindings.materialCosts.keyCode))) + } } } diff --git a/src/main/scala/li/cil/oc/common/block/RobotProxy.scala b/src/main/scala/li/cil/oc/common/block/RobotProxy.scala index 396870ecf..f800d6716 100644 --- a/src/main/scala/li/cil/oc/common/block/RobotProxy.scala +++ b/src/main/scala/li/cil/oc/common/block/RobotProxy.scala @@ -16,6 +16,7 @@ import net.minecraft.item.{EnumRarity, ItemStack} import net.minecraft.util.{Icon, MovingObjectPosition, AxisAlignedBB, Vec3} import net.minecraft.world.{IBlockAccess, World} import net.minecraftforge.common.ForgeDirection +import li.cil.oc.client.KeyBindings class RobotProxy(val parent: SpecialDelegator) extends RedstoneAware with SpecialDelegate { val unlocalizedName = "Robot" @@ -33,9 +34,11 @@ class RobotProxy(val parent: SpecialDelegator) extends RedstoneAware with Specia override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { addLines(stack, tooltip) tooltip.addAll(Tooltip.get(unlocalizedName)) - val info = new ItemUtils.RobotData(stack) - for (component <- info.containers ++ info.components) { - tooltip.add(component.getDisplayName) + if (KeyBindings.showExtendedTooltips) { + val info = new ItemUtils.RobotData(stack) + for (component <- info.containers ++ info.components) { + tooltip.add("- " + component.getDisplayName) + } } } diff --git a/src/main/scala/li/cil/oc/common/container/ComponentSlot.scala b/src/main/scala/li/cil/oc/common/container/ComponentSlot.scala index 00b1268af..bd471dee0 100644 --- a/src/main/scala/li/cil/oc/common/container/ComponentSlot.scala +++ b/src/main/scala/li/cil/oc/common/container/ComponentSlot.scala @@ -21,7 +21,7 @@ trait ComponentSlot extends Slot { @SideOnly(Side.CLIENT) override def func_111238_b() = tier != Tier.None && super.func_111238_b() - override def isItemValid(stack: ItemStack) = inventory.isItemValidForSlot(slotNumber, stack) + override def isItemValid(stack: ItemStack) = inventory.isItemValidForSlot(getSlotIndex, stack) override def onPickupFromSlot(player: EntityPlayer, stack: ItemStack) { super.onPickupFromSlot(player, stack) diff --git a/src/main/scala/li/cil/oc/common/container/DynamicComponentSlot.scala b/src/main/scala/li/cil/oc/common/container/DynamicComponentSlot.scala index b225bfd15..9c824f63c 100644 --- a/src/main/scala/li/cil/oc/common/container/DynamicComponentSlot.scala +++ b/src/main/scala/li/cil/oc/common/container/DynamicComponentSlot.scala @@ -9,7 +9,7 @@ import net.minecraft.inventory.{Slot, IInventory} class DynamicComponentSlot(val container: Player, inventory: IInventory, index: Int, x: Int, y: Int, val info: Array[Array[InventorySlot]], val tierGetter: () => Int) extends Slot(inventory, index, x, y) with ComponentSlot { override def tier = { val mainTier = tierGetter() - if (mainTier >= 0) info(mainTier)(slotNumber).tier + if (mainTier >= 0) info(mainTier)(getSlotIndex).tier else mainTier } @@ -17,7 +17,7 @@ class DynamicComponentSlot(val container: Player, inventory: IInventory, index: def slot = { val mainTier = tierGetter() - if (mainTier >= 0) info(tierGetter())(slotNumber).slot + if (mainTier >= 0) info(tierGetter())(getSlotIndex).slot else api.driver.Slot.None } diff --git a/src/main/scala/li/cil/oc/common/container/Robot.scala b/src/main/scala/li/cil/oc/common/container/Robot.scala index bdaf023e9..98f483b5e 100644 --- a/src/main/scala/li/cil/oc/common/container/Robot.scala +++ b/src/main/scala/li/cil/oc/common/container/Robot.scala @@ -1,12 +1,13 @@ package li.cil.oc.common.container import cpw.mods.fml.common.FMLCommonHandler +import cpw.mods.fml.relauncher.{SideOnly, Side} import li.cil.oc.api +import li.cil.oc.client.gui.Icons import li.cil.oc.common.tileentity +import li.cil.oc.common.InventorySlots.Tier import li.cil.oc.server.{PacketSender => ServerPacketSender} import net.minecraft.entity.player.{EntityPlayer, InventoryPlayer} -import li.cil.oc.common.InventorySlots.Tier -import li.cil.oc.client.gui.Icons class Robot(playerInventory: InventoryPlayer, robot: tileentity.Robot) extends Player(playerInventory, robot) { addSlotToContainer(170 + 0 * slotSize, 218, api.driver.Slot.Tool) @@ -20,9 +21,19 @@ class Robot(playerInventory: InventoryPlayer, robot: tileentity.Robot) extends P val x = 170 + j * slotSize val index = inventorySlots.size addSlotToContainer(new StaticComponentSlot(this, otherInventory, index, x, y, api.driver.Slot.None, Tier.Any) { + def isValid = robot.isInventorySlot(getSlotIndex) + + @SideOnly(Side.CLIENT) + override def func_111238_b() = isValid && super.func_111238_b() + override def getBackgroundIconIndex = { - if (!robot.isInventorySlot(this.slotNumber)) Icons.get(Tier.None) - super.getBackgroundIconIndex + if (isValid) super.getBackgroundIconIndex + else Icons.get(Tier.None) + } + + override def getStack = { + if (isValid) super.getStack + else null } }) } diff --git a/src/main/scala/li/cil/oc/common/container/RobotAssembler.scala b/src/main/scala/li/cil/oc/common/container/RobotAssembler.scala index 333366dd0..099761c42 100644 --- a/src/main/scala/li/cil/oc/common/container/RobotAssembler.scala +++ b/src/main/scala/li/cil/oc/common/container/RobotAssembler.scala @@ -1,13 +1,27 @@ package li.cil.oc.common.container +import cpw.mods.fml.relauncher.{SideOnly, Side} +import cpw.mods.fml.common.FMLCommonHandler import li.cil.oc.common.{InventorySlots, tileentity} -import net.minecraft.entity.player.InventoryPlayer -import net.minecraft.inventory.Slot import li.cil.oc.util.ItemUtils +import net.minecraft.entity.player.InventoryPlayer +import net.minecraft.inventory.{ICrafting, Slot} +import scala.collection.convert.WrapAsScala._ +import li.cil.oc.api +import li.cil.oc.common.InventorySlots.Tier +import li.cil.oc.client.gui.Icons class RobotAssembler(playerInventory: InventoryPlayer, assembler: tileentity.RobotAssembler) extends Player(playerInventory, assembler) { // Computer case. - addSlotToContainer(12, 12) + { + val index = inventorySlots.size + addSlotToContainer(new StaticComponentSlot(this, otherInventory, index, 12, 12, api.driver.Slot.None, Tier.Any) { + @SideOnly(Side.CLIENT) override + def func_111238_b() = !isAssembling && super.func_111238_b() + + override def getBackgroundIconIndex = if (isAssembling) Icons.get(Tier.None) else super.getBackgroundIconIndex + }) + } def caseTier = ItemUtils.caseTier(inventorySlots.get(0).asInstanceOf[Slot].getStack) @@ -41,4 +55,40 @@ class RobotAssembler(playerInventory: InventoryPlayer, assembler: tileentity.Rob // Show the player's inventory. addPlayerInventorySlots(8, 110) + + var isAssembling = false + var assemblyProgress = 0 + + @SideOnly(Side.CLIENT) + override def updateProgressBar(id: Int, value: Int) { + super.updateProgressBar(id, value) + if (id == 0) { + isAssembling = value == 1 + } + + if (id == 1) { + assemblyProgress = value + } + } + + override def detectAndSendChanges() { + super.detectAndSendChanges() + if (FMLCommonHandler.instance.getEffectiveSide.isServer) { + if (isAssembling != assembler.isAssembling) { + isAssembling = assembler.isAssembling + sendProgressBarUpdate(0, if (isAssembling) 1 else 0) + } + if (assemblyProgress != assembler.progress) { + assemblyProgress = assembler.progress + sendProgressBarUpdate(1, assemblyProgress) + } + } + } + + private def sendProgressBarUpdate(id: Int, value: Int) { + for (entry <- crafters) entry match { + case player: ICrafting => player.sendProgressBarUpdate(this, id, value) + case _ => + } + } } \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/common/item/Analyzer.scala b/src/main/scala/li/cil/oc/common/item/Analyzer.scala index 7613a0186..df4fbe069 100644 --- a/src/main/scala/li/cil/oc/common/item/Analyzer.scala +++ b/src/main/scala/li/cil/oc/common/item/Analyzer.scala @@ -17,6 +17,7 @@ class Analyzer(val parent: Delegator) extends Delegate { override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) { tooltip.addAll(Tooltip.get(unlocalizedName)) + super.tooltipLines(stack, player, tooltip, advanced) } override def onItemUse(stack: ItemStack, player: EntityPlayer, world: World, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float) = { diff --git a/src/main/scala/li/cil/oc/common/item/Delegate.scala b/src/main/scala/li/cil/oc/common/item/Delegate.scala index 98623ea86..e75553bc2 100644 --- a/src/main/scala/li/cil/oc/common/item/Delegate.scala +++ b/src/main/scala/li/cil/oc/common/item/Delegate.scala @@ -51,13 +51,15 @@ trait Delegate { @SideOnly(Side.CLIENT) def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: java.util.List[String], advanced: Boolean) { - if (KeyBindings.showMaterialCosts) { - ItemCosts.addTooltip(stack, tooltip.asInstanceOf[util.List[String]]) - } - else { - tooltip.add(StatCollector.translateToLocalFormatted( - Settings.namespace + "tooltip.MaterialCosts", - input.Keyboard.getKeyName(KeyBindings.materialCosts.keyCode))) + if (ItemCosts.hasCosts(stack)) { + if (KeyBindings.showMaterialCosts) { + ItemCosts.addTooltip(stack, tooltip.asInstanceOf[util.List[String]]) + } + else { + tooltip.add(StatCollector.translateToLocalFormatted( + Settings.namespace + "tooltip.MaterialCosts", + input.Keyboard.getKeyName(KeyBindings.materialCosts.keyCode))) + } } if (stack.hasTagCompound && stack.getTagCompound.hasKey(Settings.namespace + "data")) { val data = stack.getTagCompound.getCompoundTag(Settings.namespace + "data") diff --git a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala index 5dd07d739..39f2ae187 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala @@ -50,6 +50,8 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo var selectedSlot = actualSlot(0) + // Fixed number of containers (mostly due to GUI limitation, but also because + // I find three to be a large enough number for sufficient flexibility). override def containerCount = 3 override def componentCount = info.components.length @@ -303,7 +305,9 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo if (nbt.hasKey(Settings.namespace + "owner")) { owner = nbt.getString(Settings.namespace + "owner") } - selectedSlot = nbt.getInteger(Settings.namespace + "selectedSlot") max inventorySlots.min min inventorySlots.max + if (inventorySize > 0) { + selectedSlot = nbt.getInteger(Settings.namespace + "selectedSlot") max inventorySlots.min min inventorySlots.max + } animationTicksTotal = nbt.getInteger(Settings.namespace + "animationTicksTotal") animationTicksLeft = nbt.getInteger(Settings.namespace + "animationTicksLeft") if (animationTicksLeft > 0) { @@ -509,7 +513,7 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo def containerSlotTier(slot: Int) = if (containerSlots contains slot) { val stack = info.containers(slot - 1) Option(Driver.driverFor(stack)) match { - case Some(driver: api.driver.UpgradeContainer) => driver.tier(stack) + case Some(driver: api.driver.UpgradeContainer) => driver.providedTier(stack) case _ => Tier.None } } @@ -517,7 +521,7 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo def isToolSlot(slot: Int) = slot == 0 - def isInventorySlot(slot: Int) = !isToolSlot(slot) && !isComponentSlot(slot) + def isInventorySlot(slot: Int) = slot >= 0 && slot < getSizeInventory && !isToolSlot(slot) && !isComponentSlot(slot) def isFloppySlot(slot: Int) = isComponentSlot(slot) && (Option(getStackInSlot(slot)) match { case Some(stack) => Option(Driver.driverFor(stack)) match { @@ -572,7 +576,7 @@ class Robot(val isRemote: Boolean) extends traits.Computer with traits.PowerInfo } Array.copy(components, getSizeInventory - componentCount, components, realSize, componentCount) getSizeInventory = realSize + componentCount - if (world != null) { + if (world != null && isServer) { val p = player() for (stack <- removed) { p.inventory.addItemStackToInventory(stack) diff --git a/src/main/scala/li/cil/oc/common/tileentity/RobotAssembler.scala b/src/main/scala/li/cil/oc/common/tileentity/RobotAssembler.scala index 638a80b26..b98f062aa 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/RobotAssembler.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/RobotAssembler.scala @@ -1,13 +1,17 @@ package li.cil.oc.common.tileentity -import li.cil.oc.api.network.Visibility import li.cil.oc.{Settings, api} -import net.minecraft.item.ItemStack import li.cil.oc.api.Driver -import li.cil.oc.common.InventorySlots.Tier -import li.cil.oc.common.InventorySlots -import li.cil.oc.util.ItemUtils import li.cil.oc.api.driver.{Slot, UpgradeContainer} +import li.cil.oc.api.network.Visibility +import li.cil.oc.common.InventorySlots +import li.cil.oc.common.InventorySlots.Tier +import li.cil.oc.server.{PacketSender => ServerPacketSender} +import li.cil.oc.util.ItemUtils +import li.cil.oc.util.ExtendedNBT._ +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import cpw.mods.fml.relauncher.{Side, SideOnly} class RobotAssembler extends traits.Environment with traits.Inventory with traits.Rotatable { val node = api.Network.newNode(this, Visibility.None). @@ -16,8 +20,12 @@ class RobotAssembler extends traits.Environment with traits.Inventory with trait def isAssembling = requiredEnergy > 0 + def progress = ((1 - requiredEnergy / totalRequiredEnergy) * 100).toInt + var robot: Option[ItemStack] = None + var totalRequiredEnergy = 0.0 + var requiredEnergy = 0.0 def complexity = items.drop(1).foldLeft(0)((acc, stack) => acc + (Option(api.Driver.driverFor(stack.orNull)) match { @@ -35,6 +43,7 @@ class RobotAssembler extends traits.Environment with traits.Inventory with trait if (!isAssembling && robot.isEmpty && complexity <= maxComplexity) { // TODO validate all slots, just in case. never trust a client. never trust minecraft. val data = new ItemUtils.RobotData() + data.name = ItemUtils.RobotData.randomName data.energy = 50000 data.containers = items.take(4).drop(1).collect { case Some(item) => item @@ -45,7 +54,9 @@ class RobotAssembler extends traits.Environment with traits.Inventory with trait val stack = api.Items.get("robot").createItemStack(1) data.save(stack) robot = Some(stack) - requiredEnergy = Settings.get.robotBaseCost + complexity * Settings.get.robotComplexityCost + totalRequiredEnergy = math.max(1, Settings.get.robotBaseCost + complexity * Settings.get.robotComplexityCost) + requiredEnergy = totalRequiredEnergy + ServerPacketSender.sendRobotAssembling(this, assembling = true) for (slot <- 0 until getSizeInventory) items(slot) = None onInventoryChanged() @@ -64,10 +75,38 @@ class RobotAssembler extends traits.Environment with traits.Inventory with trait setInventorySlotContents(0, robot.get) robot = None requiredEnergy = 0 + ServerPacketSender.sendRobotAssembling(this, assembling = false) } } } + override def readFromNBT(nbt: NBTTagCompound) { + super.readFromNBT(nbt) + if (nbt.hasKey(Settings.namespace + "robot")) { + robot = Option(ItemStack.loadItemStackFromNBT(nbt.getCompoundTag(Settings.namespace + "robot"))) + } + totalRequiredEnergy = nbt.getDouble(Settings.namespace + "total") + requiredEnergy = nbt.getDouble(Settings.namespace + "remaining") + } + + override def writeToNBT(nbt: NBTTagCompound) { + super.writeToNBT(nbt) + robot.foreach(stack => nbt.setNewCompoundTag(Settings.namespace + "robot", stack.writeToNBT)) + nbt.setDouble(Settings.namespace + "total", totalRequiredEnergy) + nbt.setDouble(Settings.namespace + "remaining", requiredEnergy) + } + + @SideOnly(Side.CLIENT) override + def readFromNBTForClient(nbt: NBTTagCompound) { + super.readFromNBTForClient(nbt) + requiredEnergy = nbt.getDouble("remaining") + } + + override def writeToNBTForClient(nbt: NBTTagCompound) { + super.writeToNBTForClient(nbt) + nbt.setDouble("remaining", requiredEnergy) + } + // ----------------------------------------------------------------------- // override def getInvName = Settings.namespace + "container.RobotAssembler" diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index fbb81fa76..8a72749d1 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -142,6 +142,15 @@ object PacketSender { pb.sendToNearbyPlayers(t) } + def sendRobotAssembling(t: tileentity.RobotAssembler, assembling: Boolean) { + val pb = new PacketBuilder(PacketType.RobotAssemblingState) + + pb.writeTileEntity(t) + pb.writeBoolean(assembling) + + pb.sendToNearbyPlayers(t) + } + def sendRobotMove(t: tileentity.Robot, ox: Int, oy: Int, oz: Int, direction: ForgeDirection) { val pb = new PacketBuilder(PacketType.RobotMove) diff --git a/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerCard.scala b/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerCard.scala index 854f985e9..c8f8a6033 100644 --- a/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerCard.scala +++ b/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerCard.scala @@ -15,6 +15,8 @@ object UpgradeContainerCard extends Item with UpgradeContainer { override def providedSlot(stack: ItemStack) = Slot.Card + override def providedTier(stack: ItemStack) = tier(stack) + override def tier(stack: ItemStack) = Items.multi.subItem(stack) match { case Some(container: item.UpgradeContainerCard) => container.tier diff --git a/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerFloppy.scala b/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerFloppy.scala index e91790095..d9cc028b1 100644 --- a/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerFloppy.scala +++ b/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerFloppy.scala @@ -13,4 +13,6 @@ object UpgradeContainerFloppy extends Item with UpgradeContainer { override def slot(stack: ItemStack) = Slot.UpgradeContainer override def providedSlot(stack: ItemStack) = Slot.Disk + + override def providedTier(stack: ItemStack) = -1 // Any } diff --git a/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerUpgrade.scala b/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerUpgrade.scala index ea5e0e1da..cae125aa6 100644 --- a/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerUpgrade.scala +++ b/src/main/scala/li/cil/oc/server/driver/item/UpgradeContainerUpgrade.scala @@ -15,6 +15,8 @@ object UpgradeContainerUpgrade extends Item with UpgradeContainer { override def providedSlot(stack: ItemStack) = Slot.Upgrade + override def providedTier(stack: ItemStack) = tier(stack) + override def tier(stack: ItemStack) = Items.multi.subItem(stack) match { case Some(container: item.UpgradeContainerUpgrade) => container.tier diff --git a/src/main/scala/li/cil/oc/util/ItemCosts.scala b/src/main/scala/li/cil/oc/util/ItemCosts.scala index 44b93cdf3..b79fa5233 100644 --- a/src/main/scala/li/cil/oc/util/ItemCosts.scala +++ b/src/main/scala/li/cil/oc/util/ItemCosts.scala @@ -46,6 +46,11 @@ object ItemCosts { terminate(Item.slimeBall) terminate(Item.stick) + def hasCosts(stack: ItemStack) = { + val ingredients = computeIngredients(stack) + ingredients.size > 0 && (ingredients.size > 1 || !ItemStack.areItemStacksEqual(ingredients.head._1, stack)) + } + def addTooltip(stack: ItemStack, tooltip: util.List[String]) { tooltip.add(StatCollector.translateToLocal(Settings.namespace + "tooltip.Materials")) for ((ingredient, count) <- computeIngredients(stack)) {