package de.ellpeck.actuallyadditions.mod.items; import java.util.HashSet; import java.util.List; import java.util.Set; import com.google.common.collect.Multimap; import de.ellpeck.actuallyadditions.mod.ActuallyAdditions; import de.ellpeck.actuallyadditions.mod.blocks.metalists.TheColoredLampColors; import de.ellpeck.actuallyadditions.mod.config.values.ConfigStringListValues; import de.ellpeck.actuallyadditions.mod.inventory.ContainerDrill; import de.ellpeck.actuallyadditions.mod.inventory.GuiHandler; import de.ellpeck.actuallyadditions.mod.items.base.ItemEnergy; import de.ellpeck.actuallyadditions.mod.tile.TileEntityInventoryBase; import de.ellpeck.actuallyadditions.mod.util.ItemStackHandlerAA; import de.ellpeck.actuallyadditions.mod.util.ItemUtil; import de.ellpeck.actuallyadditions.mod.util.StackUtil; import de.ellpeck.actuallyadditions.mod.util.WorldUtil; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.Enchantments; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.EnumRarity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing.Axis; import net.minecraft.util.EnumHand; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; public class ItemDrill extends ItemEnergy { public static final int HARVEST_LEVEL = 4; private static final int ENERGY_USE = 100; public ItemDrill(String name) { super(250000, 1000, name); this.setMaxDamage(0); this.setHasSubtypes(true); this.setHarvestLevel("shovel", HARVEST_LEVEL); this.setHarvestLevel("pickaxe", HARVEST_LEVEL); } /** * Gets all of the Slots from NBT * * @param stack The Drill */ public static void loadSlotsFromNBT(IItemHandlerModifiable slots, ItemStack stack) { NBTTagCompound compound = stack.getTagCompound(); if (compound != null) { TileEntityInventoryBase.loadSlots(slots, compound); } } /** * Writes all of the Slots to NBT * * @param slots The Slots * @param stack The Drill */ public static void writeSlotsToNBT(IItemHandler slots, ItemStack stack) { NBTTagCompound compound = stack.getTagCompound(); if (compound == null) { compound = new NBTTagCompound(); } TileEntityInventoryBase.saveSlots(slots, compound); stack.setTagCompound(compound); } @Override //Places Blocks if the Placing Upgrade is installed public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { ItemStack stack = player.getHeldItem(hand); ItemStack upgrade = this.getHasUpgradeAsStack(stack, ItemDrillUpgrade.UpgradeType.PLACER); if (StackUtil.isValid(upgrade)) { int slot = ItemDrillUpgrade.getSlotToPlaceFrom(upgrade); if (slot >= 0 && slot < InventoryPlayer.getHotbarSize()) { ItemStack equip = player.inventory.getStackInSlot(slot); if (StackUtil.isValid(equip) && equip != stack) { ItemStack toPlaceStack = equip.copy(); WorldUtil.setHandItemWithoutAnnoyingSound(player, hand, toPlaceStack); //tryPlaceItemIntoWorld could throw an Exception try { //Places the Block into the World if (toPlaceStack.onItemUse(player, world, pos, hand, side, hitX, hitY, hitZ) != EnumActionResult.FAIL) { if (!player.capabilities.isCreativeMode) { WorldUtil.setHandItemWithoutAnnoyingSound(player, hand, toPlaceStack.copy()); } } } //Notify the Player and log the Exception catch (Exception e) { ActuallyAdditions.LOGGER.error("Player " + player.getName() + " who should place a Block using a Drill at " + player.posX + ", " + player.posY + ", " + player.posZ + " in World " + world.provider.getDimension() + " threw an Exception! Don't let that happen again!"); } player.inventory.setInventorySlotContents(slot, player.getHeldItem(hand)); WorldUtil.setHandItemWithoutAnnoyingSound(player, hand, stack); return EnumActionResult.SUCCESS; } } } return EnumActionResult.FAIL; } /** * Checks if a certain Upgrade is installed and returns it as an ItemStack * * @param stack The Drill * @param upgrade The Upgrade to be checked * @return The Upgrade, if it's installed */ public ItemStack getHasUpgradeAsStack(ItemStack stack, ItemDrillUpgrade.UpgradeType upgrade) { NBTTagCompound compound = stack.getTagCompound(); if (compound == null) { return StackUtil.getEmpty(); } ItemStackHandlerAA inv = new ItemStackHandlerAA(ContainerDrill.SLOT_AMOUNT); loadSlotsFromNBT(inv, stack); for (int i = 0; i < inv.getSlots(); i++) { ItemStack slotStack = inv.getStackInSlot(i); if (StackUtil.isValid(slotStack) && slotStack.getItem() instanceof ItemDrillUpgrade) { if (((ItemDrillUpgrade) slotStack.getItem()).type == upgrade) { return slotStack; } } } return StackUtil.getEmpty(); } @Override public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { if (!world.isRemote && player.isSneaking() && hand == EnumHand.MAIN_HAND) { player.openGui(ActuallyAdditions.INSTANCE, GuiHandler.GuiTypes.DRILL.ordinal(), world, (int) player.posX, (int) player.posY, (int) player.posZ); } return new ActionResult<>(EnumActionResult.PASS, player.getHeldItem(hand)); } @Override public int getMetadata(int damage) { return damage; } @Override public boolean hitEntity(ItemStack stack, EntityLivingBase entity1, EntityLivingBase entity2) { int use = this.getEnergyUsePerBlock(stack); if (!(entity2 instanceof EntityPlayer) || !((EntityPlayer) entity2).capabilities.isCreativeMode) { if (this.getEnergyStored(stack) >= use) { this.extractEnergyInternal(stack, use, false); } } return true; } @Override public EnumRarity getRarity(ItemStack stack) { return EnumRarity.EPIC; } @Override public Multimap getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack) { Multimap map = super.getAttributeModifiers(slot, stack); if (slot == EntityEquipmentSlot.MAINHAND) { map.put(SharedMonsterAttributes.ATTACK_DAMAGE.getName(), new AttributeModifier(ATTACK_DAMAGE_MODIFIER, "Drill Modifier", this.getEnergyStored(stack) >= ENERGY_USE ? 8.0F : 0.1F, 0)); map.put(SharedMonsterAttributes.ATTACK_SPEED.getName(), new AttributeModifier(ATTACK_SPEED_MODIFIER, "Tool Modifier", -2.5F, 0)); } return map; } @Override public float getDestroySpeed(ItemStack stack, IBlockState state) { return this.getEnergyStored(stack) >= this.getEnergyUsePerBlock(stack) ? this.hasExtraWhitelist(state.getBlock()) || state.getBlock().getHarvestTool(state) == null || state.getBlock().getHarvestTool(state).isEmpty() || this.getToolClasses(stack).contains(state.getBlock().getHarvestTool(state)) ? this.getEfficiencyFromUpgrade(stack) : 1.0F : 0.1F; } @Override public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, EntityPlayer player) { boolean toReturn = false; int use = this.getEnergyUsePerBlock(stack); if (this.getEnergyStored(stack) >= use) { //Enchants the Drill depending on the Upgrades it has if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.SILK_TOUCH)) { ItemUtil.addEnchantment(stack, Enchantments.SILK_TOUCH, 1); } else { if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.FORTUNE)) { ItemUtil.addEnchantment(stack, Enchantments.FORTUNE, this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.FORTUNE_II) ? 3 : 1); } } //Block hit RayTraceResult ray = WorldUtil.getNearestBlockWithDefaultReachDistance(player.world, player); if (ray != null) { //Breaks the Blocks if (!player.isSneaking() && this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.THREE_BY_THREE)) { if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.FIVE_BY_FIVE)) { toReturn = this.breakBlocks(stack, 2, player.world, pos, ray.sideHit, player); } else { toReturn = this.breakBlocks(stack, 1, player.world, pos, ray.sideHit, player); } } else { toReturn = this.breakBlocks(stack, 0, player.world, pos, ray.sideHit, player); } //Removes Enchantments added above ItemUtil.removeEnchantment(stack, Enchantments.SILK_TOUCH); ItemUtil.removeEnchantment(stack, Enchantments.FORTUNE); } } return toReturn; } @Override public boolean canHarvestBlock(IBlockState state, ItemStack stack) { Block block = state.getBlock(); return this.getEnergyStored(stack) >= this.getEnergyUsePerBlock(stack) && (this.hasExtraWhitelist(block) || state.getMaterial().isToolNotRequired() || block == Blocks.SNOW_LAYER || block == Blocks.SNOW || (block == Blocks.OBSIDIAN ? HARVEST_LEVEL >= 3 : block != Blocks.DIAMOND_BLOCK && block != Blocks.DIAMOND_ORE ? block != Blocks.EMERALD_ORE && block != Blocks.EMERALD_BLOCK ? block != Blocks.GOLD_BLOCK && block != Blocks.GOLD_ORE ? block != Blocks.IRON_BLOCK && block != Blocks.IRON_ORE ? block != Blocks.LAPIS_BLOCK && block != Blocks.LAPIS_ORE ? block != Blocks.REDSTONE_ORE && block != Blocks.LIT_REDSTONE_ORE ? state.getMaterial() == Material.ROCK || state.getMaterial() == Material.IRON || state.getMaterial() == Material.ANVIL : HARVEST_LEVEL >= 2 : HARVEST_LEVEL >= 1 : HARVEST_LEVEL >= 1 : HARVEST_LEVEL >= 2 : HARVEST_LEVEL >= 2 : HARVEST_LEVEL >= 2)); } @Override public Set getToolClasses(ItemStack stack) { HashSet hashSet = new HashSet<>(); hashSet.add("pickaxe"); hashSet.add("shovel"); return hashSet; } @Override public int getHarvestLevel(ItemStack stack, String toolClass, EntityPlayer player, IBlockState blockState) { return HARVEST_LEVEL; } /** * Gets the Energy that is used per Block broken * * @param stack The Drill * @return The Energy use per Block */ public int getEnergyUsePerBlock(ItemStack stack) { int use = ENERGY_USE; //Speed if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.SPEED)) { use += 50; if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.SPEED_II)) { use += 75; if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.SPEED_III)) { use += 175; } } } //Silk Touch if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.SILK_TOUCH)) { use += 100; } //Fortune if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.FORTUNE)) { use += 40; if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.FORTUNE_II)) { use += 80; } } //Size if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.THREE_BY_THREE)) { use += 10; if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.FIVE_BY_FIVE)) { use += 30; } } return use; } /** * Checks if a certain Upgrade is applied * * @param stack The Drill * @param upgrade The Upgrade to be checked * @return Is the Upgrade applied? */ public boolean getHasUpgrade(ItemStack stack, ItemDrillUpgrade.UpgradeType upgrade) { return StackUtil.isValid(this.getHasUpgradeAsStack(stack, upgrade)); } @Override protected void registerRendering() { for (int i = 0; i < 16; i++) { String name = this.getRegistryName() + "_" + TheColoredLampColors.values()[i].regName; ActuallyAdditions.PROXY.addRenderRegister(new ItemStack(this, 1, i), new ResourceLocation(name), "inventory"); } } @Override @SideOnly(Side.CLIENT) public void getSubItems(CreativeTabs tabs, NonNullList list) { if (this.isInCreativeTab(tabs)) { for (int i = 0; i < 16; i++) { this.addDrillStack(list, i); } } } private void addDrillStack(List list, int meta) { ItemStack stackFull = new ItemStack(this, 1, meta); this.setEnergy(stackFull, this.getMaxEnergyStored(stackFull)); list.add(stackFull); ItemStack stackEmpty = new ItemStack(this, 1, meta); this.setEnergy(stackEmpty, 0); list.add(stackEmpty); } /** * Gets the Mining Speed of the Drill * * @param stack The Drill * @return The Mining Speed depending on the Speed Upgrades */ public float getEfficiencyFromUpgrade(ItemStack stack) { float efficiency = 8.0F; if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.SPEED)) { if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.SPEED_II)) { if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.SPEED_III)) { efficiency += 37.0F; } else { efficiency += 25.0F; } } else { efficiency += 8.0F; } } if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.THREE_BY_THREE)) { efficiency *= 0.5F; if (this.getHasUpgrade(stack, ItemDrillUpgrade.UpgradeType.FIVE_BY_FIVE)) { efficiency *= 0.35F; } } return efficiency; } /** * Breaks Blocks in a certain Radius * Has to be called on both Server and Client * * @param stack The Drill * @param radius The Radius to break Blocks in (0 means only 1 Block will be broken!) * @param world The World * @param player The Player who breaks the Blocks */ public boolean breakBlocks(ItemStack stack, int radius, World world, BlockPos aPos, EnumFacing side, EntityPlayer player) { int xRange = radius; int yRange = radius; int zRange = 0; //Corrects Blocks to hit depending on Side of original Block hit if (side.getAxis() == Axis.Y) { zRange = radius; yRange = 0; } if (side.getAxis() == Axis.X) { xRange = 0; zRange = radius; } //Not defined later because main Block is getting broken below IBlockState state = world.getBlockState(aPos); float mainHardness = state.getBlockHardness(world, aPos); //Break Middle Block first int use = this.getEnergyUsePerBlock(stack); if (this.getEnergyStored(stack) >= use) { if (!this.tryHarvestBlock(world, aPos, false, stack, player, use)) { return false; } } else { return false; } if (radius == 2 && side.getAxis() != Axis.Y) { aPos = aPos.up(); IBlockState theState = world.getBlockState(aPos); if (theState.getBlockHardness(world, aPos) <= mainHardness + 5.0F) { this.tryHarvestBlock(world, aPos, true, stack, player, use); } } //Break Blocks around if (radius > 0 && mainHardness >= 0.2F) { for (int xPos = aPos.getX() - xRange; xPos <= aPos.getX() + xRange; xPos++) { for (int yPos = aPos.getY() - yRange; yPos <= aPos.getY() + yRange; yPos++) { for (int zPos = aPos.getZ() - zRange; zPos <= aPos.getZ() + zRange; zPos++) { if (!(aPos.getX() == xPos && aPos.getY() == yPos && aPos.getZ() == zPos)) { if (this.getEnergyStored(stack) >= use) { //Only break Blocks around that are (about) as hard or softer BlockPos thePos = new BlockPos(xPos, yPos, zPos); IBlockState theState = world.getBlockState(thePos); if (theState.getBlockHardness(world, thePos) <= mainHardness + 5.0F) { this.tryHarvestBlock(world, thePos, true, stack, player, use); } } else { return false; } } } } } } return true; } /** * Tries to harvest a certain Block * Breaks the Block, drops Particles etc. * Has to be called on both Server and Client * * @param world The World * @param isExtra If the Block is the Block that was looked at when breaking or an additional Block * @param stack The Drill * @param player The Player breaking the Blocks * @param use The Energy that should be extracted per Block */ private boolean tryHarvestBlock(World world, BlockPos pos, boolean isExtra, ItemStack stack, EntityPlayer player, int use) { IBlockState state = world.getBlockState(pos); Block block = state.getBlock(); float hardness = state.getBlockHardness(world, pos); boolean canHarvest = (ForgeHooks.canHarvestBlock(block, player, world, pos) || this.canHarvestBlock(state, stack)) && (!isExtra || this.getDestroySpeed(stack, world.getBlockState(pos)) > 1.0F); if (hardness >= 0.0F && (!isExtra || canHarvest && !block.hasTileEntity(world.getBlockState(pos)))) { if (!player.capabilities.isCreativeMode) { this.extractEnergyInternal(stack, use, false); } //Break the Block return WorldUtil.breakExtraBlock(stack, world, player, pos); } return false; } private boolean hasExtraWhitelist(Block block) { if (block != null) { ResourceLocation location = block.getRegistryName(); if (location != null) { String name = location.toString(); if (name != null) { for (String s : ConfigStringListValues.DRILL_EXTRA_MINING_WHITELIST.getValue()) { if (s != null && s.equals(name)) { return true; } } } } } return false; } @Override public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { return !newStack.isItemEqual(oldStack); } }