From 4f804c39d40bf31343c4ff9fc97d4981add4f19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 22 May 2015 19:39:05 +0200 Subject: [PATCH] Added hover boots. Because I can. --- assets/items.psd | Bin 612747 -> 620434 bytes src/main/resources/application.conf | 17 +++ .../doc/en_US/item/hoverBoots.md | 11 ++ .../opencomputers/doc/en_US/item/index.md | 3 + .../assets/opencomputers/lang/en_US.lang | 2 + .../opencomputers/recipes/default.recipes | 13 ++- .../textures/items/HoverBoots.png | Bin 0 -> 461 bytes src/main/scala/li/cil/oc/Constants.scala | 1 + src/main/scala/li/cil/oc/Settings.scala | 4 + .../renderer/item/HoverBootRenderer.scala | 109 ++++++++++++++++++ .../oc/common/event/HoverBootsHandler.scala | 73 ++++++++++++ .../scala/li/cil/oc/common/init/Items.scala | 17 ++- .../li/cil/oc/common/item/HoverBoots.scala | 69 +++++++++++ .../li/cil/oc/common/item/RemoteControl.scala | 11 ++ .../oc/common/item/data/HoverBootsData.scala | 22 ++++ .../oc/common/item/traits/Chargeable.scala | 96 +++++++++++++++ .../integration/ic2/ElectricItemManager.scala | 44 +++++++ .../opencomputers/ModOpenComputers.scala | 1 + 18 files changed, 488 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/assets/opencomputers/doc/en_US/item/hoverBoots.md create mode 100644 src/main/resources/assets/opencomputers/textures/items/HoverBoots.png create mode 100644 src/main/scala/li/cil/oc/client/renderer/item/HoverBootRenderer.scala create mode 100644 src/main/scala/li/cil/oc/common/event/HoverBootsHandler.scala create mode 100644 src/main/scala/li/cil/oc/common/item/HoverBoots.scala create mode 100644 src/main/scala/li/cil/oc/common/item/RemoteControl.scala create mode 100644 src/main/scala/li/cil/oc/common/item/data/HoverBootsData.scala create mode 100644 src/main/scala/li/cil/oc/common/item/traits/Chargeable.scala create mode 100644 src/main/scala/li/cil/oc/integration/ic2/ElectricItemManager.scala diff --git a/assets/items.psd b/assets/items.psd index e83e67a587f5fbb8b0887aa97cce39cac3d19b0c..9c65a2b8687ae9101bbab34f03dadbdb7fd18396 100644 GIT binary patch delta 4774 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 delta 2052 zcmai#eNYrf8pgYa{pbOf1wjyz=ovV)U|CQ+5QASFCU6mO6&ESk1;tp1M$|$|5%#DU zsc000NXILPAe@L;B4QYo0EhBbqLP5Hx*J?1IZtr$b3wAoPI`8uXOg>0PfgGC`#$f} zzkcVBDR}I8u+B4omYwhCLCeEe@_2v@$kzJ)1Pi5<lD;;Sa_j#O5p}x0Qan`;-y&?uIrs$w+KaCFAxgqLi+JMd#h)hDX<2BH4o+{ zg5FR>o4qJ=ZaRh;)O7qWG2+eP`I$o^`1Sy1vBaDa07#w(7@0Nv(27c)gG)uQ79PR* zQ{mj)QG3XY+EZB{QtmxCI+-eD*aV7!lzXpvg>{~kJzlbj663GdP!3FHB9%*$w=7B3 z8j@5dLVJ9iyfM-Mm=5uiBx(xf-p3HL2#Rv=x423-nO)VE!jM^{=FoO1#@T7a_3gsj z7DWw16ps_g8ROMbd!%J43Kes1C zR(I;7A%kXz|Kgk1i!*&PQ{A*1i(>UaB!{iK(w%BZ~mFhSnuTOyBYX*zxR z_-LGNcji_*sbTV{-w%%ilTABAqAE>OV~rj1h>WFO)u%7rGU%eVK04)oV+*tGq~;$l zvLwx62P$uAnrh@ZM_3RznsxhT=bwk3+;3|tk?f4srdHk=uCL5=9X{cby8cB*Pq>Gy zq9ELJu17(51QS$B{T-^R`sSTZtvYNi9X1@I4*Y)3ADm~w& zy?A-QyxE}CvVd1Rw=4TEE4(6GwgwvTe6f1OuKjFJ$AY{C2WQqcr__!IclWSh9}D2{ zo`vsJCysso6vvzymb~0>XumOcWvWg5$m5rxapOHwqq5wz)3iv{x57VoWKr$Q{c%$^ zDvqf43Cpee%O7{CHFqcSC`GKQyV_3&66JGoD(_PLn>!zhQEcy5y zbT(h#bTpx1(stL!XQK~1y4EmOc_+^(UTy02#jlhN_Q_*$XBA< zu)kmMf}q@tQxv(a$jxIiPVr;DRIu6dws@H!8nxvE*p|#bFA5bbWV)9L zPKt7qWCA8hCVX~*@fM-GR&K5!04xVGuo^^xNb{8pR)KXSI)m|WK>vpSM-gjLIR0wo`d2Frn}b&+AvatRkDTEk?ubVLIK@@yfSnVN)WJ>>Gclom zIH4!AK4n|9Yfbza`FlmlHS-q+#pB9RmRn-a~3)3Hj4+(^|KC3@dl zSk~CM?drwoKphq(qBwXL??^;T;rF;Pk%+X+P$F{Q05w?DN=gUu%2pJNyM7ef;Nn&k zU`zX1!1;XFL42;6Y+-Cg3k6nuHEueAg;)AQeS%>{QP=t`j2Nzw* z;@%aq@yQMpM(D>o%=F7T&Ga92qTL+*s5i~gOMK{G==b{2zoF0ZqMfkDhkirkQP%`6svOY5vS5OJ37)a{07d?0`$)2d1z?<=B(Xujf-yGl zm)IC<`d!RG>YuZ^w{$GvVunAAnZS53G5odAM7H~F@g#WhMrR~wlN=D9*(GqpvMsce V=zH!w;2wJom{={7xrKJI`5AjrWCQ>J diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index f9a4a31a4..706888188 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -556,6 +556,9 @@ opencomputers { # The amount of energy an access point can store. accessPoint: 600.0 + + # The internal buffer size of the hover boots. + hoverBoots: 15000.0 } # Default "costs", i.e. how much energy certain operations consume. @@ -720,6 +723,20 @@ opencomputers { # How much energy is required for a single 3D print. printerModel: 100 + + # The amount of energy consumed when jumping with the hover boots. Only + # applies when the jump boost is applied, i.e. when not sneaking. + hoverBootJump: 10 + + # The amount of energy consumed when the hover boots absorb some fall + # velocity (i.e. when falling from something higher than three blocks). + hoverBootAbsorb: 10 + + # The amount of energy consumed *per second* when moving around while + # wearing the hover boots. This is compensate for the step assist, which + # does not consume energy on a per-use basis. When standing still or + # moving very slowly this also does not trigger. + hoverBootMove: 1 } # The rate at which different blocks accept external power. All of these diff --git a/src/main/resources/assets/opencomputers/doc/en_US/item/hoverBoots.md b/src/main/resources/assets/opencomputers/doc/en_US/item/hoverBoots.md new file mode 100644 index 000000000..2f226673e --- /dev/null +++ b/src/main/resources/assets/opencomputers/doc/en_US/item/hoverBoots.md @@ -0,0 +1,11 @@ +# Hover Boots + +![Step on it.](oredict:oc:hoverBoots) + +If you can't be bothered to program [drones](drone.md), here's an alternative use for them: stepping stones! Or glorified inline skates. Something like that. + +Either way, these boots have a few useful properties: as long as they have power they will let you jump higher, and absorb some of the shock when landing after a particularly high jump. Specifically, they'll allow you to jump up to four blocks high and cut the impact down to one third. + +Additionally, due to always being in kind of a hovering state anyway, they allow you to seamlessly walk up steps of up to one block height. This is particularly handy when sprinting up a mountain, for example, a very commonplace fitness routine amongst Minecrafters. Or so I hear. + +The boots can be recharged in an OpenComptuers [charger](../block/charger.md) or any other such device, like the Applied Energistics 2 charger, an IndustrialCraft 2 battery box, or the Energetic Infuser from Thermal Expansion. diff --git a/src/main/resources/assets/opencomputers/doc/en_US/item/index.md b/src/main/resources/assets/opencomputers/doc/en_US/item/index.md index 4773d828e..6b900dce4 100644 --- a/src/main/resources/assets/opencomputers/doc/en_US/item/index.md +++ b/src/main/resources/assets/opencomputers/doc/en_US/item/index.md @@ -83,3 +83,6 @@ Keep in mind that some of these may not be available, depending on the recipe se * [Drone Case](droneCase1.md) * [Microcontroller Case](microcontrollerCase1.md) * [Tablet Case](tabletCase1.md) + +## Other +* [Hover Boots](hoverBoots.md) diff --git a/src/main/resources/assets/opencomputers/lang/en_US.lang b/src/main/resources/assets/opencomputers/lang/en_US.lang index 29916595c..527629c23 100644 --- a/src/main/resources/assets/opencomputers/lang/en_US.lang +++ b/src/main/resources/assets/opencomputers/lang/en_US.lang @@ -73,6 +73,7 @@ item.oc.GraphicsCard2.name=Graphics Card (Tier 3) item.oc.HardDiskDrive0.name=Hard Disk Drive (Tier 1) item.oc.HardDiskDrive1.name=Hard Disk Drive (Tier 2) item.oc.HardDiskDrive2.name=Hard Disk Drive (Tier 3) +item.oc.hoverBoots.name=Hover Boots item.oc.InkCartridge.name=Ink Cartridge item.oc.InkCartridgeEmpty.name=Ink Cartridge (Empty) item.oc.InternetCard.name=Internet Card @@ -268,6 +269,7 @@ oc:tooltip.EEPROM=Small, programmable storage that contains the BIOS computers u oc:tooltip.FakeEndstone=Almost as good as the real thing, even emulates its floatiness! oc:tooltip.Geolyzer=Allows scanning the surrounding area's blocks' hardness. This information can be useful for generating holograms of the area or for detecting ores. oc:tooltip.GraphicsCard=Used to change what's displayed on screens.[nl] Maximum resolution: §f%sx%s§7[nl] Maximum color depth: §f%s§7[nl] Operations/tick: §f%s§7 +oc:tooltip.HoverBoots=Jump higher, fall deeper, walk better. This and more, with the new and patented Hover Boots (TM). oc:tooltip.InkCartridge=Used to refill ink in 3D printers. For mysterious reasons it does not have to remain in the printer. oc:tooltip.InkCartridgeEmpty=This ink cartridge has been sucked dry. Refill it using dyes. Or throw it away. See if I care. oc:tooltip.InternetCard=This card allows making HTTP requests and using real TCP sockets. diff --git a/src/main/resources/assets/opencomputers/recipes/default.recipes b/src/main/resources/assets/opencomputers/recipes/default.recipes index 0f75a6e11..f7982a03d 100644 --- a/src/main/resources/assets/opencomputers/recipes/default.recipes +++ b/src/main/resources/assets/opencomputers/recipes/default.recipes @@ -6,15 +6,20 @@ analyzer { ["oc:materialTransistor", nuggetGold, ""] ["oc:materialCircuitBoardPrinted", nuggetGold, ""]] } -texturePicker { - input: [[dyeBlack, dyeRed, dyeGreen] - [dyeBlue, "oc:analyzer", dyePurple] - [dyeYellow, dyeMagenta, dyeWhite]] +hoverBoots { + input: [[nuggetIron, "oc:hoverUpgrade1", nuggetIron] + [leather, "oc:droneCase1", leather] + [nuggetIron, "oc:capacitor", nuggetIron]] } manual { type: shapeless input: [book, "oc:circuitChip1"] } +texturePicker { + input: [[dyeBlack, dyeRed, dyeGreen] + [dyeBlue, "oc:analyzer", dyePurple] + [dyeYellow, dyeMagenta, dyeWhite]] +} wrench { input: [[ingotIron, "", ingotIron] ["", "oc:circuitChip2", ""], diff --git a/src/main/resources/assets/opencomputers/textures/items/HoverBoots.png b/src/main/resources/assets/opencomputers/textures/items/HoverBoots.png new file mode 100644 index 0000000000000000000000000000000000000000..0096a1ccd3efc4d3497d3fe6abee70ce87e9c6cb GIT binary patch literal 461 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8t^l79S8+q*m@o@xd(EO8?}|$mMjl?~Ch9y=(%$Z-<|ayM zXVO${?FE%pr`?(6=V{Pf6UHYer>iC75E7=LCh1_KYiFf8r6;NRTC=f%imtW-r-&#k zH;;&xwzautY`C?eyl6(EtD=JVf|+W&?;-@+4k~$6Ts>-doMXcl$7!B3n@)AM99-lR#vtSraKv9? zkClDf*4D$qtFvZ&DLA||xzyn0V^Q(Wp5*1{87`TW{Nky5u6%%Dw}#}5bwTE!_+jvL L^>bP0l+XkKJ_Evk literal 0 HcmV?d00001 diff --git a/src/main/scala/li/cil/oc/Constants.scala b/src/main/scala/li/cil/oc/Constants.scala index 388173e53..413ceff3d 100644 --- a/src/main/scala/li/cil/oc/Constants.scala +++ b/src/main/scala/li/cil/oc/Constants.scala @@ -95,6 +95,7 @@ object Constants { final val HDDTier1 = "hdd1" final val HDDTier2 = "hdd2" final val HDDTier3 = "hdd3" + final val HoverBoots = "hoverBoots" final val HoverUpgradeTier1 = "hoverUpgrade1" final val HoverUpgradeTier2 = "hoverUpgrade2" final val InkCartridgeEmpty = "inkCartridgeEmpty" diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index 209417474..c760c8b38 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -153,6 +153,7 @@ class Settings(val config: Config) { val bufferAccessPoint = config.getDouble("power.buffer.accessPoint") max 0 val bufferDrone = config.getDouble("power.buffer.drone") max 0 val bufferMicrocontroller = config.getDouble("power.buffer.mcu") max 0 + val bufferHoverBoots = config.getDouble("power.buffer.hoverBoots") max 1 // power.cost val computerCost = config.getDouble("power.cost.computer") max 0 @@ -187,6 +188,9 @@ class Settings(val config: Config) { val pistonCost = config.getDouble("power.cost.pistonPush") max 0 val eepromWriteCost = config.getDouble("power.cost.eepromWrite") max 0 val printCost = config.getDouble("power.cost.printerModel") max 0 + val hoverBootJump = config.getDouble("power.cost.hoverBootJump") max 0 + val hoverBootAbsorb = config.getDouble("power.cost.hoverBootAbsorb") max 0 + val hoverBootMove = config.getDouble("power.cost.hoverBootMove") max 0 // power.rate val accessPointRate = config.getDouble("power.rate.accessPoint") max 0 diff --git a/src/main/scala/li/cil/oc/client/renderer/item/HoverBootRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/item/HoverBootRenderer.scala new file mode 100644 index 000000000..86fc6c72a --- /dev/null +++ b/src/main/scala/li/cil/oc/client/renderer/item/HoverBootRenderer.scala @@ -0,0 +1,109 @@ +package li.cil.oc.client.renderer.item + +import li.cil.oc.Settings +import li.cil.oc.util.RenderState +import net.minecraft.client.model.ModelBase +import net.minecraft.client.model.ModelBiped +import net.minecraft.client.model.ModelRenderer +import net.minecraft.util.ResourceLocation +import org.lwjgl.opengl.GL11 + +object HoverBootRenderer extends ModelBiped { + val texture = new ResourceLocation(Settings.resourceDomain, "textures/model/drone.png") + + val bootLeft = new ModelRenderer(this, "bootLeft") + val bootRight = new ModelRenderer(this, "bootRight") + val body = new ModelRenderer(this, "body") + val wing0 = new ModelRenderer(this, "wing0") + val wing1 = new ModelRenderer(this, "wing1") + val wing2 = new ModelRenderer(this, "wing2") + val wing3 = new ModelRenderer(this, "wing3") + val light0 = new LightModelRenderer(this, "light0") + val light1 = new LightModelRenderer(this, "light1") + val light2 = new LightModelRenderer(this, "light2") + val light3 = new LightModelRenderer(this, "light3") + + bootLeft.addChild(body) + bootLeft.addChild(wing0) + bootLeft.addChild(wing1) + + bootRight.addChild(body) + bootRight.addChild(wing2) + bootRight.addChild(wing3) + + wing0.addChild(light0) + wing1.addChild(light1) + wing2.addChild(light2) + wing3.addChild(light3) + + textureWidth = 64 + textureHeight = 32 + + setTextureOffset("body.middle", 0, 23) + setTextureOffset("body.top", 0, 1) + setTextureOffset("body.bottom", 0, 17) + setTextureOffset("wing0.flap0", 0, 9) + setTextureOffset("wing0.pin0", 0, 27) + setTextureOffset("wing1.flap1", 0, 9) + setTextureOffset("wing1.pin1", 0, 27) + setTextureOffset("wing2.flap2", 0, 9) + setTextureOffset("wing2.pin2", 0, 27) + setTextureOffset("wing3.flap3", 0, 9) + setTextureOffset("wing3.pin3", 0, 27) + + setTextureOffset("light0.flap0", 24, 0) + setTextureOffset("light1.flap1", 24, 0) + setTextureOffset("light2.flap2", 24, 0) + setTextureOffset("light3.flap3", 24, 0) + + bootRight.offsetY = 10.1f / 16 + bootLeft.offsetY = 10.11f / 16f + + body.addBox("top", -3, 1, -3, 6, 1, 6).rotateAngleY = math.toRadians(45).toFloat + body.addBox("middle", -1, 0, -1, 2, 1, 2).rotateAngleY = math.toRadians(45).toFloat + body.addBox("bottom", -2, -1, -2, 4, 1, 4).rotateAngleY = math.toRadians(45).toFloat + wing0.addBox("flap0", -1, 0, -7, 6, 1, 6) + wing0.addBox("pin0", 0, -1, -3, 1, 3, 1) + wing1.addBox("flap1", -1, 0, 1, 6, 1, 6) + wing1.addBox("pin1", 0, -1, 2, 1, 3, 1) + wing2.addBox("flap2", -5, 0, 1, 6, 1, 6) + wing2.addBox("pin2", -1, -1, 2, 1, 3, 1) + wing3.addBox("flap3", -5, 0, -7, 6, 1, 6) + wing3.addBox("pin3", -1, -1, -3, 1, 3, 1) + + light0.addBox("flap0", -1, 0, -7, 6, 1, 6) + light1.addBox("flap1", -1, 0, 1, 6, 1, 6) + light2.addBox("flap2", -5, 0, 1, 6, 1, 6) + light3.addBox("flap3", -5, 0, -7, 6, 1, 6) + + // No drone textured legs, thank you very much. + bipedLeftLeg.cubeList.clear() + bipedRightLeg.cubeList.clear() + + bipedLeftLeg.addChild(bootLeft) + bipedRightLeg.addChild(bootRight) + + bipedHead.isHidden = true + bipedHeadwear.isHidden = true + bipedBody.isHidden = true + bipedRightArm.isHidden = true + bipedLeftArm.isHidden = true + bipedEars.isHidden = true + bipedCloak.isHidden = true + + class LightModelRenderer(modelBase: ModelBase, name: String) extends ModelRenderer(modelBase, name) { + override def render(dt: Float): Unit = { + RenderState.disableLighting() + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS) + GL11.glDepthFunc(GL11.GL_LEQUAL) + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE) + GL11.glColor3ub(0x66.toByte, 0xDD.toByte, 0x55.toByte) + + super.render(dt) + + RenderState.enableLighting() + GL11.glPopAttrib() + } + } + +} diff --git a/src/main/scala/li/cil/oc/common/event/HoverBootsHandler.scala b/src/main/scala/li/cil/oc/common/event/HoverBootsHandler.scala new file mode 100644 index 000000000..ebc32ec63 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/event/HoverBootsHandler.scala @@ -0,0 +1,73 @@ +package li.cil.oc.common.event + +import cpw.mods.fml.common.eventhandler.SubscribeEvent +import li.cil.oc.Settings +import li.cil.oc.common.item.HoverBoots +import net.minecraft.entity.player.EntityPlayer +import net.minecraftforge.common.util.FakePlayer +import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent +import net.minecraftforge.event.entity.living.LivingFallEvent + +object HoverBootsHandler { + @SubscribeEvent + def onLivingUpdate(e: LivingUpdateEvent): Unit = e.entity match { + case player: EntityPlayer if !player.isInstanceOf[FakePlayer] => + val nbt = player.getEntityData + val hadHoverBoots = nbt.getBoolean(Settings.namespace + "hasHoverBoots") + val hasHoverBoots = !player.isSneaking && equippedArmor(player).exists(stack => stack.getItem match { + case boots: HoverBoots => + if (player.onGround && player.worldObj.getTotalWorldTime % 20 == 0) { + val velocity = player.motionX * player.motionX + player.motionY * player.motionY + player.motionZ * player.motionZ + if (velocity > 0.015f) { + boots.charge(stack, -Settings.get.hoverBootMove, simulate = false) + } + } + boots.getCharge(stack) > 0 + case _ => false + }) + if (hasHoverBoots != hadHoverBoots) { + nbt.setBoolean(Settings.namespace + "hasHoverBoots", hasHoverBoots) + player.stepHeight = if (hasHoverBoots) 1f else 0.5f + } + if (hasHoverBoots && !player.onGround && player.fallDistance < 5 && player.motionY < 0) { + player.motionY *= 0.9f + } + case _ => // Ignore. + } + + @SubscribeEvent + def onLivingJump(e: LivingJumpEvent): Unit = e.entity match { + case player: EntityPlayer if !player.isInstanceOf[FakePlayer] && !player.isSneaking => + equippedArmor(player).collectFirst { + case stack if stack.getItem.isInstanceOf[HoverBoots] => + val boots = stack.getItem.asInstanceOf[HoverBoots] + val hoverJumpCost = -Settings.get.hoverBootJump + if (boots.charge(stack, hoverJumpCost, simulate = true) == 0) { + boots.charge(stack, hoverJumpCost, simulate = false) + if (player.isSprinting) + player.addVelocity(player.motionX * 0.5, 0.4, player.motionZ * 0.5) + else + player.addVelocity(0, 0.4, 0) + } + } + case _ => // Ignore. + } + + @SubscribeEvent + def onLivingFall(e: LivingFallEvent): Unit = if (e.distance > 3) e.entity match { + case player: EntityPlayer if !player.isInstanceOf[FakePlayer] => + equippedArmor(player).collectFirst { + case stack if stack.getItem.isInstanceOf[HoverBoots] => + val boots = stack.getItem.asInstanceOf[HoverBoots] + val hoverFallCost = -Settings.get.hoverBootAbsorb + if (boots.charge(stack, hoverFallCost, simulate = true) == 0) { + boots.charge(stack, hoverFallCost, simulate = false) + e.distance *= 0.3f + } + } + case _ => // Ignore. + } + + private def equippedArmor(player: EntityPlayer) = (1 to 4).map(player.getEquipmentInSlot).filter(_ != null) +} diff --git a/src/main/scala/li/cil/oc/common/init/Items.scala b/src/main/scala/li/cil/oc/common/init/Items.scala index 21c65db9f..17f170b11 100644 --- a/src/main/scala/li/cil/oc/common/init/Items.scala +++ b/src/main/scala/li/cil/oc/common/init/Items.scala @@ -18,6 +18,7 @@ import li.cil.oc.common.item.Delegator import li.cil.oc.common.item.SimpleItem import li.cil.oc.common.item.UpgradeLeash import li.cil.oc.common.item.data.DroneData +import li.cil.oc.common.item.data.HoverBootsData import li.cil.oc.common.item.data.MicrocontrollerData import li.cil.oc.common.item.data.RobotData import li.cil.oc.common.item.data.TabletData @@ -307,6 +308,16 @@ object Items extends ItemAPI { stack } + def createChargedHoverBoots() = { + val data = new HoverBootsData() + data.charge = Settings.get.bufferHoverBoots + + val stack = get(Constants.ItemName.HoverBoots).createItemStack(1) + data.save(stack) + + stack + } + // ----------------------------------------------------------------------- // // Crafting @@ -316,7 +327,8 @@ object Items extends ItemAPI { createConfiguredDrone(), createConfiguredMicrocontroller(), createConfiguredRobot(), - createConfiguredTablet() + createConfiguredTablet(), + createChargedHoverBoots() ) ++ Loot.disksForClient ++ registeredItems override def getSubItems(item: Item, tab: CreativeTabs, list: java.util.List[_]) { @@ -517,5 +529,8 @@ object Items extends ItemAPI { // 1.5.10 Recipes.addSubItem(new item.APU(multi, Tier.One), Constants.ItemName.APUTier1, "oc:apu1") Recipes.addSubItem(new item.APU(multi, Tier.Two), Constants.ItemName.APUTier2, "oc:apu2") + + // 1.5.11 + Recipes.addItem(new item.HoverBoots(), Constants.ItemName.HoverBoots, "oc:hoverBoots") } } diff --git a/src/main/scala/li/cil/oc/common/item/HoverBoots.scala b/src/main/scala/li/cil/oc/common/item/HoverBoots.scala new file mode 100644 index 000000000..64c5faf8d --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/HoverBoots.scala @@ -0,0 +1,69 @@ +package li.cil.oc.common.item + +import li.cil.oc.Settings +import li.cil.oc.client.renderer.item.HoverBootRenderer +import li.cil.oc.common.item.data.HoverBootsData +import net.minecraft.client.model.ModelBiped +import net.minecraft.entity.Entity +import net.minecraft.entity.EntityLivingBase +import net.minecraft.item.EnumRarity +import net.minecraft.item.ItemArmor +import net.minecraft.item.ItemStack + +class HoverBoots extends ItemArmor(ItemArmor.ArmorMaterial.DIAMOND, 0, 3) with SimpleItem with traits.Chargeable { + setNoRepair() + + override def getRarity(stack: ItemStack): EnumRarity = EnumRarity.uncommon + + override def maxCharge(stack: ItemStack) = Settings.get.bufferHoverBoots + + override def getCharge(stack: ItemStack): Double = + new HoverBootsData(stack).charge + + override def setCharge(stack: ItemStack, amount: Double): Unit = { + val data = new HoverBootsData(stack) + data.charge = math.min(maxCharge(stack), math.max(0, amount)) + data.save(stack) + } + + override def canCharge(stack: ItemStack): Boolean = true + + override def charge(stack: ItemStack, amount: Double, simulate: Boolean): Double = { + val data = new HoverBootsData(stack) + if (amount < 0) { + val remainder = math.min(0, data.charge + amount) + if (!simulate) { + data.charge = math.max(0, data.charge + amount) + data.save(stack) + } + remainder + } + else { + val remainder = -math.min(0, Settings.get.bufferHoverBoots - (data.charge + amount)) + if (!simulate) { + data.charge = math.min(Settings.get.bufferHoverBoots, data.charge + amount) + data.save(stack) + } + remainder + } + } + + override def getArmorModel(entityLiving: EntityLivingBase, itemStack: ItemStack, armorSlot: Int): ModelBiped = { + if (armorSlot == armorType) HoverBootRenderer + else super.getArmorModel(entityLiving, itemStack, armorSlot) + } + + override def getArmorTexture(stack: ItemStack, entity: Entity, slot: Int, subType: String): String = { + HoverBootRenderer.texture.toString + } + + override def getDisplayDamage(stack: ItemStack): Int = { + val data = new HoverBootsData(stack) + (Settings.get.bufferHoverBoots * (1 - data.charge / Settings.get.bufferHoverBoots)).toInt + } + + override def getMaxDamage(stack: ItemStack): Int = Settings.get.bufferHoverBoots.toInt + + // Always show energy bar. + override def isDamaged(stack: ItemStack): Boolean = true +} diff --git a/src/main/scala/li/cil/oc/common/item/RemoteControl.scala b/src/main/scala/li/cil/oc/common/item/RemoteControl.scala new file mode 100644 index 000000000..eafc01890 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/RemoteControl.scala @@ -0,0 +1,11 @@ +package li.cil.oc.common.item + +import li.cil.oc.util.BlockPosition +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack + +class RemoteControl(val parent: Delegator) extends Delegate { + override def onItemUse(stack: ItemStack, player: EntityPlayer, position: BlockPosition, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = { + super.onItemUse(stack, player, position, side, hitX, hitY, hitZ) + } +} diff --git a/src/main/scala/li/cil/oc/common/item/data/HoverBootsData.scala b/src/main/scala/li/cil/oc/common/item/data/HoverBootsData.scala new file mode 100644 index 000000000..507e69337 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/data/HoverBootsData.scala @@ -0,0 +1,22 @@ +package li.cil.oc.common.item.data + +import li.cil.oc.Settings +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound + +class HoverBootsData extends ItemData { + def this(stack: ItemStack) { + this() + load(stack) + } + + var charge = 0.0 + + override def load(nbt: NBTTagCompound) { + charge = nbt.getDouble(Settings.namespace + "charge") + } + + override def save(nbt: NBTTagCompound) { + nbt.setDouble(Settings.namespace + "charge", charge) + } +} diff --git a/src/main/scala/li/cil/oc/common/item/traits/Chargeable.scala b/src/main/scala/li/cil/oc/common/item/traits/Chargeable.scala new file mode 100644 index 000000000..ff2b9af2e --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/traits/Chargeable.scala @@ -0,0 +1,96 @@ +package li.cil.oc.common.item.traits + +import appeng.api.config.AccessRestriction +import cpw.mods.fml.common.Optional +import ic2.api.item.IElectricItemManager +import li.cil.oc.Settings +import li.cil.oc.api +import li.cil.oc.common.asm.Injectable +import li.cil.oc.integration.Mods +import li.cil.oc.integration.ic2.ElectricItemManager +import net.minecraft.item.Item +import net.minecraft.item.ItemStack + +@Injectable.InterfaceList(Array( + new Injectable.Interface(value = "appeng.api.implementations.items.IAEItemPowerStorage", modid = Mods.IDs.AppliedEnergistics2), + new Injectable.Interface(value = "cofh.api.energy.IEnergyContainerItem", modid = Mods.IDs.CoFHEnergy), + new Injectable.Interface(value = "ic2.api.item.ISpecialElectricItem", modid = Mods.IDs.IndustrialCraft2), + new Injectable.Interface(value = "mekanism.api.energy.IEnergizedItem", modid = Mods.IDs.Mekanism) +)) +trait Chargeable extends api.driver.item.Chargeable { + def maxCharge(stack: ItemStack): Double + + def getCharge(stack: ItemStack): Double + + def setCharge(stack: ItemStack, amount: Double): Unit + + // Applied Energistics 2 + + def getAECurrentPower(stack: ItemStack): Double = + getCharge(stack) / Settings.get.ratioAppliedEnergistics2 + + def getAEMaxPower(stack: ItemStack): Double = + maxCharge(stack) / Settings.get.ratioAppliedEnergistics2 + + def injectAEPower(stack: ItemStack, value: Double): Double = + (charge(stack, value * Settings.get.ratioAppliedEnergistics2, false) / Settings.get.ratioAppliedEnergistics2).toInt + + def extractAEPower(stack: ItemStack, value: Double): Double = + value - (charge(stack, -value * Settings.get.ratioAppliedEnergistics2, false) / Settings.get.ratioAppliedEnergistics2).toInt + + @Optional.Method(modid = Mods.IDs.AppliedEnergistics2) + def getPowerFlow(stack: ItemStack): AccessRestriction = AccessRestriction.WRITE + + // IndustrialCraft 2 + + @Optional.Method(modid = Mods.IDs.IndustrialCraft2) + def getManager(stack: ItemStack): IElectricItemManager = ElectricItemManager + + def getMaxCharge(stack: ItemStack): Double = + maxCharge(stack) / Settings.get.ratioIndustrialCraft2 + + def getTransferLimit(stack: ItemStack): Double = + Settings.get.chargeRateTablet / Settings.get.ratioIndustrialCraft2 + + def getTier(stack: ItemStack): Int = 1 + + def canProvideEnergy(stack: ItemStack): Boolean = false + + def getEmptyItem(stack: ItemStack): Item = stack.getItem + + def getChargedItem(stack: ItemStack): Item = stack.getItem + + // Mekanism + + def getEnergy(stack: ItemStack): Double = + getCharge(stack) / Settings.get.ratioMekanism + + def setEnergy(stack: ItemStack, amount: Double): Unit = + setCharge(stack, amount * Settings.get.ratioMekanism) + + def getMaxEnergy(stack: ItemStack): Double = + maxCharge(stack) / Settings.get.ratioMekanism + + def canSend(stack: ItemStack): Boolean = false + + def canReceive(stack: ItemStack): Boolean = true + + def isMetadataSpecific(stack: ItemStack): Boolean = false + + def getMaxTransfer(stack: ItemStack): Double = + Settings.get.chargeRateTablet / Settings.get.ratioMekanism + + // Redstone Flux + + def getEnergyStored(stack: ItemStack): Int = + (getCharge(stack) / Settings.get.ratioRedstoneFlux).toInt + + def getMaxEnergyStored(stack: ItemStack): Int = + (maxCharge(stack) / Settings.get.ratioRedstoneFlux).toInt + + def receiveEnergy(stack: ItemStack, maxReceive: Int, simulate: Boolean): Int = + maxReceive - (charge(stack, maxReceive * Settings.get.ratioRedstoneFlux, simulate) / Settings.get.ratioRedstoneFlux).toInt + + def extractEnergy(stack: ItemStack, maxExtract: Int, simulate: Boolean): Int = + maxExtract - (charge(stack, -maxExtract * Settings.get.ratioRedstoneFlux, simulate) / Settings.get.ratioRedstoneFlux).toInt +} diff --git a/src/main/scala/li/cil/oc/integration/ic2/ElectricItemManager.scala b/src/main/scala/li/cil/oc/integration/ic2/ElectricItemManager.scala new file mode 100644 index 000000000..a7bd53c8c --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/ic2/ElectricItemManager.scala @@ -0,0 +1,44 @@ +package li.cil.oc.integration.ic2 + +import ic2.api.item.IElectricItemManager +import li.cil.oc.Settings +import li.cil.oc.api.driver.item.Chargeable +import li.cil.oc.common.item.HoverBoots +import li.cil.oc.common.item.data.HoverBootsData +import net.minecraft.entity.EntityLivingBase +import net.minecraft.item.ItemStack + +object ElectricItemManager extends IElectricItemManager { + override def getCharge(stack: ItemStack): Double = { + if (stack == null) 0 + else stack.getItem match { + // TODO in OC 1.6, add a getCharge method to Chargeable and use that instead. + case hoverBoots: HoverBoots => new HoverBootsData(stack).charge + case _ => 0 + } + } + + override def charge(stack: ItemStack, amount: Double, tier: Int, ignoreTransferLimit: Boolean, simulate: Boolean): Double = { + if (stack == null) 0 + else stack.getItem match { + case chargeable: Chargeable => + val limitedAmount = if (ignoreTransferLimit) math.min(Int.MaxValue, amount) else math.min(amount, Settings.get.chargeRateTablet) + limitedAmount - chargeable.charge(stack, limitedAmount * Settings.get.ratioIndustrialCraft2, simulate) / Settings.get.ratioIndustrialCraft2 + case _ => 0 + } + } + + override def discharge(stack: ItemStack, amount: Double, tier: Int, ignoreTransferLimit: Boolean, externally: Boolean, simulate: Boolean): Double = { + 0.0 // TODO if we ever need it... + } + + override def chargeFromArmor(stack: ItemStack, entity: EntityLivingBase): Unit = {} + + override def canUse(stack: ItemStack, amount: Double): Boolean = getCharge(stack) >= amount + + override def use(stack: ItemStack, amount: Double, entity: EntityLivingBase): Boolean = canUse(stack, amount) && { + false // TODO if we ever need it... + } + + override def getToolTip(stack: ItemStack): String = null +} diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala index 3997dc7be..837c27367 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -75,6 +75,7 @@ object ModOpenComputers extends ModProxy { MinecraftForge.EVENT_BUS.register(ExperienceUpgradeHandler) MinecraftForge.EVENT_BUS.register(FileSystemAccessHandler) MinecraftForge.EVENT_BUS.register(GeolyzerHandler) + MinecraftForge.EVENT_BUS.register(HoverBootsHandler) MinecraftForge.EVENT_BUS.register(Loot) MinecraftForge.EVENT_BUS.register(RobotCommonHandler) MinecraftForge.EVENT_BUS.register(SaveHandler)