From 48b50c9d2763805e7d112ffd0342b98ea1af22f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 15 May 2014 23:46:15 +0200 Subject: [PATCH] Progress bar for robot assembly, blocking slot in assembler while assembling. Some checks for robot inventory slots in GUI if there are fewer than 16 inventory slots. Not showing item costs prompt for uncraftable items and blocks. Some tier icon related rendering fixes. Fixed analyzer costs not showing in tooltip. --- .../cil/oc/api/driver/UpgradeContainer.java | 11 ++++ .../textures/gui/button_scroll.png | Bin 0 -> 164 bytes .../opencomputers/textures/gui/robot.png | Bin 742 -> 651 bytes .../textures/gui/robot_assembler.png | Bin 1759 -> 1769 bytes .../li/cil/oc/client/PacketHandler.scala | 9 +++ .../scala/li/cil/oc/client/Textures.scala | 1 + .../oc/client/gui/DynamicGuiContainer.scala | 2 + .../scala/li/cil/oc/client/gui/Robot.scala | 14 ++++- .../li/cil/oc/client/gui/RobotAssembler.scala | 40 +++++++++++-- .../li/cil/oc/common/InventorySlots.scala | 6 +- .../scala/li/cil/oc/common/PacketType.scala | 1 + .../li/cil/oc/common/block/Delegator.scala | 16 ++--- .../li/cil/oc/common/block/RobotProxy.scala | 9 ++- .../oc/common/container/ComponentSlot.scala | 2 +- .../container/DynamicComponentSlot.scala | 4 +- .../li/cil/oc/common/container/Robot.scala | 19 ++++-- .../oc/common/container/RobotAssembler.scala | 56 +++++++++++++++++- .../li/cil/oc/common/item/Analyzer.scala | 1 + .../li/cil/oc/common/item/Delegate.scala | 16 ++--- .../li/cil/oc/common/tileentity/Robot.scala | 12 ++-- .../oc/common/tileentity/RobotAssembler.scala | 51 ++++++++++++++-- .../scala/li/cil/oc/server/PacketSender.scala | 9 +++ .../driver/item/UpgradeContainerCard.scala | 2 + .../driver/item/UpgradeContainerFloppy.scala | 2 + .../driver/item/UpgradeContainerUpgrade.scala | 2 + src/main/scala/li/cil/oc/util/ItemCosts.scala | 5 ++ 26 files changed, 245 insertions(+), 45 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/textures/gui/button_scroll.png 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 0000000000000000000000000000000000000000..952cb3591c8c25491ba0c5481aa51a84eee34a7f GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol|6H_V+Po~-c74Zc4gt&HhcZY_C9y@mI|Ns9dxW60$itBm0IEGZ*TGHdl z#bChG?DPG<{rRnLSf@5ra6V_`TQup~DxQb&(<4~dhMxT@n!w-L1;Fyx1 zl&avFo0y&&l$w}QS$Hzl2B=6ez$e5NNOyO4A3JvJ|NsBy=H`ryjG>{SX=l>d+1Z(x zn1F)Ul4oTB6>*mY`2_>HP{82j&-e*w>q}1;$B>F!Z|)wn!n83?OD2GKcgMV4`Ja9)`6Yc|YTnh7-tD`*Zkt!;TtjyGhN)E>e?5E25YElO@Q~sD`6acJ zeH#|vn)X?(-ONdvfxUL`x!H662qS9&v6&eAvZBw;&S)`lI)^Ujpu9xz5{D%y)=@z3 z1$n83Yk)!y+HVXwP^1_bGFlf$J>2zCTzVlRgMxIz9LB1d@yW)FUncFTpU+Tr()T}0 l2VcW=ZdPP%{-@g+m>D+s^_pLQ^Z7AI#?#f$Wt~$(697Vev627) delta 551 zcmeBXea1S$vtB*GC&ZP3fuXy*``EE#|Ns9tH#cWwWK27g78)9AJkuBm*xA{cn3#Z4 znXehWfJ%8wg8YJkTsUB`eWBFGz`$hV>EaktaqG?9!2Biy3Dyf?cM78a|9>x=5F=1g zG-1Qt;^b8;I~N}J*SO!kbnB$qW^49M)zvdk{qw8&`u*5bvJWQB+NZC4fc3x!E&bw# zBVVt-<9zTx{?k6OmzNl(buw2(vrPQhG>MV5{y?M<`-hzz3=G8$w^-BI3QorS=TR_W zkYiZ=X+GE}j4BMCYFkClYnkVC5oBQnfvm49=Aq&t%zW)16JPdnIO}qPS$8u|sZJw@vF6*2UngIS{*VO<3 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 0cbf7ecdc550221800cff84974348c7ce1c3152b..36d07fc48225b4f6ef8874f6d10a4a91a6b466bc 100644 GIT binary patch delta 1547 zcmZ9MX*kq-6vu!68D@rz!PHeQ84|gJvW1XImM9wASYr?=F&bO8`TvQ~!YHPiq(PD; zWx1*Q5UDg{Nr{p+O2)n`GOzCv+ZO}sE1swTU%StpFb}W ziGn+VbKJGz*-pnB003f?v!lzJyH21c=_3vRjE0@nKG)Oz6QA&rA9l!K=%(^2(V1Ew zM4}g4mmyUC&+y^O0?#I6hufStTefQZZQvG6{Tr9hgjpt^gxROsAXI72nCKKY8#2D= z%=*R62FB1@sBujqY+iCfYFBj7@ixMAY}4GliC*)hEy8Y}hQcKV%$Q=S<#k}(+PCoH zIr|bT#03fC$S-0&j9BJ?O*4!E79yqmwcB64D6RPM(yLnrr5q&NpCf)9@N7RwX0N#L=bY=4@CKECBKSIDNIc#gFin+ zc1F3e$2X77`=8jThvtw5$+<2tW0v4An)?ca@t-DLbS#TuQEw` z7tTk8*^ArUgPM3# zym>*LZS%Am;_DUQk)L4)3&uDJ%BHwa`m-{S2;9$8Y0*0yJ@!hRGLdCA^qxV4I_OtI zkr6pk>HeTV1Na_F?u-Qp>#Ahdsq(k);_tDa{XNXal)!E2sqbkV@Zu%E;a8V)X zKY_((9!3U`zdjK{9Q@y!tX_%XJST@bEPTxzFU=z_dB~aX*6pu9I~m1)YCI@K(ulWo z({Cp_VP(p-1C4--QTny>;2yUhGLTmn>sIyya*J(omHsg} zYwoihdO!umX+YCM8x*H*Xesw5vo49GPI)66t%O#3JJ$fD61bK zU6Kdw%rSpzoHOZAJSXu%BKtySZ+dj{2ntDP$rpa9y&*{|{o0-XqSY#Mm6~L*WUNw? zYTm_2@~P~y9yxvWU2{xo-`g}t05gfF#WG^l!$z(L2=V zrVJ*b!8_MeY2Sk94jAD>1Z9!7pl7d+L6V3XbU!!qO#1DY!nt=*6`-w*UX-ry+!+`- z|Gqn!U|+CodrbMJ!V#9vR@DJd!eN3`#8RUDmd%K1ibifSRN!WVzBA?fDFJ2HcmX@p zvz(2iXk@HCyY*6(o>{d2z5;`W?oQDyH1(VEafK3V#wN_sRJN=o@pmiB$Nj?0nrl@UTV;X%C_L5nO9rXeS(~)lg%}}CzIWDL^Y$@qoWZ3 delta 1549 zcmZWpdpOg382|oeW`rgYJ7G9UDVF)dj`6q!?h_MG>x_w#u_m;c^TmA5KflB%_z57nckrG>-ctgWqO z9@vRqce~^^0ANFAh6W3~Z)n&607{?a?m|s?HStD;F=UK^!yIxxnr1f0)~-2SIgDu~ zO+|GIEj~6!o7d)dP9ObtpnIO)V78jQGADi~{Chqi7)Ku|m+7%TSpjx%`_x;p2~hpf zATkk41H8LHZ&f~Twqxbt+i&0dEks`q!gjgNa<2_Uccd(I9=``sA)V(9m6cJwk;+Q+ zpq@P~3j58L69I;QY!Iq=K~v^rg7CDea>`Co+lkeU;W}F`;KB`Z$IsmF+tqCaUyQ5p z-?3|;mREjjCPOBmzc|L(*XI_V2FCpWA9~_l;JdO|c)+tSuh??}lN0qCT{cDq^X)-q zPcG6~q=h;(*ALrltA;C4LAHTyFRuei3uik*H3A&!Ea$}|TZM{V$Y~?L1&EDD5}lM2 z75nq9O~!6kcyg7f1Dyw!S;N>O<@3GFjogjuy)~fRh7Q_JjtLU#G#NA3Pa$Em0ULr` z-$^CRBU)ed9a&uEbEx8AS@p9R#Rxf8g}r4J<7^}iAHdVzzt(Ldszh|Vm_n}wC8hWM zRp=`lB-Vb&*8D$UO-M|>1Y>d8+R0u#oqn~VH-$^=-FOtdFfT9CY}tlcERY;(j4%dz zLyV5&f!uN17voKX#y!fm@|S}%^UX)F5{tAiOj?QjbhE#VNwSbwZ6#A!pWK!J|4ksD zDqj^{(-!bhPIL8#gErJpoc89^${|ZgmMwxr8Q9Aqz@V=Tips* zt<{Q@nfFm>H^j%dqp!3&_;4#;7p|4oh}S95l=KgCAF-5d&r+yN41ANbg3e>^Ln5c9 z?h%Tjx0^TmOzT08llfm$>gUeDN8FN9LgLSziKME>{2LNQE|42cA!NH}kW=d_!<=blor`@|ybY9ZQ-{TQXU7Rab4HtdU5=C@S@_8j-Y|ZloQ|r7< zk1q!HpaJD>vWn=+R}<%RN5qjsCZjqy^5pqyXrcPlW|@b6noyN;zXs-4U^>XuE_jZRk(U4mQ~LwL0cgxnul}*AC?|)qR35nHB5U8xsx>} zUToZh96T*r47(#=oQjYH`8p``3OD9$b=V_JAQ-1z?q|m&+alq`3wB)%kq#=jf)oxz zS5G})zN_D}No%XS@7xvX62Y`jYH-}~87tNx{lA2CxExKj$iv zA#UR6)eMDbWOi6%bvo3oi&3p3jaZ$q&N$vn^tFp8U|>PUy1gOJRJ*h7f5Plr=}$jM zX(6Y<-RAD#(sAO!=s;Bzns9DhG^!ojIDj8=?5eLxZ59`$ efkhd!6!E}3dJ8Rb`r)mgaU>64_bS)WbN>N)zoV@H 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)) {