diff --git a/src/main/java/mekanism/common/config/GeneralConfig.java b/src/main/java/mekanism/common/config/GeneralConfig.java index 39e042adce5..42724c16e7a 100644 --- a/src/main/java/mekanism/common/config/GeneralConfig.java +++ b/src/main/java/mekanism/common/config/GeneralConfig.java @@ -106,9 +106,23 @@ public class GeneralConfig extends BaseConfig { public final DoubleOption ENERGY_PER_REDSTONE = new DoubleOption(this, "general", "EnergyPerRedstone", 10000D, "How much energy (Joules) a piece of redstone gives in machines."); - public final IntOption DISASSEMBLER_USAGE = new IntOption(this, "general", "DisassemblerEnergyUsage", 10, + public final IntOption disassemblerEnergyUsage = new IntOption(this, "general", "DisassemblerEnergyUsage", 10, "Base Energy (Joules) usage of the Atomic Disassembler. (Gets multiplied by speed factor)"); + public final IntOption disassemblerEnergyUsageHoe = new IntOption(this, "general", "DisassemblerEnergyUsageHoe", 10, + "Cost in Joules of using the Atomic Disassembler as a hoe."); + + public final IntOption disassemblerEnergyUsageWeapon = new IntOption(this, "general", "DisassemblerEnergyUsageWeapon", 2000, + "Cost in Joules of using the Atomic Disassembler as a weapon."); + + public final IntOption disassemblerDamageMin = new IntOption(this, "general", "DisassemblerDamageMin", 4, + "The amount of damage the Atomic Disassembler does when it is out of power. (Value is in number of half hearts)"); + + public final IntOption disassemblerDamageMax = new IntOption(this, "general", "DisassemblerDamageMax", 20, + "The amount of damage the Atomic Disassembler does when it has at least DisassemblerEnergyUsageWeapon power stored. (Value is in number of half hearts)"); + + public final DoubleOption disassemblerBatteryCapacity = new DoubleOption(this, "general", "DisassemblerBatteryCapacity", 1000000, "Maximum amount (joules) of energy the Atomic Disassembler can contain", 0, Double.MAX_VALUE).setRequiresGameRestart(true); + public final IntOption VOICE_PORT = new IntOption(this, "general", "VoicePort", 36123, "TCP port for the Voice server to listen on.", 1, 65535); diff --git a/src/main/java/mekanism/common/item/ItemAtomicDisassembler.java b/src/main/java/mekanism/common/item/ItemAtomicDisassembler.java index 727eb80e751..25d16321c79 100644 --- a/src/main/java/mekanism/common/item/ItemAtomicDisassembler.java +++ b/src/main/java/mekanism/common/item/ItemAtomicDisassembler.java @@ -17,6 +17,7 @@ import mekanism.common.util.LangUtils; import net.minecraft.block.Block; import net.minecraft.block.BlockDirt; +import net.minecraft.block.BlockDirt.DirtType; import net.minecraft.block.state.IBlockState; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.EntityLivingBase; @@ -39,16 +40,15 @@ import net.minecraft.util.text.TextComponentString; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants.WorldEvents; +import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.items.ItemHandlerHelper; public class ItemAtomicDisassembler extends ItemEnergized { - public double HOE_USAGE = 10 * MekanismConfig.current().general.DISASSEMBLER_USAGE.val(); - public ItemAtomicDisassembler() { - super(1000000); + super(MekanismConfig.current().general.disassemblerBatteryCapacity.val()); } @Override @@ -60,41 +60,42 @@ public boolean canHarvestBlock(@Nonnull IBlockState state, ItemStack stack) { @Override public void addInformation(ItemStack itemstack, World world, List list, ITooltipFlag flag) { super.addInformation(itemstack, world, list, flag); - list.add(LangUtils.localize("tooltip.mode") + ": " + EnumColor.INDIGO + getModeName(itemstack)); - list.add(LangUtils.localize("tooltip.efficiency") + ": " + EnumColor.INDIGO + getEfficiency(itemstack)); + Mode mode = getMode(itemstack); + list.add(LangUtils.localize("tooltip.mode") + ": " + EnumColor.INDIGO + mode.getModeName()); + list.add(LangUtils.localize("tooltip.efficiency") + ": " + EnumColor.INDIGO + mode.getEfficiency()); } @Override public boolean hitEntity(ItemStack itemstack, EntityLivingBase target, EntityLivingBase attacker) { - if (getEnergy(itemstack) > 0) { - if (attacker instanceof EntityPlayer) { - target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) attacker), 20); - } else { - target.attackEntityFrom(DamageSource.causeMobDamage(attacker), 20); - } - setEnergy(itemstack, getEnergy(itemstack) - 2000); + double energy = getEnergy(itemstack); + int energyCost = MekanismConfig.current().general.disassemblerEnergyUsageWeapon.val(); + int minDamage = MekanismConfig.current().general.disassemblerDamageMin.val(); + int damageDifference = MekanismConfig.current().general.disassemblerDamageMax.val() - minDamage; + //If we don't have enough power use it at a reduced power level + double percent = 1; + if (energy < energyCost && energyCost != 0) { + percent = energy / energyCost; + } + float damage = (float) (minDamage + damageDifference * percent); + if (attacker instanceof EntityPlayer) { + target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) attacker), damage); } else { - if (attacker instanceof EntityPlayer) { - target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) attacker), 4); - } else { - target.attackEntityFrom(DamageSource.causeMobDamage(attacker), 4); - } + target.attackEntityFrom(DamageSource.causeMobDamage(attacker), damage); + } + if (energy > 0) { + setEnergy(itemstack, energy - energyCost); } return false; } @Override public float getDestroySpeed(ItemStack itemstack, IBlockState state) { - return getEnergy(itemstack) != 0 ? getEfficiency(itemstack) : 1F; + return getEnergy(itemstack) != 0 ? getMode(itemstack).getEfficiency() : 1F; } @Override public boolean onBlockDestroyed(ItemStack itemstack, World world, IBlockState state, BlockPos pos, EntityLivingBase entityliving) { - if (state.getBlockHardness(world, pos) != 0.0D) { - setEnergy(itemstack, getEnergy(itemstack) - (MekanismConfig.current().general.DISASSEMBLER_USAGE.val() * getEfficiency(itemstack))); - } else { - setEnergy(itemstack, getEnergy(itemstack) - (MekanismConfig.current().general.DISASSEMBLER_USAGE.val() * getEfficiency(itemstack) / 2F)); - } + setEnergy(itemstack, getEnergy(itemstack) - getDestroyEnergy(itemstack, state.getBlockHardness(world, pos))); return true; } @@ -111,27 +112,31 @@ private RayTraceResult doRayTrace(IBlockState state, BlockPos pos, EntityPlayer @Override public boolean onBlockStartBreak(ItemStack itemstack, BlockPos pos, EntityPlayer player) { super.onBlockStartBreak(itemstack, pos, player); - if (!player.world.isRemote) { + if (!player.world.isRemote && !player.capabilities.isCreativeMode && getMode(itemstack) == Mode.VEIN) { IBlockState state = player.world.getBlockState(pos); Block block = state.getBlock(); - int meta = block.getMetaFromState(state); if (block == Blocks.LIT_REDSTONE_ORE) { block = Blocks.REDSTONE_ORE; } RayTraceResult raytrace = doRayTrace(state, pos, player); ItemStack stack = block.getPickBlock(state, raytrace, player.world, pos, player); - Coord4D orig = new Coord4D(pos, player.world); List names = OreDictCache.getOreDictName(stack); boolean isOre = false; for (String s : names) { if (s.startsWith("ore") || s.equals("logWood")) { isOre = true; + break; } } - if (getMode(itemstack) == 3 && isOre && !player.capabilities.isCreativeMode) { - Set found = new Finder(player, stack, new Coord4D(pos, player.world), raytrace).calc(); + if (isOre) { + Coord4D orig = new Coord4D(pos, player.world); + Set found = new Finder(player, stack, orig, raytrace).calc(); for (Coord4D coord : found) { - if (coord.equals(orig) || getEnergy(itemstack) < (MekanismConfig.current().general.DISASSEMBLER_USAGE.val() * getEfficiency(itemstack))) { + if (coord.equals(orig)) { + continue; + } + int destroyEnergy = getDestroyEnergy(itemstack, coord.getBlockState(player.world).getBlockHardness(player.world, coord.getPos())); + if (getEnergy(itemstack) < destroyEnergy) { continue; } Block block2 = coord.getBlock(player.world); @@ -140,7 +145,7 @@ public boolean onBlockStartBreak(ItemStack itemstack, BlockPos pos, EntityPlayer player.world.setBlockToAir(coord.getPos()); block2.breakBlock(player.world, coord.getPos(), state); block2.dropBlockAsItem(player.world, coord.getPos(), state, 0); - setEnergy(itemstack, getEnergy(itemstack) - (MekanismConfig.current().general.DISASSEMBLER_USAGE.val() * getEfficiency(itemstack))); + setEnergy(itemstack, getEnergy(itemstack) - destroyEnergy); } } } @@ -159,8 +164,9 @@ public ActionResult onItemRightClick(World world, EntityPlayer entity if (entityplayer.isSneaking()) { if (!world.isRemote) { toggleMode(itemstack); + Mode mode = getMode(itemstack); entityplayer.sendMessage(new TextComponentString(EnumColor.DARK_BLUE + Mekanism.LOG_TAG + " " + EnumColor.GREY + LangUtils.localize("tooltip.modeToggle") - + " " + EnumColor.INDIGO + getModeName(itemstack) + EnumColor.AQUA + " (" + getEfficiency(itemstack) + ")")); + + " " + EnumColor.INDIGO + mode.getModeName() + EnumColor.AQUA + " (" + mode.getEfficiency() + ")")); } return new ActionResult<>(EnumActionResult.SUCCESS, itemstack); } @@ -170,102 +176,89 @@ public ActionResult onItemRightClick(World world, EntityPlayer entity @Nonnull @Override public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { - ItemStack stack = player.getHeldItem(hand); - Block block = world.getBlockState(pos).getBlock(); - if (!player.isSneaking() && (block == Blocks.DIRT || block == Blocks.GRASS_PATH)) { - if (useHoe(stack, player, world, pos, side) == EnumActionResult.FAIL) { - return EnumActionResult.FAIL; - } - switch (getEfficiency(stack)) { - case 20: - for (int x1 = -1; x1 <= +1; x1++) { - for (int z1 = -1; z1 <= +1; z1++) { - useHoe(stack, player, world, pos.add(x1, 0, z1), side); - } - } - break; - case 128: - for (int x1 = -2; x1 <= +2; x1++) { - for (int z1 = -2; z1 <= +2; z1++) { - useHoe(stack, player, world, pos.add(x1, 0, z1), side); - } - } - break; - } - return EnumActionResult.SUCCESS; - } else if (!player.isSneaking() && block == Blocks.GRASS) { - if (useShovel(stack, player, world, pos, side) == EnumActionResult.FAIL) { - return EnumActionResult.FAIL; + if (!player.isSneaking()) { + ItemStack stack = player.getHeldItem(hand); + int diameter = getMode(stack).getDiameter(); + if (diameter > 0) { + Block block = world.getBlockState(pos).getBlock(); + if (block == Blocks.DIRT || block == Blocks.GRASS_PATH) { + return useItemAs(player, world, pos, side, stack, diameter, this::useHoe); + } else if (block == Blocks.GRASS) { + return useItemAs(player, world, pos, side, stack, diameter, this::useShovel); + } } - switch (getEfficiency(stack)) { - case 20: - for (int x1 = -1; x1 <= +1; x1++) { - for (int z1 = -1; z1 <= +1; z1++) { - useShovel(stack, player, world, pos.add(x1, 0, z1), side); - } - } - break; - case 128: - for (int x1 = -2; x1 <= +2; x1++) { - for (int z1 = -2; z1 <= +2; z1++) { - useShovel(stack, player, world, pos.add(x1, 0, z1), side); - } - } + } + return EnumActionResult.PASS; + } + + private EnumActionResult useItemAs(EntityPlayer player, World world, BlockPos pos, EnumFacing side, ItemStack stack, int diameter, ItemUseConsumer consumer) { + double energy = getEnergy(stack); + int hoeUsage = MekanismConfig.current().general.disassemblerEnergyUsageHoe.val(); + if (energy < hoeUsage || consumer.use(stack, player, world, pos, side) == EnumActionResult.FAIL) { + //Fail if we don't have enough energy or using the item failed + return EnumActionResult.FAIL; + } + double energyUsed = hoeUsage; + int radius = (diameter - 1) / 2; + for (int x = -radius; x <= radius; x++) { + for (int z = -radius; z <= radius; z++) { + if (energyUsed + hoeUsage > energy) { break; + } else if ((x != 0 || z != 0) && consumer.use(stack, player, world, pos.add(x, 0, z), side) == EnumActionResult.SUCCESS) { + //Don't attempt to use it on the source location as it was already done above + // If we successfully used it in a spot increment how much energy we used + energyUsed += hoeUsage; + } } - return EnumActionResult.SUCCESS; } - return EnumActionResult.PASS; + setEnergy(stack, energy - energyUsed); + return EnumActionResult.SUCCESS; } - private EnumActionResult useHoe(ItemStack stack, EntityPlayer playerIn, World worldIn, BlockPos pos, EnumFacing facing) { - if (!playerIn.canPlayerEdit(pos.offset(facing), facing, stack)) { + private EnumActionResult useHoe(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing facing) { + if (!player.canPlayerEdit(pos.offset(facing), facing, stack)) { return EnumActionResult.FAIL; } - int hook = net.minecraftforge.event.ForgeEventFactory.onHoeUse(stack, playerIn, worldIn, pos); + int hook = ForgeEventFactory.onHoeUse(stack, player, world, pos); if (hook != 0) { return hook > 0 ? EnumActionResult.SUCCESS : EnumActionResult.FAIL; } - IBlockState iblockstate = worldIn.getBlockState(pos); - Block block = iblockstate.getBlock(); - if (facing != EnumFacing.DOWN && worldIn.isAirBlock(pos.up())) { + if (facing != EnumFacing.DOWN && world.isAirBlock(pos.up())) { + IBlockState state = world.getBlockState(pos); + Block block = state.getBlock(); + IBlockState newState = null; if (block == Blocks.GRASS || block == Blocks.GRASS_PATH) { - setBlock(stack, playerIn, worldIn, pos, Blocks.FARMLAND.getDefaultState()); - return EnumActionResult.SUCCESS; - } - if (block == Blocks.DIRT) { - switch (iblockstate.getValue(BlockDirt.VARIANT)) { - case DIRT: - setBlock(stack, playerIn, worldIn, pos, Blocks.FARMLAND.getDefaultState()); - return EnumActionResult.SUCCESS; - case COARSE_DIRT: - setBlock(stack, playerIn, worldIn, pos, Blocks.DIRT.getDefaultState() - .withProperty(BlockDirt.VARIANT, BlockDirt.DirtType.DIRT)); - return EnumActionResult.SUCCESS; - default: - return EnumActionResult.PASS; + newState = Blocks.FARMLAND.getDefaultState(); + } else if (block == Blocks.DIRT) { + DirtType type = state.getValue(BlockDirt.VARIANT); + if (type == DirtType.DIRT) { + newState = Blocks.FARMLAND.getDefaultState(); + } else if (type == DirtType.COARSE_DIRT) { + newState = Blocks.DIRT.getDefaultState().withProperty(BlockDirt.VARIANT, DirtType.DIRT); } } + if (newState != null) { + setBlock(stack, player, world, pos, newState); + return EnumActionResult.SUCCESS; + } } return EnumActionResult.PASS; } - private EnumActionResult useShovel(ItemStack stack, EntityPlayer playerIn, World worldIn, BlockPos pos, EnumFacing facing) { - if (!playerIn.canPlayerEdit(pos.offset(facing), facing, stack)) { + private EnumActionResult useShovel(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing facing) { + if (!player.canPlayerEdit(pos.offset(facing), facing, stack)) { return EnumActionResult.FAIL; - } - IBlockState iblockstate = worldIn.getBlockState(pos); - Block block = iblockstate.getBlock(); - if (facing != EnumFacing.DOWN && worldIn.isAirBlock(pos.up())) { + } else if (facing != EnumFacing.DOWN && world.isAirBlock(pos.up())) { + Block block = world.getBlockState(pos).getBlock(); if (block == Blocks.GRASS) { - setBlock(stack, playerIn, worldIn, pos, Blocks.GRASS_PATH.getDefaultState()); + setBlock(stack, player, world, pos, Blocks.GRASS_PATH.getDefaultState()); return EnumActionResult.SUCCESS; } } return EnumActionResult.PASS; } - protected void setBlock(ItemStack stack, EntityPlayer player, World worldIn, BlockPos pos, IBlockState state) { + private void setBlock(ItemStack stack, EntityPlayer player, World worldIn, BlockPos pos, IBlockState state) { worldIn.playSound(player, pos, SoundEvents.ITEM_HOE_TILL, SoundCategory.BLOCKS, 1.0F, 1.0F); if (!worldIn.isRemote) { worldIn.setBlockState(pos, state, 11); @@ -273,45 +266,21 @@ protected void setBlock(ItemStack stack, EntityPlayer player, World worldIn, Blo } } - public int getEfficiency(ItemStack itemStack) { - switch (getMode(itemStack)) { - case 0: - return 20; - case 1: - return 8; - case 2: - return 128; - case 3: - return 20; - case 4: - return 0; - } - return 0; + private int getDestroyEnergy(ItemStack itemStack, float hardness) { + int destroyEnergy = MekanismConfig.current().general.disassemblerEnergyUsage.val() * getMode(itemStack).getEfficiency(); + return hardness == 0 ? destroyEnergy / 2 : destroyEnergy; } - public int getMode(ItemStack itemStack) { - return ItemDataUtils.getInt(itemStack, "mode"); - } - - public String getModeName(ItemStack itemStack) { - int mode = getMode(itemStack); - switch (mode) { - case 0: - return LangUtils.localize("tooltip.disassembler.normal"); - case 1: - return LangUtils.localize("tooltip.disassembler.slow"); - case 2: - return LangUtils.localize("tooltip.disassembler.fast"); - case 3: - return LangUtils.localize("tooltip.disassembler.vein"); - case 4: - return LangUtils.localize("tooltip.disassembler.off"); - } - return null; + public Mode getMode(ItemStack itemStack) { + Mode[] values = Mode.values(); + //If it is out of bounds just shift it as if it had gone around that many times + int mode = ItemDataUtils.getInt(itemStack, "mode") % values.length; + return values[mode]; } public void toggleMode(ItemStack itemStack) { - ItemDataUtils.setInt(itemStack, "mode", getMode(itemStack) < 4 ? getMode(itemStack) + 1 : 0); + Mode mode = getMode(itemStack); + ItemDataUtils.setInt(itemStack, "mode", (mode.ordinal() + 1) % Mode.values().length); } @Override @@ -323,12 +292,42 @@ public boolean canSend(ItemStack itemStack) { @Override @Deprecated public Multimap getItemAttributeModifiers(EntityEquipmentSlot equipmentSlot) { - Multimap multimap = super.getItemAttributeModifiers(equipmentSlot); + Multimap multiMap = super.getItemAttributeModifiers(equipmentSlot); if (equipmentSlot == EntityEquipmentSlot.MAINHAND) { - multimap.put(SharedMonsterAttributes.ATTACK_SPEED.getName(), - new AttributeModifier(ATTACK_SPEED_MODIFIER, "Weapon modifier", -2.4000000953674316D, 0)); + multiMap.put(SharedMonsterAttributes.ATTACK_SPEED.getName(), new AttributeModifier(ATTACK_SPEED_MODIFIER, "Weapon modifier", -2.4000000953674316D, 0)); + } + return multiMap; + } + + public enum Mode { + NORMAL("normal", 20, 3), + SLOW("slow", 8, 1), + FAST("fast", 128, 5), + VEIN("vein", 20, 3), + OFF("off", 0, 0); + + private final String mode; + private final int efficiency; + //Must be odd, or zero + private final int diameter; + + Mode(String mode, int efficiency, int diameter) { + this.mode = mode; + this.efficiency = efficiency; + this.diameter = diameter; + } + + public String getModeName() { + return LangUtils.localize("tooltip.disassembler." + mode); + } + + public int getEfficiency() { + return efficiency; + } + + public int getDiameter() { + return diameter; } - return multimap; } public static class Finder { @@ -366,10 +365,14 @@ public void loop(Coord4D pointer) { found.add(pointer); for (EnumFacing side : EnumFacing.VALUES) { Coord4D coord = pointer.offset(side); - ItemStack blockStack = coord.getBlock(world).getPickBlock(coord.getBlockState(world), rayTraceResult, world, coord.getPos(), player); - if (coord.exists(world) && checkID(coord.getBlock(world)) && - (ItemHandlerHelper.canItemStacksStack(stack, blockStack) || (coord.getBlock(world) == startBlock && isWood && coord.getBlockMeta(world) % 4 == stack.getItemDamage() % 4))) { - loop(coord); + if (coord.exists(world)) { + Block block = coord.getBlock(world); + if (checkID(block)) { + ItemStack blockStack = block.getPickBlock(coord.getBlockState(world), rayTraceResult, world, coord.getPos(), player); + if (ItemHandlerHelper.canItemStacksStack(stack, blockStack) || (block == startBlock && isWood && coord.getBlockMeta(world) % 4 == stack.getItemDamage() % 4)) { + loop(coord); + } + } } } } @@ -381,7 +384,15 @@ public Set calc() { public boolean checkID(Block b) { Block origBlock = location.getBlock(world); - return (ignoreBlocks.get(origBlock) == null && b == origBlock) || (ignoreBlocks.get(origBlock) != null && ignoreBlocks.get(origBlock).contains(b)); + List ignored = ignoreBlocks.get(origBlock); + return ignored == null ? b == origBlock : ignored.contains(b); } } + + @FunctionalInterface + interface ItemUseConsumer { + + //Used to reference useHoe and useShovel via lambda references + EnumActionResult use(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing facing); + } } \ No newline at end of file