From f154295b5ed8d772f20690b14f8b8061cad72741 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sat, 27 May 2023 16:57:09 +0200 Subject: [PATCH] feat: implement duplicator --- .clang-format | 2 +- .../net/anvilcraft/thaummach/ClientProxy.java | 7 + .../net/anvilcraft/thaummach/CommonProxy.java | 6 + .../java/net/anvilcraft/thaummach/GuiID.java | 1 + .../thaummach/ThaumicMachinery.java | 29 +- .../blocks/BlockApparatusFragile.java | 4 +- .../thaummach/blocks/BlockApparatusWood.java | 98 ++-- .../container/ContainerDuplicator.java | 85 +++ .../thaummach/gui/GuiDuplicator.java | 82 +++ .../packets/PacketDuplicatorPress.java | 82 +++ .../packets/PacketDuplicatorSetRepeat.java | 57 ++ .../wood/DuplicatorApparatusRenderer.java | 87 +++ .../render/model/ModelDuplicator.java | 46 ++ .../render/tile/TileDuplicatorRenderer.java | 71 +++ .../thaummach/tiles/TileDuplicator.java | 541 ++++++++++++++++++ .../resources/assets/thaummach/sounds.json | 13 + .../assets/thaummach/sounds/stomp1.ogg | Bin 0 -> 11445 bytes .../assets/thaummach/sounds/stomp2.ogg | Bin 0 -> 10384 bytes .../textures/blocks/duplicator_bottom.png | Bin 609 -> 675 bytes .../textures/blocks/duplicator_front.png | Bin 0 -> 506 bytes .../textures/blocks/duplicator_side.png | Bin 506 -> 609 bytes .../textures/blocks/duplicator_top.png | Bin 675 -> 0 bytes .../thaummach/textures/guis/duplicator.png | Bin 0 -> 5535 bytes .../thaummach/textures/models/duplicator.png | Bin 0 -> 2869 bytes 24 files changed, 1136 insertions(+), 75 deletions(-) create mode 100644 src/main/java/net/anvilcraft/thaummach/container/ContainerDuplicator.java create mode 100644 src/main/java/net/anvilcraft/thaummach/gui/GuiDuplicator.java create mode 100644 src/main/java/net/anvilcraft/thaummach/packets/PacketDuplicatorPress.java create mode 100644 src/main/java/net/anvilcraft/thaummach/packets/PacketDuplicatorSetRepeat.java create mode 100644 src/main/java/net/anvilcraft/thaummach/render/apparatus/apparati/wood/DuplicatorApparatusRenderer.java create mode 100644 src/main/java/net/anvilcraft/thaummach/render/model/ModelDuplicator.java create mode 100644 src/main/java/net/anvilcraft/thaummach/render/tile/TileDuplicatorRenderer.java create mode 100644 src/main/java/net/anvilcraft/thaummach/tiles/TileDuplicator.java create mode 100644 src/main/resources/assets/thaummach/sounds/stomp1.ogg create mode 100644 src/main/resources/assets/thaummach/sounds/stomp2.ogg create mode 100644 src/main/resources/assets/thaummach/textures/blocks/duplicator_front.png delete mode 100644 src/main/resources/assets/thaummach/textures/blocks/duplicator_top.png create mode 100644 src/main/resources/assets/thaummach/textures/guis/duplicator.png create mode 100644 src/main/resources/assets/thaummach/textures/models/duplicator.png diff --git a/.clang-format b/.clang-format index d48bed8..bffc64f 100644 --- a/.clang-format +++ b/.clang-format @@ -52,7 +52,7 @@ BreakBeforeTernaryOperators: true BreakConstructorInitializers: AfterColon BreakInheritanceList: AfterColon BreakStringLiterals: true -ColumnLimit: 90 +ColumnLimit: 100 CompactNamespaces: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 diff --git a/src/main/java/net/anvilcraft/thaummach/ClientProxy.java b/src/main/java/net/anvilcraft/thaummach/ClientProxy.java index 6166ebc..0b9f430 100644 --- a/src/main/java/net/anvilcraft/thaummach/ClientProxy.java +++ b/src/main/java/net/anvilcraft/thaummach/ClientProxy.java @@ -9,6 +9,7 @@ import net.anvilcraft.thaummach.gui.GuiArcaneFurnace; import net.anvilcraft.thaummach.gui.GuiBore; import net.anvilcraft.thaummach.gui.GuiCondenser; import net.anvilcraft.thaummach.gui.GuiCrystallizer; +import net.anvilcraft.thaummach.gui.GuiDuplicator; import net.anvilcraft.thaummach.gui.GuiGenerator; import net.anvilcraft.thaummach.gui.GuiRepairer; import net.anvilcraft.thaummach.gui.GuiSoulBrazier; @@ -20,6 +21,7 @@ import net.anvilcraft.thaummach.render.tile.TileBoreRenderer; import net.anvilcraft.thaummach.render.tile.TileCondenserRenderer; import net.anvilcraft.thaummach.render.tile.TileConduitPumpRenderer; import net.anvilcraft.thaummach.render.tile.TileCrystallizerRenderer; +import net.anvilcraft.thaummach.render.tile.TileDuplicatorRenderer; import net.anvilcraft.thaummach.render.tile.TileGeneratorRenderer; import net.anvilcraft.thaummach.render.tile.TileRepairerRenderer; import net.anvilcraft.thaummach.render.tile.TileSealRenderer; @@ -35,6 +37,7 @@ import net.anvilcraft.thaummach.tiles.TileConduitValve; import net.anvilcraft.thaummach.tiles.TileConduitValveAdvanced; import net.anvilcraft.thaummach.tiles.TileCrucible; import net.anvilcraft.thaummach.tiles.TileCrystallizer; +import net.anvilcraft.thaummach.tiles.TileDuplicator; import net.anvilcraft.thaummach.tiles.TileFilter; import net.anvilcraft.thaummach.tiles.TileGenerator; import net.anvilcraft.thaummach.tiles.TilePurifier; @@ -77,6 +80,7 @@ public class ClientProxy extends CommonProxy { ClientRegistry.registerTileEntity(TileCondenser.class, "condenser", new TileCondenserRenderer()); ClientRegistry.registerTileEntity(TileConduitPump.class, "conduit_pump", new TileConduitPumpRenderer()); ClientRegistry.registerTileEntity(TileCrystallizer.class, "crystallizer", new TileCrystallizerRenderer()); + ClientRegistry.registerTileEntity(TileDuplicator.class, "duplicator", new TileDuplicatorRenderer()); ClientRegistry.registerTileEntity(TileGenerator.class, "generator", new TileGeneratorRenderer()); ClientRegistry.registerTileEntity(TileRepairer.class, "repairer", new TileRepairerRenderer()); ClientRegistry.registerTileEntity(TileSeal.class, "seal", new TileSealRenderer()); @@ -102,6 +106,9 @@ public class ClientProxy extends CommonProxy { case CRYSTALLIZER: return new GuiCrystallizer(player.inventory, (TileCrystallizer) te); + case DUPLICATOR: + return new GuiDuplicator(player.inventory, (TileDuplicator) te); + case GENERATOR: return new GuiGenerator((TileGenerator) te); diff --git a/src/main/java/net/anvilcraft/thaummach/CommonProxy.java b/src/main/java/net/anvilcraft/thaummach/CommonProxy.java index d7dd193..7e3e7c0 100644 --- a/src/main/java/net/anvilcraft/thaummach/CommonProxy.java +++ b/src/main/java/net/anvilcraft/thaummach/CommonProxy.java @@ -6,6 +6,7 @@ import net.anvilcraft.thaummach.container.ContainerArcaneFurnace; import net.anvilcraft.thaummach.container.ContainerBore; import net.anvilcraft.thaummach.container.ContainerCondenser; import net.anvilcraft.thaummach.container.ContainerCrystallizer; +import net.anvilcraft.thaummach.container.ContainerDuplicator; import net.anvilcraft.thaummach.container.ContainerRepairer; import net.anvilcraft.thaummach.container.ContainerSoulBrazier; import net.anvilcraft.thaummach.container.ContainerVoidChest; @@ -20,6 +21,7 @@ import net.anvilcraft.thaummach.tiles.TileConduitValve; import net.anvilcraft.thaummach.tiles.TileConduitValveAdvanced; import net.anvilcraft.thaummach.tiles.TileCrucible; import net.anvilcraft.thaummach.tiles.TileCrystallizer; +import net.anvilcraft.thaummach.tiles.TileDuplicator; import net.anvilcraft.thaummach.tiles.TileFilter; import net.anvilcraft.thaummach.tiles.TileGenerator; import net.anvilcraft.thaummach.tiles.TilePurifier; @@ -50,6 +52,7 @@ public class CommonProxy implements IGuiHandler { GameRegistry.registerTileEntity(TileConduitValveAdvanced.class, "conduit_valve_advanced"); GameRegistry.registerTileEntity(TileCrucible.class, "crucible"); GameRegistry.registerTileEntity(TileCrystallizer.class, "crystallizer"); + GameRegistry.registerTileEntity(TileDuplicator.class, "duplicator"); GameRegistry.registerTileEntity(TileFilter.class, "filter"); GameRegistry.registerTileEntity(TileGenerator.class, "generator"); GameRegistry.registerTileEntity(TilePurifier.class, "purifier"); @@ -80,6 +83,9 @@ public class CommonProxy implements IGuiHandler { case CRYSTALLIZER: return new ContainerCrystallizer(player.inventory, (TileCrystallizer) te); + case DUPLICATOR: + return new ContainerDuplicator(player.inventory, (TileDuplicator) te); + case REPAIRER: return new ContainerRepairer(player.inventory, (TileRepairer) te); diff --git a/src/main/java/net/anvilcraft/thaummach/GuiID.java b/src/main/java/net/anvilcraft/thaummach/GuiID.java index 254829f..49f110b 100644 --- a/src/main/java/net/anvilcraft/thaummach/GuiID.java +++ b/src/main/java/net/anvilcraft/thaummach/GuiID.java @@ -5,6 +5,7 @@ public enum GuiID { BORE, CONDENSER, CRYSTALLIZER, + DUPLICATOR, GENERATOR, REPAIRER, SOUL_BRAZIER, diff --git a/src/main/java/net/anvilcraft/thaummach/ThaumicMachinery.java b/src/main/java/net/anvilcraft/thaummach/ThaumicMachinery.java index 70ae462..77e3dec 100644 --- a/src/main/java/net/anvilcraft/thaummach/ThaumicMachinery.java +++ b/src/main/java/net/anvilcraft/thaummach/ThaumicMachinery.java @@ -15,6 +15,8 @@ import net.anvilcraft.thaummach.entities.EntitySingularity; import net.anvilcraft.thaummach.packets.IPacketFX; import net.anvilcraft.thaummach.packets.PacketChangeVoidInterfaceChannel; import net.anvilcraft.thaummach.packets.PacketChangeVoidInterfaceContainerPage; +import net.anvilcraft.thaummach.packets.PacketDuplicatorPress; +import net.anvilcraft.thaummach.packets.PacketDuplicatorSetRepeat; import net.anvilcraft.thaummach.packets.PacketFXSparkle; import net.anvilcraft.thaummach.packets.PacketFXWisp; import net.anvilcraft.thaummach.tiles.TileSeal; @@ -39,25 +41,14 @@ public class ThaumicMachinery { public void preInit(FMLPreInitializationEvent ev) { channel = NetworkRegistry.INSTANCE.newSimpleChannel("thaummach"); int pktid = 0; - channel.registerMessage( - new PacketFXWisp.Handler(), PacketFXWisp.class, pktid++, Side.CLIENT - ); - channel.registerMessage( - new PacketFXSparkle.Handler(), PacketFXSparkle.class, pktid++, Side.CLIENT - ); - channel.registerMessage( - new PacketChangeVoidInterfaceChannel.Handler(), - PacketChangeVoidInterfaceChannel.class, - pktid++, - Side.SERVER - ); - channel.registerMessage( - new PacketChangeVoidInterfaceContainerPage.Handler(), - PacketChangeVoidInterfaceContainerPage.class, - pktid++, - Side.SERVER - ); - + // clang-format off + channel.registerMessage(new PacketChangeVoidInterfaceChannel.Handler(), PacketChangeVoidInterfaceChannel.class, pktid++, Side.SERVER); + channel.registerMessage(new PacketChangeVoidInterfaceContainerPage.Handler(), PacketChangeVoidInterfaceContainerPage.class, pktid++, Side.SERVER); + channel.registerMessage(new PacketDuplicatorPress.Handler(), PacketDuplicatorPress.class, pktid++, Side.CLIENT); + channel.registerMessage(new PacketDuplicatorSetRepeat.Handler(), PacketDuplicatorSetRepeat.class, pktid++, Side.SERVER); + channel.registerMessage(new PacketFXSparkle.Handler(), PacketFXSparkle.class, pktid++, Side.CLIENT); + channel.registerMessage(new PacketFXWisp.Handler(), PacketFXWisp.class, pktid++, Side.CLIENT); + // clang-format on NetworkRegistry.INSTANCE.registerGuiHandler(this, proxy); proxy.registerTileEntities(); diff --git a/src/main/java/net/anvilcraft/thaummach/blocks/BlockApparatusFragile.java b/src/main/java/net/anvilcraft/thaummach/blocks/BlockApparatusFragile.java index 5a217c3..e285004 100644 --- a/src/main/java/net/anvilcraft/thaummach/blocks/BlockApparatusFragile.java +++ b/src/main/java/net/anvilcraft/thaummach/blocks/BlockApparatusFragile.java @@ -5,7 +5,6 @@ import java.util.Random; import dev.tilera.auracore.api.HelperLocation; import dev.tilera.auracore.client.FXSparkle; -import net.anvilcraft.thaummach.AuraUtils; import net.anvilcraft.thaummach.render.BlockApparatusRenderer; import net.anvilcraft.thaummach.render.apparatus.IApparatusRenderer; import net.anvilcraft.thaummach.render.apparatus.apparati.fragile.ConduitApparatusRenderer; @@ -125,9 +124,8 @@ public class BlockApparatusFragile extends BlockApparatus { return ConduitPumpApparatusRenderer.INSTANCE; default: - break; + throw new IllegalArgumentException("ALEC"); } - return null; } @Override diff --git a/src/main/java/net/anvilcraft/thaummach/blocks/BlockApparatusWood.java b/src/main/java/net/anvilcraft/thaummach/blocks/BlockApparatusWood.java index 06e4a62..61a44f2 100644 --- a/src/main/java/net/anvilcraft/thaummach/blocks/BlockApparatusWood.java +++ b/src/main/java/net/anvilcraft/thaummach/blocks/BlockApparatusWood.java @@ -11,8 +11,10 @@ import net.anvilcraft.thaummach.particles.FXWisp; import net.anvilcraft.thaummach.render.BlockApparatusRenderer; import net.anvilcraft.thaummach.render.apparatus.IApparatusRenderer; import net.anvilcraft.thaummach.render.apparatus.apparati.wood.CondenserApparatusRenderer; +import net.anvilcraft.thaummach.render.apparatus.apparati.wood.DuplicatorApparatusRenderer; import net.anvilcraft.thaummach.render.apparatus.apparati.wood.RepairerApparatusRenderer; import net.anvilcraft.thaummach.tiles.TileCondenser; +import net.anvilcraft.thaummach.tiles.TileDuplicator; import net.anvilcraft.thaummach.tiles.TileRepairer; import net.minecraft.block.Block; import net.minecraft.block.material.Material; @@ -42,9 +44,9 @@ public class BlockApparatusWood extends BlockApparatus { public IIcon[] iconsDuskTotemSide; public IIcon iconDuplicatorBottom; + public IIcon iconDuplicatorFront; public IIcon iconDuplicatorInside; public IIcon iconDuplicatorSide; - public IIcon iconDuplicatorTop; public IIcon iconRestorerBottom; public IIcon iconRestorerSide; @@ -79,9 +81,9 @@ public class BlockApparatusWood extends BlockApparatus { .toArray(IIcon[] ::new); this.iconDuplicatorBottom = reg.apply("duplicator_bottom"); - this.iconDuplicatorSide = reg.apply("duplicator_side"); + this.iconDuplicatorFront = reg.apply("duplicator_front"); this.iconDuplicatorInside = reg.apply("duplicator_inside"); - this.iconDuplicatorTop = reg.apply("duplicator_top"); + this.iconDuplicatorSide = reg.apply("duplicator_side"); this.iconRestorerBottom = reg.apply("restorer_bottom"); this.iconRestorerSide = reg.apply("restorer_side"); @@ -98,7 +100,11 @@ public class BlockApparatusWood extends BlockApparatus { case REPAIRER: return RepairerApparatusRenderer.INSTANCE; + case DUPLICATOR: + return DuplicatorApparatusRenderer.INSTANCE; + default: + //throw new IllegalArgumentException("ALEC"); return null; } } @@ -106,11 +112,9 @@ public class BlockApparatusWood extends BlockApparatus { @Override @SuppressWarnings({ "rawtypes", "unchecked" }) public void getSubBlocks(Item p_149666_1_, CreativeTabs p_149666_2_, List itemList) { - itemList.add(new ItemStack(this, 1, 0)); - itemList.add(new ItemStack(this, 1, 1)); - itemList.add(new ItemStack(this, 1, 2)); - itemList.add(new ItemStack(this, 1, 3)); - itemList.add(new ItemStack(this, 1, 4)); + IntStream.rangeClosed(0, 4) + .mapToObj((m) -> new ItemStack(this, 1, m)) + .forEach(itemList::add); } @Override @@ -124,9 +128,9 @@ public class BlockApparatusWood extends BlockApparatus { case REPAIRER: return new TileRepairer(); - //case DUPLICATOR: - // return new TileDuplicator(); - // + case DUPLICATOR: + return new TileDuplicator(); + //case REPAIRER: // return new TileRepairer(); @@ -136,8 +140,7 @@ public class BlockApparatusWood extends BlockApparatus { } @Override - public void - setBlockBoundsBasedOnState(IBlockAccess iblockaccess, int i, int j, int k) { + public void setBlockBoundsBasedOnState(IBlockAccess iblockaccess, int i, int j, int k) { int md = iblockaccess.getBlockMetadata(i, j, k); if (md == 0) { float w3 = 0.1875F; @@ -153,12 +156,7 @@ public class BlockApparatusWood extends BlockApparatus { if (md == 0) { float w3 = 0.1875F; AxisAlignedBB.getBoundingBox( - (double) w3, - 0.0, - (double) w3, - (double) (1.0F - w3), - 1.0, - (double) (1.0F - w3) + (double) w3, 0.0, (double) w3, (double) (1.0F - w3), 1.0, (double) (1.0F - w3) ); } else if (md == 10) { AxisAlignedBB.getBoundingBox(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); @@ -169,17 +167,15 @@ public class BlockApparatusWood extends BlockApparatus { @Override public void onBlockPlacedBy( - World world, int i, int j, int k, EntityLivingBase entityliving, ItemStack stack + World world, int x, int y, int z, EntityLivingBase entityliving, ItemStack stack ) { - MetaVals md = MetaVals.get(world.getBlockMetadata(i, j, k)); - int l = MathHelper.floor_double( - (double) (entityliving.rotationYaw * 4.0F / 360.0F) + 0.5 - ) - & 3; + MetaVals md = MetaVals.get(world.getBlockMetadata(x, y, z)); if (md == MetaVals.DUPLICATOR) { - // TODO: duplicator - //TileDuplicator td = (TileDuplicator) world.getBlockTileEntity(i, j, k); - //td.orientation = l; + int l + = MathHelper.floor_double((double) (entityliving.rotationYaw * 4.0F / 360.0F) + 0.5) + & 3; + TileDuplicator td = (TileDuplicator) world.getTileEntity(x, y, z); + td.orientation = l; } } @@ -248,34 +244,32 @@ public class BlockApparatusWood extends BlockApparatus { MetaVals md = MetaVals.get(iblockaccess.getBlockMetadata(i, j, k)); if (md == MetaVals.CONDENSER) { return l <= 1 ? this.iconCondenserTop : this.iconCondenserSide; - } - //else if (md == 1) { - // if (l <= 1) { - // return 70; - // } else { - // TileEntity te = iblockaccess.getBlockTileEntity(i, j, k); - // if (te != null && te instanceof TileDuplicator) { - // if (((TileDuplicator) te).orientation == 0 && l == 2) { - // return 71; - // } + } else if (md == MetaVals.DUPLICATOR) { + if (l <= 1) { + return this.iconDuplicatorBottom; + } else { + TileEntity te = iblockaccess.getTileEntity(i, j, k); + if (te != null && te instanceof TileDuplicator) { + if (((TileDuplicator) te).orientation == 0 && l == 2) { + return this.iconDuplicatorFront; + } - // if (((TileDuplicator) te).orientation == 1 && l == 5) { - // return 71; - // } + if (((TileDuplicator) te).orientation == 1 && l == 5) { + return this.iconDuplicatorFront; + } - // if (((TileDuplicator) te).orientation == 2 && l == 3) { - // return 71; - // } + if (((TileDuplicator) te).orientation == 2 && l == 3) { + return this.iconDuplicatorFront; + } - // if (((TileDuplicator) te).orientation == 3 && l == 4) { - // return 71; - // } - // } + if (((TileDuplicator) te).orientation == 3 && l == 4) { + return this.iconDuplicatorFront; + } + } - // return 72; - // } - //} - else if (md == MetaVals.REPAIRER) { + return this.iconDuplicatorSide; + } + } else if (md == MetaVals.REPAIRER) { return l <= 1 ? this.iconRestorerTop : this.iconRestorerSide; } //else if (md == 3) { diff --git a/src/main/java/net/anvilcraft/thaummach/container/ContainerDuplicator.java b/src/main/java/net/anvilcraft/thaummach/container/ContainerDuplicator.java new file mode 100644 index 0000000..da8f709 --- /dev/null +++ b/src/main/java/net/anvilcraft/thaummach/container/ContainerDuplicator.java @@ -0,0 +1,85 @@ +package net.anvilcraft.thaummach.container; + +import net.anvilcraft.thaummach.OutputSlot; +import net.anvilcraft.thaummach.tiles.TileDuplicator; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class ContainerDuplicator extends Container { + private TileDuplicator duplicator; + + public ContainerDuplicator(InventoryPlayer inventoryplayer, TileDuplicator tileEntity) { + this.duplicator = tileEntity; + this.addSlotToContainer(new Slot(tileEntity, 9, 23, 34)); + + int j; + int k; + for (j = 0; j < 3; ++j) { + for (k = 0; k < 3; ++k) { + this.addSlotToContainer( + new OutputSlot(tileEntity, k + j * 3, 90 + k * 18, 17 + j * 18) + ); + } + } + + for (j = 0; j < 3; ++j) { + for (k = 0; k < 9; ++k) { + this.addSlotToContainer( + new Slot(inventoryplayer, k + j * 9 + 9, 8 + k * 18, 84 + j * 18) + ); + } + } + + for (j = 0; j < 9; ++j) { + this.addSlotToContainer(new Slot(inventoryplayer, j, 8 + j * 18, 142)); + } + } + + @Override + public void updateProgressBar(int i, int j) { + if (i == 0) { + this.duplicator.duplicatorCopyTime = (float) j; + } + } + + @Override + public ItemStack transferStackInSlot(EntityPlayer pl, int i) { + ItemStack itemstack = null; + Slot slot = (Slot) super.inventorySlots.get(i); + if (slot != null && slot.getHasStack()) { + ItemStack itemstack1 = slot.getStack(); + itemstack = itemstack1.copy(); + if (i < 11) { + if (!this.mergeItemStack(itemstack1, 11, 37, true)) { + return null; + } + } else if (i >= 11 && i < 37) { + if (!this.mergeItemStack(itemstack1, 0, 1, false)) { + return null; + } + } else if (!this.mergeItemStack(itemstack1, 11, 37, false)) { + return null; + } + + if (itemstack1.stackSize == 0) { + slot.putStack((ItemStack) null); + } else { + slot.onSlotChanged(); + } + + if (itemstack1.stackSize == itemstack.stackSize) { + return null; + } + } + + return itemstack; + } + + @Override + public boolean canInteractWith(EntityPlayer pl) { + return true; + } +} diff --git a/src/main/java/net/anvilcraft/thaummach/gui/GuiDuplicator.java b/src/main/java/net/anvilcraft/thaummach/gui/GuiDuplicator.java new file mode 100644 index 0000000..452954b --- /dev/null +++ b/src/main/java/net/anvilcraft/thaummach/gui/GuiDuplicator.java @@ -0,0 +1,82 @@ +package net.anvilcraft.thaummach.gui; + +import net.anvilcraft.thaummach.ThaumicMachinery; +import net.anvilcraft.thaummach.container.ContainerDuplicator; +import net.anvilcraft.thaummach.packets.PacketDuplicatorSetRepeat; +import net.anvilcraft.thaummach.tiles.TileDuplicator; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +public class GuiDuplicator extends GuiContainer { + private TileDuplicator duplicatorInventory; + + public GuiDuplicator(InventoryPlayer inventoryplayer, TileDuplicator tileEntity) { + super(new ContainerDuplicator(inventoryplayer, tileEntity)); + this.duplicatorInventory = tileEntity; + } + + @Override + protected void drawGuiContainerForegroundLayer(int alec1, int alec2) { + super.fontRendererObj.drawString("Duplicator", 8, 5, 0x404040); + super.fontRendererObj.drawString("Inventory", 8, super.ySize - 96 + 2, 0x404040); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float f, int qq, int ww) { + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + super.mc.renderEngine.bindTexture( + new ResourceLocation("thaummach", "textures/guis/duplicator.png") + ); + int j = (super.width - super.xSize) / 2; + int k = (super.height - super.ySize) / 2; + this.drawTexturedModalRect(j, k, 0, 0, super.xSize, super.ySize); + int i1; + if (this.duplicatorInventory.isCooking()) { + i1 = this.duplicatorInventory.getCookProgressScaled(25); + this.drawTexturedModalRect(j + 54, k + 34, 176, 15, i1 + 1, 16); + } + + if (!this.duplicatorInventory.repeat) { + this.drawTexturedModalRect(j + 62, k + 48, 176, 0, 10, 10); + } else { + this.drawTexturedModalRect(j + 62, k + 48, 186, 0, 10, 10); + } + + if (this.duplicatorInventory.boost > 0) { + i1 = this.duplicatorInventory.getBoostScaled(); + this.drawTexturedModalRect(j + 157, k + 45 - i1, 208, 30 - i1, 7, i1); + } + + super.mc.renderEngine.bindTexture(TextureMap.locationItemsTexture); + if (this.duplicatorInventory.getUpgrades()[0] >= 0) { + this.drawTexturedModalRect( + j + 152, k + 60, 16 * this.duplicatorInventory.getUpgrades()[0], 32, 16, 16 + ); + } + } + + @Override + protected void mouseClicked(int i, int j, int k) { + super.mouseClicked(i, j, k); + int sx = (super.width - super.xSize) / 2; + int sy = (super.height - super.ySize) / 2; + int k1 = i - (sx + 62); + int l1 = j - (sy + 48); + if (k1 >= 0 && l1 >= 0 && k1 < 10 && l1 <= 10) { + Minecraft.getMinecraft().getSoundHandler().playSound( + PositionedSoundRecord.func_147674_a(new ResourceLocation("random.orb"), 1.0f) + ); + ThaumicMachinery.channel.sendToServer(new PacketDuplicatorSetRepeat( + this.duplicatorInventory.xCoord, + this.duplicatorInventory.yCoord, + this.duplicatorInventory.zCoord, + !this.duplicatorInventory.repeat + )); + } + } +} diff --git a/src/main/java/net/anvilcraft/thaummach/packets/PacketDuplicatorPress.java b/src/main/java/net/anvilcraft/thaummach/packets/PacketDuplicatorPress.java new file mode 100644 index 0000000..3079ee6 --- /dev/null +++ b/src/main/java/net/anvilcraft/thaummach/packets/PacketDuplicatorPress.java @@ -0,0 +1,82 @@ +package net.anvilcraft.thaummach.packets; + +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.anvilcraft.thaummach.particles.FXWisp; +import net.anvilcraft.thaummach.tiles.TileDuplicator; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; + +public class PacketDuplicatorPress implements IMessage { + int x; + int y; + int z; + + public PacketDuplicatorPress() {} + + public PacketDuplicatorPress(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public void fromBytes(ByteBuf buf) { + this.x = buf.readInt(); + this.y = buf.readInt(); + this.z = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(this.x); + buf.writeInt(this.y); + buf.writeInt(this.z); + } + + public static class Handler implements IMessageHandler { + @Override + public IMessage onMessage(PacketDuplicatorPress msg, MessageContext ctx) { + World world = Minecraft.getMinecraft().theWorld; + TileEntity te = world.getTileEntity(msg.x, msg.y, msg.z); + if (te instanceof TileDuplicator) { + ((TileDuplicator) te).doPress = true; + + Minecraft.getMinecraft().getSoundHandler().playSound( + PositionedSoundRecord.func_147675_a( + new ResourceLocation("thaummach", "stomp"), msg.x, msg.y, msg.z + ) + ); + + int q = 50; + for (int a = 0; a < q; ++a) { + float xx = (float) msg.x + 0.5F + - (world.rand.nextFloat() - world.rand.nextFloat()) * 1.5F; + float yy = (float) msg.y + 0.5F + - (world.rand.nextFloat() - world.rand.nextFloat()) * 0.1F; + float zz = (float) msg.z + 0.5F + - (world.rand.nextFloat() - world.rand.nextFloat()) * 1.5F; + FXWisp ef = new FXWisp( + world, + (double) ((float) msg.x + 0.5F), + (double) ((float) msg.y + 0.5F), + (double) ((float) msg.z + 0.5F), + (double) xx, + (double) yy, + (double) zz, + 0.15F, + world.rand.nextInt(5) + ); + Minecraft.getMinecraft().effectRenderer.addEffect(ef); + } + } + + return null; + } + } +} diff --git a/src/main/java/net/anvilcraft/thaummach/packets/PacketDuplicatorSetRepeat.java b/src/main/java/net/anvilcraft/thaummach/packets/PacketDuplicatorSetRepeat.java new file mode 100644 index 0000000..6e4e4b0 --- /dev/null +++ b/src/main/java/net/anvilcraft/thaummach/packets/PacketDuplicatorSetRepeat.java @@ -0,0 +1,57 @@ +package net.anvilcraft.thaummach.packets; + +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import io.netty.buffer.ByteBuf; +import net.anvilcraft.thaummach.tiles.TileDuplicator; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class PacketDuplicatorSetRepeat implements IMessage { + int x; + int y; + int z; + boolean repeat; + + public PacketDuplicatorSetRepeat() {} + + public PacketDuplicatorSetRepeat(int x, int y, int z, boolean repeat) { + this.x = x; + this.y = y; + this.z = z; + this.repeat = repeat; + } + + @Override + public void fromBytes(ByteBuf buf) { + this.x = buf.readInt(); + this.y = buf.readInt(); + this.z = buf.readInt(); + this.repeat = buf.readBoolean(); + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeInt(this.x); + buf.writeInt(this.y); + buf.writeInt(this.z); + buf.writeBoolean(this.repeat); + } + + public static class Handler implements IMessageHandler { + @Override + public IMessage onMessage(PacketDuplicatorSetRepeat msg, MessageContext ctx) { + World world = ctx.getServerHandler().playerEntity.worldObj; + + TileEntity te = world.getTileEntity(msg.x, msg.y, msg.z); + + if (te instanceof TileDuplicator) { + ((TileDuplicator) te).repeat = msg.repeat; + world.markBlockForUpdate(msg.x, msg.y, msg.z); + } + + return null; + } + } +} diff --git a/src/main/java/net/anvilcraft/thaummach/render/apparatus/apparati/wood/DuplicatorApparatusRenderer.java b/src/main/java/net/anvilcraft/thaummach/render/apparatus/apparati/wood/DuplicatorApparatusRenderer.java new file mode 100644 index 0000000..8db26b5 --- /dev/null +++ b/src/main/java/net/anvilcraft/thaummach/render/apparatus/apparati/wood/DuplicatorApparatusRenderer.java @@ -0,0 +1,87 @@ +package net.anvilcraft.thaummach.render.apparatus.apparati.wood; + +import net.anvilcraft.thaummach.TMBlocks; +import net.anvilcraft.thaummach.blocks.BlockApparatusMetal; +import net.anvilcraft.thaummach.blocks.BlockApparatusWood; +import net.anvilcraft.thaummach.render.apparatus.IApparatusRenderer; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.world.IBlockAccess; +import thaumcraft.client.renderers.block.BlockRenderer; + +public class DuplicatorApparatusRenderer implements IApparatusRenderer { + public static final DuplicatorApparatusRenderer INSTANCE = new DuplicatorApparatusRenderer(); + + @Override + public void renderApparatus( + IBlockAccess w, RenderBlocks rb, int x, int y, int z, Block block_, int meta, boolean inv + ) { + BlockApparatusWood block = (BlockApparatusWood) block_; + float w3 = 0.1775F; + rb.setRenderBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + if (inv) { + BlockRenderer.drawFaces( + rb, + block, + block.iconDuplicatorBottom, + block.iconDuplicatorBottom, + block.iconDuplicatorSide, + block.iconDuplicatorSide, + block.iconDuplicatorSide, + block.iconDuplicatorFront, + true + ); + } else { + rb.renderStandardBlock(block, x, y, z); + } + + if (!inv) { + rb.renderFaceYPos( + block, + (double) x, + (double) ((float) y - 1.0F + w3), + (double) z, + block.iconDuplicatorInside + ); + rb.renderFaceXPos( + block, + (double) ((float) (x - 1) + w3), + (double) y, + (double) z, + block.iconDuplicatorInside + ); + rb.renderFaceXNeg( + block, + (double) ((float) (x + 1) - w3), + (double) y, + (double) z, + block.iconDuplicatorInside + ); + rb.renderFaceZPos( + block, + (double) x, + (double) y, + (double) ((float) (z - 1) + w3), + block.iconDuplicatorInside + ); + rb.renderFaceZNeg( + block, + (double) x, + (double) y, + (double) ((float) (z + 1) - w3), + block.iconDuplicatorInside + ); + } else { + rb.setRenderBounds(0.1F, 0.1F, 0.1F, 0.9F, 0.99F, 0.9F); + BlockRenderer.drawFaces( + rb, + block, + ((BlockApparatusMetal) TMBlocks.apparatusMetal).iconArcaneFurnaceInside, + false + ); + } + + rb.overrideBlockTexture = null; + rb.setRenderBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F); + } +} diff --git a/src/main/java/net/anvilcraft/thaummach/render/model/ModelDuplicator.java b/src/main/java/net/anvilcraft/thaummach/render/model/ModelDuplicator.java new file mode 100644 index 0000000..714cbb0 --- /dev/null +++ b/src/main/java/net/anvilcraft/thaummach/render/model/ModelDuplicator.java @@ -0,0 +1,46 @@ +package net.anvilcraft.thaummach.render.model; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import net.minecraft.entity.Entity; + +public class ModelDuplicator extends ModelBase { + ModelRenderer press1; + ModelRenderer piston1; + + public ModelDuplicator() { + super.textureWidth = 64; + super.textureHeight = 32; + this.press1 = new ModelRenderer(this, 0, 0); + this.press1.addBox(-4.0F, 0.0F, -4.0F, 8, 4, 8); + this.press1.setRotationPoint(0.0F, 12.0F, 0.0F); + this.press1.setTextureSize(64, 32); + this.press1.mirror = true; + this.setRotation(this.press1, 0.0F, 0.0F, 0.0F); + this.piston1 = new ModelRenderer(this, 0, 12); + this.piston1.addBox(-2.0F, 0.0F, -2.0F, 4, 4, 4); + this.piston1.setRotationPoint(0.0F, 8.0F, 0.0F); + this.piston1.setTextureSize(64, 32); + this.piston1.mirror = true; + this.setRotation(this.piston1, 0.0F, 0.0F, 0.0F); + } + + @Override + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) { + super.render(entity, f, f1, f2, f3, f4, f5); + this.setRotationAngles(f, f1, f2, f3, f4, f5, entity); + this.press1.render(f5); + this.piston1.render(f5); + } + + public void render() { + this.press1.render(0.0625F); + this.piston1.render(0.0625F); + } + + private void setRotation(ModelRenderer model, float x, float y, float z) { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } +} diff --git a/src/main/java/net/anvilcraft/thaummach/render/tile/TileDuplicatorRenderer.java b/src/main/java/net/anvilcraft/thaummach/render/tile/TileDuplicatorRenderer.java new file mode 100644 index 0000000..c4e8149 --- /dev/null +++ b/src/main/java/net/anvilcraft/thaummach/render/tile/TileDuplicatorRenderer.java @@ -0,0 +1,71 @@ +package net.anvilcraft.thaummach.render.tile; + +import net.anvilcraft.thaummach.particles.FXWisp; +import net.anvilcraft.thaummach.render.model.ModelDuplicator; +import net.anvilcraft.thaummach.tiles.TileDuplicator; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +public class TileDuplicatorRenderer extends TileEntitySpecialRenderer { + private ModelDuplicator model = new ModelDuplicator(); + + public void renderEntityAt(TileDuplicator duplicator, double x, double y, double z, float fq) { + float dist = 0.1875F - duplicator.press; + if (duplicator.getWorldObj().rand.nextFloat() + < duplicator.duplicatorCopyTime / duplicator.currentItemCopyCost) { + float xx = (float) duplicator.xCoord + 0.5F + - (duplicator.getWorldObj().rand.nextFloat() + - duplicator.getWorldObj().rand.nextFloat()) + * 0.7F; + float yy = (float) duplicator.yCoord + 0.5F + - (duplicator.getWorldObj().rand.nextFloat() + - duplicator.getWorldObj().rand.nextFloat()) + * 0.7F; + float zz = (float) duplicator.zCoord + 0.5F + - (duplicator.getWorldObj().rand.nextFloat() + - duplicator.getWorldObj().rand.nextFloat()) + * 0.7F; + FXWisp ef = new FXWisp( + duplicator.getWorldObj(), + (double) ((float) duplicator.xCoord + 0.5F), + (double) ((float) duplicator.yCoord + 0.5F), + (double) ((float) duplicator.zCoord + 0.5F), + (double) xx, + (double) yy, + (double) zz, + 0.1F, + duplicator.getWorldObj().rand.nextInt(5) + ); + Minecraft.getMinecraft().effectRenderer.addEffect(ef); + } + + this.bindTexture(new ResourceLocation("thaummach", "textures/models/duplicator.png")); + GL11.glEnable(0xba1); + GL11.glEnable(0xbe2); + GL11.glPushMatrix(); + GL11.glEnable(0x803a); + GL11.glBlendFunc(770, 771); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glTranslatef((float) x + 0.5F, (float) y - 0.5F, (float) z + 0.5F); + GL11.glPushMatrix(); + GL11.glTranslatef(0.0F, -dist, 0.0F); + this.model.render(); + GL11.glPopMatrix(); + GL11.glPushMatrix(); + GL11.glRotatef(180.0F, 0.0F, 0.0F, 1.0F); + GL11.glTranslatef(0.0F, -2.0F - dist, 0.0F); + this.model.render(); + GL11.glPopMatrix(); + GL11.glDisable(0x803a); + GL11.glPopMatrix(); + GL11.glDisable(0xbe2); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + } + + public void renderTileEntityAt(TileEntity tileentity, double d, double d1, double d2, float f) { + this.renderEntityAt((TileDuplicator) tileentity, d, d1, d2, f); + } +} diff --git a/src/main/java/net/anvilcraft/thaummach/tiles/TileDuplicator.java b/src/main/java/net/anvilcraft/thaummach/tiles/TileDuplicator.java new file mode 100644 index 0000000..9287ef6 --- /dev/null +++ b/src/main/java/net/anvilcraft/thaummach/tiles/TileDuplicator.java @@ -0,0 +1,541 @@ +package net.anvilcraft.thaummach.tiles; + +import java.util.stream.IntStream; + +import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint; +import dev.tilera.auracore.api.machine.IUpgradable; +import dev.tilera.auracore.api.machine.TileVisUser; +import dev.tilera.auracore.aura.AuraManager; +import net.anvilcraft.thaummach.GuiID; +import net.anvilcraft.thaummach.ITileGui; +import net.anvilcraft.thaummach.RecipesCrucible; +import net.anvilcraft.thaummach.ThaumicMachinery; +import net.anvilcraft.thaummach.packets.PacketDuplicatorPress; +import net.anvilcraft.thaummach.particles.FXWisp; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import thaumcraft.api.aspects.Aspect; +import thaumcraft.api.aspects.AspectList; + +// TODO: make rotatable using AC IWandable +public class TileDuplicator extends TileVisUser implements ISidedInventory, IUpgradable, ITileGui { + private ItemStack[] duplicatorItemStacks = new ItemStack[10]; + public float duplicatorCopyTime = 0.0F; + public float currentItemCopyCost; + public float sucked = 0.0F; + public boolean repeat = false; + public int boost = 0; + private byte[] upgrades = new byte[] { -1 }; + public int orientation = -1; + public float press = 0.0F; + public boolean doPress = false; + private int pressDelay = 0; + int boostDelay = 20; + + @Override + public GuiID getGuiID() { + return GuiID.DUPLICATOR; + } + + @Override + public int getSizeInventory() { + return this.duplicatorItemStacks.length; + } + + @Override + public ItemStack getStackInSlot(int i) { + return this.duplicatorItemStacks[i]; + } + + @Override + public ItemStack decrStackSize(int i, int j) { + if (this.duplicatorItemStacks[i] != null) { + ItemStack itemstack1; + if (this.duplicatorItemStacks[i].stackSize <= j) { + itemstack1 = this.duplicatorItemStacks[i]; + this.duplicatorItemStacks[i] = null; + return itemstack1; + } else { + itemstack1 = this.duplicatorItemStacks[i].splitStack(j); + if (this.duplicatorItemStacks[i].stackSize == 0) { + this.duplicatorItemStacks[i] = null; + } + + return itemstack1; + } + } else { + return null; + } + } + + @Override + public void setInventorySlotContents(int i, ItemStack itemstack) { + this.duplicatorItemStacks[i] = itemstack; + if (itemstack != null && itemstack.stackSize > this.getInventoryStackLimit()) { + itemstack.stackSize = this.getInventoryStackLimit(); + } + } + + @Override + public String getInventoryName() { + return "Thaumic Duplicator"; + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + NBTTagList nbttaglist = nbttagcompound.getTagList("Items", 10); + this.duplicatorItemStacks = new ItemStack[this.getSizeInventory()]; + + for (int i = 0; i < nbttaglist.tagCount(); ++i) { + NBTTagCompound nbttagcompound1 = (NBTTagCompound) nbttaglist.getCompoundTagAt(i); + byte byte0 = nbttagcompound1.getByte("SlotDuplicator"); + if (byte0 >= 0 && byte0 < this.duplicatorItemStacks.length) { + this.duplicatorItemStacks[byte0] = ItemStack.loadItemStackFromNBT(nbttagcompound1); + } + } + + this.duplicatorCopyTime = nbttagcompound.getFloat("CopyTime"); + this.currentItemCopyCost = nbttagcompound.getFloat("CopyCost"); + this.repeat = nbttagcompound.getBoolean("Repeat"); + this.upgrades = nbttagcompound.getByteArray("upgrades"); + this.orientation = nbttagcompound.getShort("orientation"); + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + nbttagcompound.setFloat("CopyTime", this.duplicatorCopyTime); + nbttagcompound.setFloat("CopyCost", this.currentItemCopyCost); + nbttagcompound.setBoolean("Repeat", this.repeat); + nbttagcompound.setByteArray("upgrades", this.upgrades); + nbttagcompound.setShort("orientation", (short) this.orientation); + NBTTagList nbttaglist = new NBTTagList(); + + for (int i = 0; i < this.duplicatorItemStacks.length; ++i) { + if (this.duplicatorItemStacks[i] != null) { + NBTTagCompound nbttagcompound1 = new NBTTagCompound(); + nbttagcompound1.setByte("SlotDuplicator", (byte) i); + this.duplicatorItemStacks[i].writeToNBT(nbttagcompound1); + nbttaglist.appendTag(nbttagcompound1); + } + } + + nbttagcompound.setTag("Items", nbttaglist); + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + public int getCookProgressScaled(int i) { + return Math.round(this.duplicatorCopyTime / this.currentItemCopyCost * (float) i); + } + + public int getBoostScaled() { + return Math.round(0.1F + (float) this.boost / 2.0F) * 6; + } + + public boolean isCooking() { + return this.duplicatorCopyTime > 0.0F; + } + + @Override + public void updateEntity() { + super.updateEntity(); + if (!super.worldObj.isRemote) { + boolean flag1 = false; + boolean flag = this.duplicatorCopyTime > 0.0F; + if (this.canProcess() && this.currentItemCopyCost > 0.0F + && !super.worldObj.isBlockIndirectlyGettingPowered( + super.xCoord, super.yCoord, super.zCoord + )) { + float sa + = 0.5F + 0.05F * (float) this.boost + (this.hasUpgrade((byte) 0) ? 0.5F : 0.0F); + this.sucked = this.getAvailablePureVis(sa); + this.duplicatorCopyTime += this.sucked; + this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); + } else { + this.sucked = 0.0F; + } + if (this.duplicatorCopyTime >= this.currentItemCopyCost && flag) { + this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); + AuraManager.addFluxToClosest( + this.worldObj, + this.xCoord, + this.yCoord, + this.zCoord, + new AspectList().add( + Aspect.TAINT, Math.max(1, (int) (this.currentItemCopyCost / 20.0f)) + ) + ); + + this.addProcessedItem(); + ThaumicMachinery.channel.sendToAllAround( + new PacketDuplicatorPress(this.xCoord, this.yCoord, this.zCoord), + new TargetPoint( + this.worldObj.provider.dimensionId, + this.xCoord, + this.yCoord, + this.zCoord, + 64 + ) + ); + this.duplicatorCopyTime = 0.0F; + this.currentItemCopyCost = 0.0F; + this.markDirty(); + } + + if (this.currentItemCopyCost != 0.0F + && this.currentItemCopyCost != (float) this.getCopyCost()) { + this.duplicatorCopyTime = 0.0F; + this.currentItemCopyCost = 0.0F; + super.worldObj.playSoundEffect( + (double) super.xCoord + 0.5, + (double) super.yCoord + 0.5, + (double) super.zCoord + 0.5, + "random.fizz", + 1.0F, + 1.6F + ); + } + + if (this.duplicatorCopyTime == 0.0F && this.canProcess()) { + this.currentItemCopyCost = (float) this.getCopyCost(); + this.markDirty(); + } + + if (flag != this.duplicatorCopyTime > 0.0F) { + flag1 = true; + } + + if (flag1) { + this.markDirty(); + } + + // TODO: magic boost + //if (this.boostDelay <= 0 || this.boostDelay == 10) { + // auraX = super.xCoord >> 4; + // auraZ = super.zCoord >> 4; + // ac = (SIAuraChunk) mod_ThaumCraft.AuraHM.get(Arrays.asList( + // auraX, auraZ, ThaumCraftCore.getDimension(super.worldObj) + // )); + // if (ac != null && this.boost < 10 && ac.boost > 0) { + // ++this.boost; + // --ac.boost; + // } + //} + + if (this.boostDelay <= 0) { + if (this.boost > 0) { + --this.boost; + } + + this.boostDelay = 20; + } else { + --this.boostDelay; + } + } else { + if (this.press > 0.0F && !this.doPress) { + this.press *= 0.97F; + } + + if (this.press < 0.125F && !this.doPress) { + this.press = 0.125F; + } + + if (this.press < 0.1875F && this.doPress) { + this.press *= 1.1F; + } + + if (this.press >= 0.1875F && this.doPress && this.pressDelay <= 0) { + this.pressDelay = 12; + this.press = 0.1875F; + } + + if (this.pressDelay > 0) { + --this.pressDelay; + } + + if (this.pressDelay <= 0 && this.doPress && this.press >= 0.1875F) { + this.doPress = false; + } + } + } + + public int getCopyCost() { + if (this.duplicatorItemStacks[9] != null + && this.duplicatorItemStacks[9].getRarity() == EnumRarity.common) { + if (this.duplicatorItemStacks[9].getItem() + == Item.getItemFromBlock(Blocks.cobblestone)) { + return 2; + } else { + float t = RecipesCrucible.smelting().getSmeltingResult( + this.duplicatorItemStacks[9], true, false + ); + if (t > 0.0F) { + int tr = Math.round(t * (float) (this.hasUpgrade((byte) 1) ? 4 : 5)); + return tr; + } else { + return 0; + } + } + } else { + return 0; + } + } + + private boolean canProcess() { + if (this.duplicatorItemStacks[9] == null) { + return false; + } else { + for (int j = 0; j < 9; ++j) { + if (this.duplicatorItemStacks[j] == null) { + return true; + } + + if (this.duplicatorItemStacks[j].isItemEqual(this.duplicatorItemStacks[9])) { + int st = this.duplicatorItemStacks[j].stackSize + 1; + if (!this.repeat) { + ++st; + } + + if (st <= this.getInventoryStackLimit() + && st <= this.duplicatorItemStacks[j].getMaxStackSize()) { + return true; + } + } + } + + return false; + } + } + + private void addProcessedItem() { + if (this.canProcess()) { + ItemStack itemstack = new ItemStack( + this.duplicatorItemStacks[9].getItem(), + 1, + this.duplicatorItemStacks[9].getItemDamage() + ); + int repeats = 1; + if (!this.repeat) { + repeats = 2; + } + + for (int q = 0; q < repeats; ++q) { + for (int j = 0; j < 9; ++j) { + if (this.duplicatorItemStacks[j] == null) { + this.duplicatorItemStacks[j] = itemstack.copy(); + break; + } + + if (this.duplicatorItemStacks[j].isItemEqual(itemstack) + && this.duplicatorItemStacks[j].stackSize < itemstack.getMaxStackSize()) { + ItemStack var10000 = this.duplicatorItemStacks[j]; + var10000.stackSize += itemstack.stackSize; + break; + } + } + } + + if (!this.repeat) { + --this.duplicatorItemStacks[9].stackSize; + if (this.duplicatorItemStacks[9].stackSize <= 0) { + this.duplicatorItemStacks[9] = null; + } + } + } + } + + //@Override + //public int getStartInventorySide(int side) { + // return side != 0 && side != 1 ? 0 : 9; + //} + + //@Override + //public int getSizeInventorySide(int side) { + // return side != 0 && side != 1 ? 9 : 1; + //} + + @Override + public boolean isUseableByPlayer(EntityPlayer entityplayer) { + return true; + } + + @Override + public boolean getConnectable(ForgeDirection face) { + switch (face) { + case NORTH: + case EAST: + case SOUTH: + case WEST: + return true; + + default: + return false; + } + } + + @Override + public boolean canAcceptUpgrade(byte upgrade) { + if (upgrade != 0 && upgrade != 1) { + return false; + } else { + return !this.hasUpgrade(upgrade); + } + } + + @Override + public int getUpgradeLimit() { + return 1; + } + + @Override + public byte[] getUpgrades() { + return this.upgrades; + } + + @Override + public boolean hasUpgrade(byte upgrade) { + if (this.upgrades.length < 1) { + return false; + } else { + for (int a = 0; a < this.getUpgradeLimit(); ++a) { + if (this.upgrades[a] == upgrade) { + return true; + } + } + + return false; + } + } + + @Override + public boolean setUpgrade(byte upgrade) { + for (int a = 0; a < this.getUpgradeLimit(); ++a) { + if (this.upgrades[a] < 0 && this.canAcceptUpgrade(upgrade)) { + this.upgrades[a] = upgrade; + return true; + } + } + + return false; + } + + @Override + public boolean clearUpgrade(int index) { + if (this.upgrades[index] >= 0) { + this.upgrades[index] = -1; + return true; + } else { + return false; + } + } + + // TODO: IWandable + //@Override + //public boolean rotate() { + // ++this.orientation; + // if (this.orientation > 3) { + // this.orientation -= 4; + // } + + // return true; + //} + + @Override + public ItemStack getStackInSlotOnClosing(int var1) { + if (this.duplicatorItemStacks[var1] != null) { + ItemStack var2 = this.duplicatorItemStacks[var1]; + this.duplicatorItemStacks[var1] = null; + return var2; + } else { + return null; + } + } + + @Override + public void openInventory() {} + + @Override + public void closeInventory() {} + + @Override + public boolean isItemValidForSlot(int p_94041_1_, ItemStack p_94041_2_) { + return true; + } + + @Override + public int[] getAccessibleSlotsFromSide(int side) { + // output slot for top/bottom + switch (side) { + case 0: + case 1: + return new int[] { 9 }; + + default: + return IntStream.range(0, 9).toArray(); + } + } + + @Override + public boolean canInsertItem(int slot, ItemStack stack, int side) { + return this.isItemValidForSlot(slot, stack); + } + + @Override + public boolean canExtractItem(int slot, ItemStack otherStack, int side) { + ItemStack thisStack = this.duplicatorItemStacks[slot]; + + return thisStack != null && thisStack.isItemEqual(otherStack) + && thisStack.stackSize >= otherStack.stackSize; + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setFloat("duplicatorCopyTime", this.duplicatorCopyTime); + nbt.setFloat("currentItemCopyCost", this.currentItemCopyCost); + nbt.setFloat("sucked", this.sucked); + nbt.setBoolean("repeat", this.repeat); + nbt.setInteger("boost", this.boost); + nbt.setByteArray("upgrades", this.upgrades); + nbt.setInteger("orientation", this.orientation); + + return new S35PacketUpdateTileEntity( + this.xCoord, this.yCoord, this.zCoord, this.getBlockMetadata(), nbt + ); + } + + @Override + public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { + NBTTagCompound nbt = pkt.func_148857_g(); + + this.duplicatorCopyTime = nbt.getFloat("duplicatorCopyTime"); + this.currentItemCopyCost = nbt.getFloat("currentItemCopyCost"); + this.sucked = nbt.getFloat("sucked"); + this.repeat = nbt.getBoolean("repeat"); + this.boost = nbt.getInteger("boost"); + this.upgrades = nbt.getByteArray("upgrades"); + this.orientation = nbt.getInteger("orientation"); + } +} diff --git a/src/main/resources/assets/thaummach/sounds.json b/src/main/resources/assets/thaummach/sounds.json index 53fe8f3..1ae0d93 100644 --- a/src/main/resources/assets/thaummach/sounds.json +++ b/src/main/resources/assets/thaummach/sounds.json @@ -62,6 +62,19 @@ } ] }, + "stomp": { + "category": "block", + "sounds": [ + { + "name": "stomp1", + "stream": false + }, + { + "name": "stomp2", + "stream": false + } + ] + }, "upgrade": { "category": "master", "sounds": [ diff --git a/src/main/resources/assets/thaummach/sounds/stomp1.ogg b/src/main/resources/assets/thaummach/sounds/stomp1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..0417782a1881e84e8165f4b052396397e9b92576 GIT binary patch literal 11445 zcmb_?1yEd1v+uzPP67m%;LhTU1$SLsmf#K{EFK^@1b25>TtaXNgrLFQ0|a+TumnQ# zmi+H`?^myG)zee6Lr-_luc!M=&*@!`hOMnOfDHV{6=wVokr~^afJBYt`O?k89`?XO zlCAzn64dd}-&Q1zhnfF*J`M2u`ytvuaqupswyLrnojab$Zq5T$ z5ekt;FVvodysf!evp8ylFTXwunoQ7rSZB8+0r`6@KobB6q6$f)kVC_(kpW%+K>f-R zw$04*X!vb4QKDE|r%0ATXQKK=4AWKuT;o2#UIYTT6`>9i9SF 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 Vlcsrt)iHs22Um(fbRvKR_#e?w^m+gQ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/thaummach/sounds/stomp2.ogg b/src/main/resources/assets/thaummach/sounds/stomp2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..bb0d4df2370e23951ba04f4ea5fe773fba0fa83a GIT binary patch literal 10384 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/thaummach/textures/blocks/duplicator_bottom.png b/src/main/resources/assets/thaummach/textures/blocks/duplicator_bottom.png index 2bd2a835330d34f8973ef7b118a4550a8a5e9b4a..e173b7394069eeaf30a43d8bdd1db8244c605538 100644 GIT binary patch delta 625 zcmV-%0*?LR1fvCz83+ad001BJ|6!3KD1SvsL_t(|+H6xhZWTcgtoiM%*A^gwgh2!d z5hISk0XPT}5fLd8;s8V-AAl1OkdhE{0F@p}gudxsex_J1>0 zQz9^;61dTM^s&P@P73ZqKq?g{s}buM`{_V73A=|0r4-F5OGu2o1WP52XTbp$z&gg< zxplQU=a388jK$_gAQ6MT#}FgKo4#lyV+*S(^UPo|j;O7|J7;lW=um3VES0fS${44L zt4#Dr(?lhA4ZLYSyl&@{VOrso~$p zJHwb+SZSr|DfhL_!7@VWSLbcd;n8`6da99VB}rvc))?uxsM_V!INO)qIe&tUtxKGY zQ?Pedh1SY|xz$V$NNLQ$YAoLFTyL>6*uD}GhHJ3?A~XKbHe_k#oU6Ha_jU{3DuI-= z7!&5Mj8;@wbI0#}7wAk1?%Zr?_PJP&@B%to%ywOI0zGF(bLeCm!DC7^SC5ply72qa ziJHtYUJ{t~%k=oURk4P?KVF@)A+Tunk>s)K@a@+EZ+6=MFO#!Tg%ZmaQJVHu!E({d zBz+6%-a$IUc)1uKKg-3)?7GMCG6BncMkKxvV~Krbc=EfB`7OWzkSJ%>jQAqC00000 LNkvXXu0mjf?X5D1 delta 559 zcmV+~0?_@V1>ppc83+OZ005AYXf}}{D1QS5pm3T*|g!R;vw5Tn{^U{NI6$|TGw;9)P{;s95n@e_En%^}21_5CRCgu4|g6`hWHXj7ikkTI6K!oKnOlppJbPcDvnbwF0^<%jtBQ zQVJKoEVqJGNs;Kvc8{ z`W%7Fa0O1l1-JqS;1E=_6tu`hNeC!HNckuBeweY7C=LipXgbhab1{PVbz)Q~}FD#%G0$&BcClRp& z@!_F)zpx&jz3*bE%O9_A1v>8*(?x*yPJCcOIT~@yAXkE7qVnHtnWHJr68or*8z2Tuf5gIAXJ1>+zd@d!!c#an9ZEkzW&J>@0nQ4QetY;*La59+Hylk z@&}P5-Bcn^=c_VnwJWBpn+1$W=N_wuq3Ag}P-~b$gDlHNX5<=P4CU{q{1-saZJwJYYPNZ}&QY4T4z3(rN z?pIH5e&)+EcJcyiWBVfJ~(Ra44LMP!Vy=c-ge!s^TMzUOanjj7d4&{@xcJ z9>_8m)+#kx~^-QrhoeO1&m45*jnUd@0?P^CZLXe7k0bdYPABoEX(P1 znozHT-a8G~dO@#?(20;O62h!R|p1pP1Q~e&0o0ogKoP^M_-UgSlUK4Lmrb zJ-)z)lCp5ffOz%3n@vV&y>0`Ymha8Gy<=T^?2&;qTsmv8SETiQ(|-OqIl>rQwYg5~ yZJJHa{o-8K-0000^@5LC1jw8%tB2q;2G`6u>%n6Z;61q3tpTK0P1eBV>!$FuM;bm;U8 zT;FQ6QbGv8QS$)Sc_4TgLoixHYlXq*2oHCJ4Mz6{7Fn;rOV1)NET9wuUj@G>5r44* z@!_F)zpx&jz3*bE%O9_A1v>8*(?x*yPJCcOIT~@yAXkE7qVnHtnWH3>ngWyfS>GMeFQ-!)ATRhJVGW2y2>*S%SK1 zyaCp`f2AO#%GUvPd9S_I&LC8TQrrwpM#C{>$(YTY)xQ488Sj}`%u-@%)7N;0+}d(O zNb(1fB;8aZPv@&LYqcw;tD6OnMk7rUL_8unDA~o4DYc=v_VH|qr~B4cOf@9J=rO0W yzQsxF@J}@=HNq}Ni0w>v+odyRR*>}vGp&309H zSJ#+d?{2m)Uki5k6P~>6ak5;YHDGJ#k!ywgan`|F3u^#l3|_w|_=E9#2N`>Z86WmD zR#PG{q7t~#dGxWvI8F-gLO?1NC#wfI*^I^JMj#P`y~hwE!<)WnBx4J!Df7%=F^;IM!aHYiVdzk5&@7d)Q_2{p zisRKpGHE9wMyClx8%HrhF!*`AgqKV)kbrDsDk#kG^kHM!bIDr+6Koc0Q1Redr$WlN zNKLGr;6t4#Dr(?lhA4ZLYSyl&@{VOrso~$p zJHwb+SZSr|DfhL_!7@VWSLbcd;n8`6da99VB}rvc))?uxsM_V!INO)qIf9L?OPq{T zuyL+W#+;vr&Z-%N9|Z_Eo`h(aR)# z3+diLI>UIm7#}~&#mMZs$MG@&%X~&8z7S)HePwv^yN>xSzyOdaXVr}OBDnwn002ov JPDHLkV1k97JhT7+ diff --git a/src/main/resources/assets/thaummach/textures/guis/duplicator.png b/src/main/resources/assets/thaummach/textures/guis/duplicator.png new file mode 100644 index 0000000000000000000000000000000000000000..3112ea5830e318db55ae666b9f0acfa42d2f25e8 GIT binary patch literal 5535 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