From db9b0501d5b04e3db045ada58caf98727d591d68 Mon Sep 17 00:00:00 2001 From: Bob Date: Sun, 12 Oct 2025 21:42:18 +0200 Subject: [PATCH] conveyor stuff, yet more drill crap --- changelog | 10 ++ .../com/hbm/blocks/network/CraneBoxer.java | 17 ++- .../com/hbm/blocks/network/CraneInserter.java | 48 +++++-- .../com/hbm/blocks/network/CraneRouter.java | 133 +++++++++++++----- .../hbm/entity/item/EntityMovingPackage.java | 1 + .../com/hbm/items/tool/ItemSurveyScanner.java | 3 + .../com/hbm/items/tool/ItemToolAbility.java | 1 + .../weapon/sedna/factory/ConfettiUtil.java | 3 +- .../weapon/sedna/factory/GunFactory.java | 1 + .../weapon/sedna/factory/XFactoryDrill.java | 116 +++++++++++++++ .../weapon/sedna/factory/XFactoryTool.java | 12 -- .../items/weapon/sedna/impl/ItemGunDrill.java | 85 +++++------ .../weapon/sedna/mags/MagazineFluid.java | 2 +- .../sedna/mags/MagazineLiquidEngine.java | 59 ++++++++ .../hbm/particle/helper/SkeletonCreator.java | 7 +- .../item/weapon/sedna/ItemRenderDrill.java | 47 +++++-- .../network/TileEntityCraneInserter.java | 34 ++++- .../textures/gui/storage/gui_crane_router.png | Bin 3351 -> 3655 bytes .../hbm/textures/models/weapons/drill.png | Bin 3404 -> 7402 bytes 19 files changed, 455 insertions(+), 124 deletions(-) create mode 100644 src/main/java/com/hbm/items/weapon/sedna/factory/XFactoryDrill.java create mode 100644 src/main/java/com/hbm/items/weapon/sedna/mags/MagazineLiquidEngine.java diff --git a/changelog b/changelog index 1f85ec8e0..6e6163f03 100644 --- a/changelog +++ b/changelog @@ -11,6 +11,16 @@ * The conveyor ejector now has a "only take maximum possible" toggle * Enabling this means that, if stack ejection upgrades are installed, only stacks that meet the limit can be ejected * Items with a lower maximum stacksize will be ejected regardless +* Survey scanners now pick up bedrock oil +* The conveyor sorter filter slots now have directional labels instead of only color coding + * Apparently color blind people exist? +* Conveyor sorters can now process boxes + * All stacks are sorted individually, and each batch of items that comes out of one side is sent as a box +* Conveyor boxers can now accept boxes, this is useful for batching up partial boxes that come out of sorters +* Conveyor inserters can now accept boxes directly instead of causing them to burst open +* Conveyor inserters now have a special rule when supplying an arc furnace where instead of trying a full stack and then one item, the first always failing and the last being too slow, they will supply the slot target amount instead + * Given the cycle delay and the lid's movement speed, the inserters should now be fast enough to fully supply a speed III arc furnace +* Skeletons can bow be gibbed by explosions, although it will spawn clean bone particles and omit the gore splash effect ## Fixed * Fixed the T-51b set not having radiation resistance diff --git a/src/main/java/com/hbm/blocks/network/CraneBoxer.java b/src/main/java/com/hbm/blocks/network/CraneBoxer.java index 2498e734c..66702e603 100644 --- a/src/main/java/com/hbm/blocks/network/CraneBoxer.java +++ b/src/main/java/com/hbm/blocks/network/CraneBoxer.java @@ -6,6 +6,7 @@ import api.hbm.conveyor.IEnterableBlock; import com.hbm.lib.RefStrings; import com.hbm.tileentity.network.TileEntityCraneBase; import com.hbm.tileentity.network.TileEntityCraneBoxer; + import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.block.Block; @@ -84,9 +85,21 @@ public class CraneBoxer extends BlockCraneBase implements IEnterableBlock { @Override public boolean canPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { - return false; + return true; } @Override - public void onPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { } + public void onPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { + TileEntityCraneBoxer unboxer = (TileEntityCraneBoxer) world.getTileEntity(x, y, z); + ForgeDirection accessedSide = getOutputSide(world, x, y, z).getOpposite(); + + for(ItemStack stack : entity.getItemStacks()) { + ItemStack remainder = CraneInserter.addToInventory(unboxer, unboxer.getAccessibleSlotsFromSide(accessedSide.ordinal()), stack, accessedSide.ordinal()); + + if(remainder != null && remainder.stackSize > 0) { + EntityItem drop = new EntityItem(world, x + 0.5, y + 0.5, z + 0.5, remainder.copy()); + world.spawnEntityInWorld(drop); + } + } + } } diff --git a/src/main/java/com/hbm/blocks/network/CraneInserter.java b/src/main/java/com/hbm/blocks/network/CraneInserter.java index e4cb74967..f152a4fd3 100644 --- a/src/main/java/com/hbm/blocks/network/CraneInserter.java +++ b/src/main/java/com/hbm/blocks/network/CraneInserter.java @@ -145,19 +145,51 @@ public class CraneInserter extends BlockCraneBase implements IEnterableBlock { return toAdd; } - @Override - public boolean canPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { - return false; - } + @Override public boolean canPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { return true; } @Override - public void onPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { } + public void onPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { + ForgeDirection outputDirection = getOutputSide(world, x, y, z); + TileEntity te = world.getTileEntity(x + outputDirection.offsetX, y + outputDirection.offsetY, z + outputDirection.offsetZ); - @Override - public boolean hasComparatorInputOverride() { - return true; + if(entity == null || entity.getItemStacks() == null || entity.getItemStacks().length == 0) { + return; + } + + ItemStack[] toAdd = entity.getItemStacks(); + + if(!world.isBlockIndirectlyGettingPowered(x, y, z)) { + int[] access = null; + + if(te instanceof ISidedInventory) { + ISidedInventory sided = (ISidedInventory) te; + access = InventoryUtil.masquerade(sided, outputDirection.getOpposite().ordinal()); + } + + if(te instanceof IInventory) { + IInventory inv = (IInventory) te; + + for(ItemStack stack : toAdd) addToInventory(inv, access, stack, outputDirection.getOpposite().ordinal()); + } + } + + TileEntityCraneInserter inserter = null; + + for(ItemStack stack : toAdd) { + + if(stack.stackSize > 0) { + inserter = (TileEntityCraneInserter) world.getTileEntity(x, y, z); + addToInventory(inserter, null, stack, outputDirection.getOpposite().ordinal()); + } + if(stack.stackSize > 0 && inserter != null && !inserter.destroyer) { + EntityItem drop = new EntityItem(world, x + 0.5, y + 0.5, z + 0.5, stack.copy()); + world.spawnEntityInWorld(drop); + } + } } + @Override public boolean hasComparatorInputOverride() { return true; } + @Override public int getComparatorInputOverride(World world, int x, int y, int z, int side) { return Container.calcRedstoneFromInventory((TileEntityCraneInserter)world.getTileEntity(x, y, z)); diff --git a/src/main/java/com/hbm/blocks/network/CraneRouter.java b/src/main/java/com/hbm/blocks/network/CraneRouter.java index af4db88bb..7ed933fee 100644 --- a/src/main/java/com/hbm/blocks/network/CraneRouter.java +++ b/src/main/java/com/hbm/blocks/network/CraneRouter.java @@ -7,6 +7,7 @@ import api.hbm.conveyor.IEnterableBlock; import com.hbm.blocks.IBlockMultiPass; import com.hbm.blocks.ITooltipProvider; import com.hbm.entity.item.EntityMovingItem; +import com.hbm.entity.item.EntityMovingPackage; import com.hbm.items.tool.ItemConveyorWand; import com.hbm.lib.RefStrings; import com.hbm.main.MainRegistry; @@ -115,16 +116,100 @@ public class CraneRouter extends BlockContainer implements IBlockMultiPass, IEnt return 7; } - @Override - public boolean canItemEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorItem entity) { - return true; - } + @Override public boolean canItemEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorItem entity) { return true; } + @Override public boolean canPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { return true; } @Override public void onItemEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorItem entity) { - TileEntityCraneRouter router = (TileEntityCraneRouter) world.getTileEntity(x, y, z); - ItemStack stack = entity.getItemStack(); + List[] sort = this.sort(world, x, y, z, entity.getItemStack()); + for(int i = 0; i < 7; i++) { + ForgeDirection d = ForgeDirection.getOrientation(i); + List list = sort[i]; + + if(d == ForgeDirection.UNKNOWN) { + for(ItemStack stack : list) world.spawnEntityInWorld(new EntityItem(world, x + 0.5, y + 0.5, z + 0.5, stack)); + } else { + for(ItemStack stack : list) sendOnRoute(world, x, y, z, stack, d); + } + } + + } + + protected void sendOnRoute(World world, int x, int y, int z, ItemStack item, ForgeDirection dir) { + IConveyorBelt belt = null; + Block block = world.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); + + if(block instanceof IConveyorBelt) { + belt = (IConveyorBelt) block; + } + + if(belt != null) { + EntityMovingItem moving = new EntityMovingItem(world); + Vec3 pos = Vec3.createVectorHelper(x + 0.5 + dir.offsetX * 0.55, y + 0.5 + dir.offsetY * 0.55, z + 0.5 + dir.offsetZ * 0.55); + Vec3 snap = belt.getClosestSnappingPosition(world, x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ, pos); + moving.setPosition(snap.xCoord, snap.yCoord, snap.zCoord); + moving.setItemStack(item); + world.spawnEntityInWorld(moving); + } else { + world.spawnEntityInWorld(new EntityItem(world, x + 0.5 + dir.offsetX * 0.55, y + 0.5 + dir.offsetY * 0.55, z + 0.5 + dir.offsetZ * 0.55, item)); + } + } + + @Override + public void onPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { + List[] sort = this.sort(world, x, y, z, entity.getItemStacks()); + + for(int i = 0; i < 7; i++) { + ForgeDirection d = ForgeDirection.getOrientation(i); + List list = sort[i]; + if(list.isEmpty()) continue; + + if(d == ForgeDirection.UNKNOWN) { + for(ItemStack stack : list) world.spawnEntityInWorld(new EntityItem(world, x + 0.5, y + 0.5, z + 0.5, stack)); + } else { + + IConveyorBelt belt = null; + Block block = world.getBlock(x + d.offsetX, y + d.offsetY, z + d.offsetZ); + if(block instanceof IConveyorBelt) belt = (IConveyorBelt) block; + + if(belt != null) { + EntityMovingPackage moving = new EntityMovingPackage(world); + Vec3 pos = Vec3.createVectorHelper(x + 0.5 + d.offsetX * 0.55, y + 0.5 + d.offsetY * 0.55, z + 0.5 + d.offsetZ * 0.55); + Vec3 snap = belt.getClosestSnappingPosition(world, x + d.offsetX, y + d.offsetY, z + d.offsetZ, pos); + moving.setPosition(snap.xCoord, snap.yCoord, snap.zCoord); + moving.setItemStacks(list.toArray(new ItemStack[0])); + world.spawnEntityInWorld(moving); + } else { + for(ItemStack stack : list) world.spawnEntityInWorld(new EntityItem(world, x + 0.5 + d.offsetX * 0.55, y + 0.5 + d.offsetY * 0.55, z + 0.5 + d.offsetZ * 0.55, stack)); + } + } + } + } + + @Override + public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean ext) { + this.addStandardInfo(stack, player, list, ext); + } + + /** Accepts an arbitrary amount of ItemStacks (either solo or from boxes) and returns an array corresponding with ForgeDirections, + * with each direction having a list of items being output in that direction. Index 6 is used for UNKNOWN, i.e. unsortable items. + * Returned lists are populated with COPIES of the original stacks. */ + public static List[] sort(World world, int x, int y, int z, ItemStack... stacks) { + TileEntityCraneRouter router = (TileEntityCraneRouter) world.getTileEntity(x, y, z); + List[] output = new List[7]; + for(int i = 0; i < 7; i++) output[i] = new ArrayList(); + + for(ItemStack stack : stacks) { + if(stack == null) continue; + ForgeDirection dir = getOutputDir(router, stack.copy()); + output[dir.ordinal()].add(stack); + } + + return output; + } + + public static ForgeDirection getOutputDir(TileEntityCraneRouter router, ItemStack stack) { List validDirs = new ArrayList(); //check filters for all sides @@ -168,40 +253,10 @@ public class CraneRouter extends BlockContainer implements IBlockMultiPass, IEnt } if(validDirs.isEmpty()) { - world.spawnEntityInWorld(new EntityItem(world, x + 0.5, y + 0.5, z + 0.5, stack.copy())); - return; + return ForgeDirection.UNKNOWN; } - int i = world.rand.nextInt(validDirs.size()); - sendOnRoute(world, x, y, z, entity, validDirs.get(i)); - } - - protected void sendOnRoute(World world, int x, int y, int z, IConveyorItem item, ForgeDirection dir) { - - IConveyorBelt belt = null; - Block block = world.getBlock(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ); - - if(block instanceof IConveyorBelt) { - belt = (IConveyorBelt) block; - } - - if(belt != null) { - EntityMovingItem moving = new EntityMovingItem(world); - Vec3 pos = Vec3.createVectorHelper(x + 0.5 + dir.offsetX * 0.55, y + 0.5 + dir.offsetY * 0.55, z + 0.5 + dir.offsetZ * 0.55); - Vec3 snap = belt.getClosestSnappingPosition(world, x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ, pos); - moving.setPosition(snap.xCoord, snap.yCoord, snap.zCoord); - moving.setItemStack(item.getItemStack()); - world.spawnEntityInWorld(moving); - } else { - world.spawnEntityInWorld(new EntityItem(world, x + 0.5 + dir.offsetX * 0.55, y + 0.5 + dir.offsetY * 0.55, z + 0.5 + dir.offsetZ * 0.55, item.getItemStack())); - } - } - - @Override public boolean canPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { return false; } - @Override public void onPackageEnter(World world, int x, int y, int z, ForgeDirection dir, IConveyorPackage entity) { } - - @Override - public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean ext) { - this.addStandardInfo(stack, player, list, ext); + int i = router.getWorldObj().rand.nextInt(validDirs.size()); + return validDirs.get(i); } } diff --git a/src/main/java/com/hbm/entity/item/EntityMovingPackage.java b/src/main/java/com/hbm/entity/item/EntityMovingPackage.java index ddf2fb77d..65bb7cfd9 100644 --- a/src/main/java/com/hbm/entity/item/EntityMovingPackage.java +++ b/src/main/java/com/hbm/entity/item/EntityMovingPackage.java @@ -74,6 +74,7 @@ public class EntityMovingPackage extends EntityMovingConveyorObject implements I @Override public void enterBlock(IEnterableBlock enterable, BlockPos pos, ForgeDirection dir) { + if(this.isDead) return; if(enterable.canPackageEnter(worldObj, pos.getX(), pos.getY(), pos.getZ(), dir, this)) { enterable.onPackageEnter(worldObj, pos.getX(), pos.getY(), pos.getZ(), dir, this); diff --git a/src/main/java/com/hbm/items/tool/ItemSurveyScanner.java b/src/main/java/com/hbm/items/tool/ItemSurveyScanner.java index e4906b2ea..cb73d7e5a 100644 --- a/src/main/java/com/hbm/items/tool/ItemSurveyScanner.java +++ b/src/main/java/com/hbm/items/tool/ItemSurveyScanner.java @@ -26,6 +26,7 @@ public class ItemSurveyScanner extends Item { boolean hasOil = false; boolean hasColtan = false; + boolean hasBedrockOil = false; boolean hasDepth = false; boolean hasSchist = false; boolean hasAussie = false; @@ -40,6 +41,7 @@ public class ItemSurveyScanner extends Item { //wow, this sucks! if(block == ModBlocks.ore_oil) hasOil = true; else if(block == ModBlocks.ore_coltan) hasColtan = true; + else if(block == ModBlocks.ore_bedrock_oil) hasBedrockOil = true; else if(block == ModBlocks.stone_depth) hasDepth = true; else if(block == ModBlocks.stone_depth_nether) hasDepth = true; else if(block == ModBlocks.stone_gneiss) hasSchist = true; @@ -55,6 +57,7 @@ public class ItemSurveyScanner extends Item { } if(hasOil) player.addChatComponentMessage(new ChatComponentText("Found OIL!").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.BLACK))); + if(hasBedrockOil) player.addChatComponentMessage(new ChatComponentText("Found BEDROCK OIL!").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.BLACK))); if(hasColtan) player.addChatComponentMessage(new ChatComponentText("Found COLTAN!").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GOLD))); if(hasDepth) player.addChatComponentMessage(new ChatComponentText("Found DEPTH ROCK!").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.GRAY))); if(hasSchist) player.addChatComponentMessage(new ChatComponentText("Found SCHIST!").setChatStyle(new ChatStyle().setColor(EnumChatFormatting.DARK_AQUA))); diff --git a/src/main/java/com/hbm/items/tool/ItemToolAbility.java b/src/main/java/com/hbm/items/tool/ItemToolAbility.java index cca7f351b..dfcac8ae8 100644 --- a/src/main/java/com/hbm/items/tool/ItemToolAbility.java +++ b/src/main/java/com/hbm/items/tool/ItemToolAbility.java @@ -385,6 +385,7 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro if(removedByPlayer && canHarvest) { try { + blockCaptureDrops.invoke(block, true); block.harvestBlock(world, player, x, y, z, l); List drops = (List)blockCaptureDrops.invoke(block, false); diff --git a/src/main/java/com/hbm/items/weapon/sedna/factory/ConfettiUtil.java b/src/main/java/com/hbm/items/weapon/sedna/factory/ConfettiUtil.java index 661b4185a..c7fb51289 100644 --- a/src/main/java/com/hbm/items/weapon/sedna/factory/ConfettiUtil.java +++ b/src/main/java/com/hbm/items/weapon/sedna/factory/ConfettiUtil.java @@ -45,10 +45,11 @@ public class ConfettiUtil { if(entity instanceof EntityCyberCrab) return; if(entity instanceof EntityTeslaCrab) return; if(entity instanceof EntityTaintCrab) return; - if(entity instanceof EntitySkeleton) return; if(entity instanceof EntitySlime) return; SkeletonCreator.composeEffectGib(entity.worldObj, entity, 0.25F); + + if(entity instanceof EntitySkeleton) return; NBTTagCompound vdat = new NBTTagCompound(); vdat.setString("type", "giblets"); diff --git a/src/main/java/com/hbm/items/weapon/sedna/factory/GunFactory.java b/src/main/java/com/hbm/items/weapon/sedna/factory/GunFactory.java index d2daf744c..e7787c983 100644 --- a/src/main/java/com/hbm/items/weapon/sedna/factory/GunFactory.java +++ b/src/main/java/com/hbm/items/weapon/sedna/factory/GunFactory.java @@ -68,6 +68,7 @@ public class GunFactory { XFactory35800.init(); XFactory45.init(); XFactoryTool.init(); + XFactoryDrill.init(); ModItems.weapon_mod_test = new ItemEnumMulti(EnumModTest.class, true, true).setUnlocalizedName("weapon_mod_test").setMaxStackSize(1); ModItems.weapon_mod_generic = new ItemEnumMulti(EnumModGeneric.class, true, true).setUnlocalizedName("weapon_mod_generic").setMaxStackSize(1).setCreativeTab(MainRegistry.weaponTab); diff --git a/src/main/java/com/hbm/items/weapon/sedna/factory/XFactoryDrill.java b/src/main/java/com/hbm/items/weapon/sedna/factory/XFactoryDrill.java new file mode 100644 index 000000000..65ef98f00 --- /dev/null +++ b/src/main/java/com/hbm/items/weapon/sedna/factory/XFactoryDrill.java @@ -0,0 +1,116 @@ +package com.hbm.items.weapon.sedna.factory; + +import java.util.function.BiConsumer; + +import com.hbm.blocks.ModBlocks; +import com.hbm.inventory.fluid.Fluids; +import com.hbm.items.ModItems; +import com.hbm.items.weapon.sedna.Crosshair; +import com.hbm.items.weapon.sedna.GunConfig; +import com.hbm.items.weapon.sedna.ItemGunBaseNT; +import com.hbm.items.weapon.sedna.Receiver; +import com.hbm.items.weapon.sedna.ItemGunBaseNT.LambdaContext; +import com.hbm.items.weapon.sedna.ItemGunBaseNT.WeaponQuality; +import com.hbm.items.weapon.sedna.impl.ItemGunDrill; +import com.hbm.items.weapon.sedna.mags.IMagazine; +import com.hbm.items.weapon.sedna.mags.MagazineLiquidEngine; +import com.hbm.items.weapon.sedna.mods.WeaponModManager; +import com.hbm.render.anim.AnimationEnums.GunAnimation; +import com.hbm.util.EntityDamageUtil; + +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.network.play.server.S28PacketEffect; +import net.minecraft.util.DamageSource; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.World; + +public class XFactoryDrill { + + public static final String D_REACH = "D_REACH"; + public static final String F_DTNEG = "F_DTNEG"; + public static final String F_PIERCE = "F_PIERCE"; + public static final String I_AOE = "I_AOE"; + public static final String I_HARVEST = "I_HARVEST"; + + public static void init() { + + ModItems.gun_drill = new ItemGunDrill(WeaponQuality.UTILITY, new GunConfig() + .dura(3_000).draw(10).inspect(55).hideCrosshair(false).crosshair(Crosshair.L_CIRCUMFLEX) + .rec(new Receiver(0) + .dmg(10F).delay(20).auto(true).jam(0) + .mag(new MagazineLiquidEngine(0, 4_000, Fluids.GASOLINE, Fluids.GASOLINE_LEADED, Fluids.COALGAS, Fluids.COALGAS_LEADED)) + .offset(1, -0.0625 * 2.5, -0.25D) + .canFire(Lego.LAMBDA_STANDARD_CAN_FIRE).fire(LAMBDA_DRILL_FIRE)) + .pp(Lego.LAMBDA_STANDARD_CLICK_PRIMARY).pr(Lego.LAMBDA_STANDARD_RELOAD).decider(GunStateDecider.LAMBDA_STANDARD_DECIDER) + //.anim(LAMBDA_CT_ANIMS).orchestra(Orchestras.ORCHESTRA_CHARGE_THROWER) + ).setUnlocalizedName("gun_drill"); + } + + public static BiConsumer LAMBDA_DRILL_FIRE = (stack, ctx) -> { + doStandardFire(stack, ctx, GunAnimation.CYCLE, true); + }; + + public static void doStandardFire(ItemStack stack, LambdaContext ctx, GunAnimation anim, boolean calcWear) { + EntityPlayer player = ctx.getPlayer(); + int index = ctx.configIndex; + if(anim != null) ItemGunBaseNT.playAnimation(player, stack, anim, ctx.configIndex); + + Receiver primary = ctx.config.getReceivers(stack)[0]; + IMagazine mag = primary.getMagazine(stack); + + MovingObjectPosition mop = EntityDamageUtil.getMouseOver(ctx.getPlayer(), getModdableReach(stack, 5.0D)); + if(mop != null) { + if(mop.typeOfHit == mop.typeOfHit.ENTITY) { + float damage = 5.0F; + if(mop.entityHit instanceof EntityLivingBase) { + EntityDamageUtil.attackEntityFromNT((EntityLivingBase) mop.entityHit, DamageSource.causePlayerDamage(ctx.getPlayer()), damage, true, true, 0.1F, getModdableDTNegation(stack, 2F), getModdablePiercing(stack, 0.15F)); + } else { + mop.entityHit.attackEntityFrom(DamageSource.causePlayerDamage(ctx.getPlayer()), damage); + } + } + if(player != null && mop.typeOfHit == mop.typeOfHit.BLOCK) { + + int aoe = getModdableAoE(stack, 1); + for(int i = -aoe; i <= aoe; i++) for(int j = -aoe; j <= aoe; j++) for(int k = -aoe; k <= aoe; k++) { + breakExtraBlock(player.worldObj, mop.blockX + i, mop.blockY + j, mop.blockZ + k, player, mop.blockX, mop.blockY, mop.blockZ); + } + } + } + + mag.useUpAmmo(stack, ctx.inventory, 10); + if(calcWear) ItemGunBaseNT.setWear(stack, index, Math.min(ItemGunBaseNT.getWear(stack, index), ctx.config.getDurability(stack))); + } + + public static void breakExtraBlock(World world, int x, int y, int z, EntityPlayer playerEntity, int refX, int refY, int refZ) { + if(world.isAirBlock(x, y, z)) return; + if(!(playerEntity instanceof EntityPlayerMP)) return; + + EntityPlayerMP player = (EntityPlayerMP) playerEntity; + Block block = world.getBlock(x, y, z); + int meta = world.getBlockMetadata(x, y, z); + + if(!block.canHarvestBlock(player, meta) || (block.getBlockHardness(world, x, y, z) == -1.0F && block.getPlayerRelativeBlockHardness(player, world, x, y, z) == 0.0F) || block == ModBlocks.stone_keyhole) { + world.playSoundAtEntity(player, "random.break", 0.5F, 0.8F + world.rand.nextFloat() * 0.6F); + return; + } + + // we are serverside and tryHarvestBlock already invokes the 2001 packet for every player except the user, so we manually send it for the user as well + player.theItemInWorldManager.tryHarvestBlock(x, y, z); + + if(world.getBlock(x, y, z) == Blocks.air) { // only do this when the block was destroyed. if the block doesn't create air when broken, this breaks, but it's no big deal + player.playerNetServerHandler.sendPacket(new S28PacketEffect(2001, x, y, z, Block.getIdFromBlock(block) + (meta << 12), false)); + } + } + + // this system technically doesn't need to be part of the GunCfg or Receiver or anything, we can just do this and it works the exact same + public static double getModdableReach(ItemStack stack, double base) { return WeaponModManager.eval(base, stack, D_REACH, ModItems.gun_drill, 0); } + public static float getModdableDTNegation(ItemStack stack, float base) { return WeaponModManager.eval(base, stack, F_DTNEG, ModItems.gun_drill, 0); } + public static float getModdablePiercing(ItemStack stack, float base) { return WeaponModManager.eval(base, stack, F_PIERCE, ModItems.gun_drill, 0); } + public static int getModdableAoE(ItemStack stack, int base) { return WeaponModManager.eval(base, stack, I_AOE, ModItems.gun_drill, 0); } + public static int getModdableHarvestLevel(ItemStack stack, int base) { return WeaponModManager.eval(base, stack, I_HARVEST, ModItems.gun_drill, 0); } +} diff --git a/src/main/java/com/hbm/items/weapon/sedna/factory/XFactoryTool.java b/src/main/java/com/hbm/items/weapon/sedna/factory/XFactoryTool.java index 5fbd2d7e5..3237bd1d0 100644 --- a/src/main/java/com/hbm/items/weapon/sedna/factory/XFactoryTool.java +++ b/src/main/java/com/hbm/items/weapon/sedna/factory/XFactoryTool.java @@ -24,7 +24,6 @@ import com.hbm.items.weapon.sedna.ItemGunBaseNT.LambdaContext; import com.hbm.items.weapon.sedna.ItemGunBaseNT.WeaponQuality; import com.hbm.items.weapon.sedna.factory.GunFactory.EnumAmmo; import com.hbm.items.weapon.sedna.impl.ItemGunChargeThrower; -import com.hbm.items.weapon.sedna.impl.ItemGunDrill; import com.hbm.items.weapon.sedna.mags.MagazineFullReload; import com.hbm.lib.RefStrings; import com.hbm.main.MainRegistry; @@ -276,17 +275,6 @@ public class XFactoryTool { .setupStandardConfiguration() .anim(LAMBDA_CT_ANIMS).orchestra(Orchestras.ORCHESTRA_CHARGE_THROWER) ).setUnlocalizedName("gun_charge_thrower"); - - ModItems.gun_drill = new ItemGunDrill(WeaponQuality.UTILITY, new GunConfig() - .dura(3_000).draw(10).inspect(55).reloadChangeType(true).hideCrosshair(false).crosshair(Crosshair.L_CIRCUMFLEX) - .rec(new Receiver(0) - .dmg(10F).delay(4).dry(10).auto(true).spread(0F).spreadHipfire(0F).reload(60).jam(0).sound("hbm:weapon.fire.grenade", 1.0F, 1.0F) - .mag(new MagazineFullReload(0, 1).addConfigs(ct_hook, ct_mortar, ct_mortar_charge)) - .offset(1, -0.0625 * 2.5, -0.25D) - .setupStandardFire()) - .setupStandardConfiguration() - //.anim(LAMBDA_CT_ANIMS).orchestra(Orchestras.ORCHESTRA_CHARGE_THROWER) - ).setUnlocalizedName("gun_drill"); } public static BiConsumer LAMBDA_RECOIL_CT = (stack, ctx) -> { diff --git a/src/main/java/com/hbm/items/weapon/sedna/impl/ItemGunDrill.java b/src/main/java/com/hbm/items/weapon/sedna/impl/ItemGunDrill.java index 3a888903d..55ef58dd5 100644 --- a/src/main/java/com/hbm/items/weapon/sedna/impl/ItemGunDrill.java +++ b/src/main/java/com/hbm/items/weapon/sedna/impl/ItemGunDrill.java @@ -1,11 +1,16 @@ package com.hbm.items.weapon.sedna.impl; import com.hbm.inventory.fluid.FluidType; +import com.hbm.inventory.fluid.Fluids; import com.hbm.items.weapon.sedna.GunConfig; import com.hbm.items.weapon.sedna.ItemGunBaseNT; +import com.hbm.items.weapon.sedna.factory.XFactoryDrill; +import com.hbm.items.weapon.sedna.mags.IMagazine; +import com.hbm.items.weapon.sedna.mags.MagazineLiquidEngine; import api.hbm.energymk2.IBatteryItem; import api.hbm.fluidmk2.IFillableItem; +import net.minecraft.block.Block; import net.minecraft.item.ItemStack; public class ItemGunDrill extends ItemGunBaseNT implements IFillableItem, IBatteryItem { @@ -13,66 +18,66 @@ public class ItemGunDrill extends ItemGunBaseNT implements IFillableItem, IBatte public ItemGunDrill(WeaponQuality quality, GunConfig... cfg) { super(quality, cfg); } + + @Override + public int getHarvestLevel(ItemStack stack, String toolClass) { + return XFactoryDrill.getModdableHarvestLevel(stack, ToolMaterial.IRON.getHarvestLevel()); + } + + @Override + public boolean canHarvestBlock(Block par1Block, ItemStack itemStack) { + return true; // this lets us break things that have no set harvest level (i.e. most NTM shit) + } @Override public boolean acceptsFluid(FluidType type, ItemStack stack) { - return false; + IMagazine mag = ((ItemGunBaseNT) stack.getItem()).getConfig(stack, 0).getReceivers(stack)[0].getMagazine(stack); + return mag instanceof MagazineLiquidEngine; } @Override public int tryFill(FluidType type, int amount, ItemStack stack) { + IMagazine mag = ((ItemGunBaseNT) stack.getItem()).getConfig(stack, 0).getReceivers(stack)[0].getMagazine(stack); + + if(mag instanceof MagazineLiquidEngine) { + MagazineLiquidEngine engine = (MagazineLiquidEngine) mag; + int toFill = Math.min(amount, 50); + toFill = Math.min(toFill, engine.getCapacity(stack) - this.getFill(stack)); + engine.setAmount(stack, this.getFill(stack) + toFill); + return amount - toFill; + } + return 0; } @Override public boolean providesFluid(FluidType type, ItemStack stack) { return false; } - - @Override - public int tryEmpty(FluidType type, int amount, ItemStack stack) { - return 0; - } + @Override public int tryEmpty(FluidType type, int amount, ItemStack stack) { return amount; } @Override public FluidType getFirstFluidType(ItemStack stack) { - return null; + IMagazine mag = ((ItemGunBaseNT) stack.getItem()).getConfig(stack, 0).getReceivers(stack)[0].getMagazine(stack); + if(mag instanceof MagazineLiquidEngine) return ((MagazineLiquidEngine) mag).getType(stack, null); + return Fluids.NONE; } - + @Override public int getFill(ItemStack stack) { - return 0; - } - - @Override - public void chargeBattery(ItemStack stack, long i) { + IMagazine mag = ((ItemGunBaseNT) stack.getItem()).getConfig(stack, 0).getReceivers(stack)[0].getMagazine(stack); - } - - @Override - public void setCharge(ItemStack stack, long i) { + if(mag instanceof MagazineLiquidEngine) { + MagazineLiquidEngine engine = (MagazineLiquidEngine) mag; + return engine.getAmount(stack, null); + } - } - - @Override - public void dischargeBattery(ItemStack stack, long i) { - - } - - @Override - public long getCharge(ItemStack stack) { return 0; } - @Override - public long getMaxCharge(ItemStack stack) { - return 0; - } - - @Override - public long getChargeRate() { - return 0; - } - - @Override - public long getDischargeRate() { - return 0; - } + // TBI + @Override public void chargeBattery(ItemStack stack, long i) { } + @Override public void setCharge(ItemStack stack, long i) { } + @Override public void dischargeBattery(ItemStack stack, long i) { } + @Override public long getCharge(ItemStack stack) { return 0; } + @Override public long getMaxCharge(ItemStack stack) { return 0; } + @Override public long getChargeRate() { return 0; } + @Override public long getDischargeRate() { return 0; } } diff --git a/src/main/java/com/hbm/items/weapon/sedna/mags/MagazineFluid.java b/src/main/java/com/hbm/items/weapon/sedna/mags/MagazineFluid.java index 1f0056825..f22c950ff 100644 --- a/src/main/java/com/hbm/items/weapon/sedna/mags/MagazineFluid.java +++ b/src/main/java/com/hbm/items/weapon/sedna/mags/MagazineFluid.java @@ -57,7 +57,7 @@ public class MagazineFluid implements IMagazine { @Override public SpentCasing getCasing(ItemStack stack, IInventory inventory) { return null; } @Override public ItemStack getIconForHUD(ItemStack stack, EntityPlayer player) { return new ItemStack(ModItems.fluid_icon, 1, this.getMagType(stack, index)); } - @Override public String reportAmmoStateForHUD(ItemStack stack, EntityPlayer player) { return getIconForHUD(stack, player).getDisplayName(); } + @Override public String reportAmmoStateForHUD(ItemStack stack, EntityPlayer player) { return getAmount(stack, player.inventory) + "mB"; } @Override public void setAmountBeforeReload(ItemStack stack, int amount) { ItemGunBaseNT.setValueInt(stack, KEY_MAG_PREV + index, amount); } @Override public int getAmountBeforeReload(ItemStack stack) { return ItemGunBaseNT.getValueInt(stack, KEY_MAG_PREV + index); } diff --git a/src/main/java/com/hbm/items/weapon/sedna/mags/MagazineLiquidEngine.java b/src/main/java/com/hbm/items/weapon/sedna/mags/MagazineLiquidEngine.java new file mode 100644 index 000000000..4dd8e984b --- /dev/null +++ b/src/main/java/com/hbm/items/weapon/sedna/mags/MagazineLiquidEngine.java @@ -0,0 +1,59 @@ +package com.hbm.items.weapon.sedna.mags; + +import com.hbm.inventory.fluid.FluidType; +import com.hbm.items.ModItems; +import com.hbm.items.weapon.sedna.ItemGunBaseNT; +import com.hbm.particle.SpentCasing; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +/** Type of fixed ammo engine */ +public class MagazineLiquidEngine implements IMagazine { + + public static final String KEY_MAG_COUNT = "magcount"; + public static final String KEY_MAG_PREV = "magprev"; + public static final String KEY_MAG_AFTER = "magafter"; + + /** A number so the gun tell multiple mags apart */ + public int index; + /** How much ammo this mag can hold */ + public int capacity; + /** Whichever fluids we can pour in this bastard */ + public FluidType[] acceptedTypes; + + public MagazineLiquidEngine(int index, int capacity, FluidType... acceptedTypes) { + this.index = index; + this.capacity = capacity; + this.acceptedTypes = acceptedTypes; + } + + @Override public FluidType getType(ItemStack stack, IInventory inventory) { return acceptedTypes[0]; } + @Override public void setType(ItemStack stack, FluidType type) { } + @Override public int getCapacity(ItemStack stack) { return capacity; } + + @Override + public void useUpAmmo(ItemStack stack, IInventory inventory, int amount) { + this.setAmount(stack, this.getAmount(stack, inventory) - amount); + } + + @Override public int getAmount(ItemStack stack, IInventory inventory) { return getMagCount(stack, index); } + @Override public void setAmount(ItemStack stack, int amount) { setMagCount(stack, index, amount); } + + @Override public boolean canReload(ItemStack stack, IInventory inventory) { return false; } + @Override public void initNewType(ItemStack stack, IInventory inventory) { } + @Override public void reloadAction(ItemStack stack, IInventory inventory) { } + @Override public SpentCasing getCasing(ItemStack stack, IInventory inventory) { return null; } + + @Override public ItemStack getIconForHUD(ItemStack stack, EntityPlayer player) { return new ItemStack(ModItems.fluid_icon, 1, this.getType(stack, player.inventory).getID()); } + @Override public String reportAmmoStateForHUD(ItemStack stack, EntityPlayer player) { return getAmount(stack, player.inventory) + "mB"; } + + @Override public void setAmountBeforeReload(ItemStack stack, int amount) { ItemGunBaseNT.setValueInt(stack, KEY_MAG_PREV + index, amount); } + @Override public int getAmountBeforeReload(ItemStack stack) { return ItemGunBaseNT.getValueInt(stack, KEY_MAG_PREV + index); } + @Override public void setAmountAfterReload(ItemStack stack, int amount) { ItemGunBaseNT.setValueInt(stack, KEY_MAG_AFTER + index, amount); } + @Override public int getAmountAfterReload(ItemStack stack) { return ItemGunBaseNT.getValueInt(stack, KEY_MAG_AFTER + index); } + + public static int getMagCount(ItemStack stack, int index) { return ItemGunBaseNT.getValueInt(stack, KEY_MAG_COUNT + index); } + public static void setMagCount(ItemStack stack, int index, int value) { ItemGunBaseNT.setValueInt(stack, KEY_MAG_COUNT + index, value); } +} diff --git a/src/main/java/com/hbm/particle/helper/SkeletonCreator.java b/src/main/java/com/hbm/particle/helper/SkeletonCreator.java index 059ae65a8..ed789c60d 100644 --- a/src/main/java/com/hbm/particle/helper/SkeletonCreator.java +++ b/src/main/java/com/hbm/particle/helper/SkeletonCreator.java @@ -60,6 +60,7 @@ public class SkeletonCreator implements IParticleCreator { float force = data.getFloat("force"); int entityID = data.getInteger("entityID"); Entity entity = world.getEntityByID(entityID); + boolean skel = entity instanceof EntitySkeleton; if(!(entity instanceof EntityLivingBase)) return; EntityLivingBase living = (EntityLivingBase) entity; @@ -72,12 +73,16 @@ public class SkeletonCreator implements IParticleCreator { if(bonealizer != null) { BoneDefinition[] bones = bonealizer.apply(living); for(BoneDefinition bone : bones) { - if(gib && rand.nextBoolean()) continue; + if(gib && rand.nextBoolean() && !skel) continue; ParticleSkeleton skeleton = new ParticleSkeleton(Minecraft.getMinecraft().getTextureManager(), world, bone.x, bone.y, bone.z, brightness, brightness, brightness, bone.type); skeleton.prevRotationYaw = skeleton.rotationYaw = bone.yaw; skeleton.prevRotationPitch = skeleton.rotationPitch = bone.pitch; if(gib) { skeleton.makeGib(); + if(skel) { + skeleton.useTexture = skeleton.texture; + skeleton.useTextureExt = skeleton.texture_ext; + } skeleton.motionX = rand.nextGaussian() * force; skeleton.motionY = (rand.nextGaussian() + 1) * force; skeleton.motionZ = rand.nextGaussian() * force; diff --git a/src/main/java/com/hbm/render/item/weapon/sedna/ItemRenderDrill.java b/src/main/java/com/hbm/render/item/weapon/sedna/ItemRenderDrill.java index dc77ef450..e16341924 100644 --- a/src/main/java/com/hbm/render/item/weapon/sedna/ItemRenderDrill.java +++ b/src/main/java/com/hbm/render/item/weapon/sedna/ItemRenderDrill.java @@ -3,6 +3,7 @@ package com.hbm.render.item.weapon.sedna; import org.lwjgl.opengl.GL11; import com.hbm.items.weapon.sedna.ItemGunBaseNT; +import com.hbm.items.weapon.sedna.mags.IMagazine; import com.hbm.main.ResourceManager; import net.minecraft.client.Minecraft; @@ -20,43 +21,61 @@ public class ItemRenderDrill extends ItemRenderWeaponBase { float offset = 0.8F; standardAimingTransform(stack, -1.25F * offset, -1.75F * offset, 1.75F * offset, - 0, -4.6825 / 8D, 0.75); - - GL11.glRotated(15, 0, 1, 0); - GL11.glRotated(-10, 1, 0, 0); + -1F * offset, -1.75F * offset, 1.25F * offset); } @Override public void renderFirstPerson(ItemStack stack) { - + ItemGunBaseNT gun = (ItemGunBaseNT) stack.getItem(); Minecraft.getMinecraft().renderEngine.bindTexture(ResourceManager.drill_tex); double scale = 0.375D; GL11.glScaled(scale, scale, scale); + IMagazine mag = gun.getConfig(stack, 0).getReceivers(stack)[0].getMagazine(stack); + double gauge = (double) mag.getAmount(stack, null) / (double) mag.getCapacity(stack); + + float aimingProgress = ItemGunBaseNT.prevAimingProgress + (ItemGunBaseNT.aimingProgress - ItemGunBaseNT.prevAimingProgress) * interp; + GL11.glRotated(15 * (1 - aimingProgress), 0, 1, 0); + GL11.glRotated(-10 * (1 - aimingProgress), 1, 0, 0); + GL11.glShadeModel(GL11.GL_SMOOTH); ResourceManager.drill.renderPart("Base"); GL11.glPushMatrix(); GL11.glTranslated(1, 2.0625, -1.75); GL11.glRotated(45, 1, 0, 0); - GL11.glRotated(-135, 0, 0, 1); + GL11.glRotated(-135 + gauge * 270, 0, 0, 1); GL11.glRotated(-45, 1, 0, 0); GL11.glTranslated(-1, -2.0625, 1.75); ResourceManager.drill.renderPart("Gauge"); GL11.glPopMatrix(); - + + double rot = System.currentTimeMillis() / 3 % 360D; + double rot2 = rot * 5; + + GL11.glPushMatrix(); + GL11.glTranslated(0, Math.sin(rot2 * Math.PI / 180) * 0.125 - 0.125, 0); ResourceManager.drill.renderPart("Piston1"); - ResourceManager.drill.renderPart("Piston2"); - ResourceManager.drill.renderPart("Piston3"); + GL11.glPopMatrix(); GL11.glPushMatrix(); - GL11.glRotated(System.currentTimeMillis() / 3 % 360D, 0, 0, -1); + GL11.glTranslated(0, Math.sin(rot2 * Math.PI / 180 + Math.PI * 2D / 3D) * 0.125 - 0.125, 0); + ResourceManager.drill.renderPart("Piston2"); + GL11.glPopMatrix(); + + GL11.glPushMatrix(); + GL11.glTranslated(0, Math.sin(rot2 * Math.PI / 180 + Math.PI * 4D / 3D) * 0.125 - 0.125, 0); + ResourceManager.drill.renderPart("Piston3"); + GL11.glPopMatrix(); + + GL11.glPushMatrix(); + GL11.glRotated(rot, 0, 0, -1); ResourceManager.drill.renderPart("DrillBack"); GL11.glPopMatrix(); GL11.glPushMatrix(); - GL11.glRotated(System.currentTimeMillis() / 3 % 360D, 0, 0, 1); + GL11.glRotated(rot, 0, 0, 1); ResourceManager.drill.renderPart("DrillFront"); GL11.glPopMatrix(); @@ -66,7 +85,7 @@ public class ItemRenderDrill extends ItemRenderWeaponBase { @Override public void setupThirdPerson(ItemStack stack) { super.setupThirdPerson(stack); - double scale = 1.75D; + double scale = 2.25D; GL11.glScaled(scale, scale, scale); GL11.glTranslated(1, -2, 6); } @@ -83,10 +102,10 @@ public class ItemRenderDrill extends ItemRenderWeaponBase { @Override public void setupModTable(ItemStack stack) { - double scale = -7.5D; + double scale = -8.75D; GL11.glScaled(scale, scale, scale); GL11.glRotated(90, 0, 1, 0); - GL11.glTranslated(0, 2, 0); + GL11.glTranslated(0, 0, 0); } @Override diff --git a/src/main/java/com/hbm/tileentity/network/TileEntityCraneInserter.java b/src/main/java/com/hbm/tileentity/network/TileEntityCraneInserter.java index 3d55bf30f..266bd2332 100644 --- a/src/main/java/com/hbm/tileentity/network/TileEntityCraneInserter.java +++ b/src/main/java/com/hbm/tileentity/network/TileEntityCraneInserter.java @@ -5,6 +5,8 @@ import com.hbm.interfaces.IControlReceiver; import com.hbm.inventory.container.ContainerCraneInserter; import com.hbm.inventory.gui.GUICraneInserter; import com.hbm.tileentity.IGUIProvider; +import com.hbm.tileentity.TileEntityProxyBase; +import com.hbm.tileentity.machine.TileEntityMachineArcFurnaceLarge; import com.hbm.util.InventoryUtil; import cpw.mods.fml.relauncher.Side; @@ -40,7 +42,7 @@ public class TileEntityCraneInserter extends TileEntityCraneBase implements IGUI super.updateEntity(); if(!worldObj.isRemote) { - if (!this.worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord)) {ForgeDirection outputSide = getOutputSide(); + if(!this.worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord)) {ForgeDirection outputSide = getOutputSide(); TileEntity te = worldObj.getTileEntity(xCoord + outputSide.offsetX, yCoord + outputSide.offsetY, zCoord + outputSide.offsetZ); int[] access = null; @@ -51,6 +53,8 @@ public class TileEntityCraneInserter extends TileEntityCraneBase implements IGUI access = InventoryUtil.masquerade(sided, outputSide.getOpposite().ordinal()); } + boolean didSomething = false; + if(te instanceof IInventory) { for(int i = 0; i < slots.length; i++) { @@ -62,26 +66,44 @@ public class TileEntityCraneInserter extends TileEntityCraneBase implements IGUI if(ret == null || ret.stackSize != stack.stackSize) { slots[i] = ret; this.markDirty(); - return; + didSomething = true; + break; } } } //if the previous operation fails, repeat but use single items instead of the whole stack instead //this should fix cases where the inserter can't insert into something that has a stack size limitation - for(int i = 0; i < slots.length; i++) { + if(!didSomething) for(int i = 0; i < slots.length; i++) { ItemStack stack = slots[i]; if(stack != null) { stack = stack.copy(); - stack.stackSize = 1; + + int overshoot = 0; + if(te instanceof TileEntityProxyBase) te = ((TileEntityProxyBase) te).getTE(); // we can't get this far without some slots being exposed, so the result has to be compatible with IInventory anyway + if(te instanceof TileEntityMachineArcFurnaceLarge) { + int toInsert = Math.min(stack.stackSize, ((TileEntityMachineArcFurnaceLarge) te).getMaxInputSize()); + overshoot = stack.stackSize - toInsert; + stack.stackSize = toInsert; + } else { + stack.stackSize = 1; + } + ItemStack ret = CraneInserter.addToInventory((IInventory) te, access, stack.copy(), outputSide.getOpposite().ordinal()); if(ret == null || ret.stackSize != stack.stackSize) { - this.decrStackSize(i, 1); + slots[i] = ret; + if(slots[1] != null) { + slots[i].stackSize += overshoot; + } else if(overshoot > 0){ + slots[i] = stack.copy(); + slots[i].stackSize = overshoot; + } this.markDirty(); - return; + didSomething = true; + break; } } } diff --git a/src/main/resources/assets/hbm/textures/gui/storage/gui_crane_router.png b/src/main/resources/assets/hbm/textures/gui/storage/gui_crane_router.png index 76796614489e5f3db6670236e2ae8c1118b11ea1..0957afd8cc2d8eb13e7a1be8607942ca6eb3aee5 100644 GIT binary patch literal 3655 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 C^n0xU literal 3351 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 MGZ!$7(=HGG2Tb<*Pyhe` diff --git a/src/main/resources/assets/hbm/textures/models/weapons/drill.png b/src/main/resources/assets/hbm/textures/models/weapons/drill.png index c07d7c3a2f0cf31f71e8aa13a0b7229d04a339a5..de7c228a8f600c8e8deb5faf9cfab62842dfed75 100644 GIT binary patch literal 7402 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

s_?B*Q--hVZemuRxy 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 L72=K2&Dj3~*}^SO literal 3404 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 W?NsWiKHzu+a{bQZFvT(K>i+@&B8I8}