package com.hbm.tileentity.machine; import java.util.HashMap; import java.util.List; import java.util.Set; import com.google.common.collect.Sets; import com.hbm.blocks.ModBlocks; import com.hbm.inventory.UpgradeManagerNT; import com.hbm.inventory.container.ContainerMiningLaser; import com.hbm.inventory.fluid.Fluids; import com.hbm.inventory.fluid.tank.FluidTank; import com.hbm.inventory.gui.GUIMiningLaser; import com.hbm.inventory.recipes.CentrifugeRecipes; import com.hbm.inventory.recipes.CrystallizerRecipes; import com.hbm.inventory.recipes.CrystallizerRecipes.CrystallizerRecipe; import com.hbm.inventory.recipes.ShredderRecipes; import com.hbm.items.ModItems; import com.hbm.items.machine.ItemMachineUpgrade; import com.hbm.items.machine.ItemMachineUpgrade.UpgradeType; import com.hbm.lib.Library; import com.hbm.tileentity.IGUIProvider; import com.hbm.tileentity.IUpgradeInfoProvider; import com.hbm.tileentity.TileEntityMachineBase; import com.hbm.util.BobMathUtil; import com.hbm.util.InventoryUtil; import com.hbm.util.fauxpointtwelve.BlockPos; import com.hbm.util.fauxpointtwelve.DirPos; import com.hbm.util.i18n.I18nUtil; import api.hbm.block.IDrillInteraction; import api.hbm.block.IMiningDrill; import api.hbm.energymk2.IEnergyReceiverMK2; import api.hbm.fluid.IFluidStandardSender; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.Container; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.FurnaceRecipes; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.EnumChatFormatting; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; public class TileEntityMachineMiningLaser extends TileEntityMachineBase implements IEnergyReceiverMK2, IMiningDrill, IFluidStandardSender, IGUIProvider, IUpgradeInfoProvider { public long power; public int age = 0; public static final long maxPower = 100000000; public static final int consumption = 10000; public FluidTank tank; public boolean isOn; private boolean redstonePowered; public int targetX; public int targetY; public int targetZ; public int lastTargetX; public int lastTargetY; public int lastTargetZ; public boolean beam; boolean lock = false; double breakProgress; public UpgradeManagerNT upgradeManager = new UpgradeManagerNT(); public TileEntityMachineMiningLaser() { //slot 0: battery //slots 1 - 8: upgrades //slots 9 - 29: output super(30); tank = new FluidTank(Fluids.OIL, 64_000); } @Override public String getName() { return "container.miningLaser"; } private double clientBreakProgress; private DirPos[] getConPos() { return new DirPos[] { new DirPos(xCoord + 2, yCoord, zCoord, Library.POS_X), new DirPos(xCoord - 2, yCoord, zCoord, Library.NEG_X), new DirPos(xCoord, yCoord, zCoord + 2, Library.POS_Z), new DirPos(xCoord, yCoord, zCoord - 2, Library.NEG_Z), }; } private boolean isMultiblockRedstonePowered() { for (DirPos conPos : getConPos()) { BlockPos pos = conPos.offset(conPos.getDir().getOpposite()); if(this.worldObj.isBlockIndirectlyGettingPowered(pos.getX(), pos.getY(), pos.getZ())) { return true; } } return false; } @Override public void updateEntity() { if(!worldObj.isRemote) { this.updateConnections(); for (DirPos pos : getConPos()) { this.sendFluid(tank, worldObj, pos.getX(), pos.getY(), pos.getZ(), pos.getDir()); } power = Library.chargeTEFromItems(slots, 0, power, maxPower); //reset progress if the position changes if(lastTargetX != targetX || lastTargetY != targetY || lastTargetZ != targetZ) breakProgress = 0; //set last positions for interpolation and the like lastTargetX = targetX; lastTargetY = targetY; lastTargetZ = targetZ; boolean prevRedstone = this.redstonePowered; this.redstonePowered = this.isMultiblockRedstonePowered(); if(prevRedstone != this.redstonePowered) { this.markDirty(); } boolean shouldRun = this.isOn && !this.redstonePowered; if(shouldRun) { upgradeManager.checkSlots(this, slots, 1, 8); int cycles = 1 + upgradeManager.getLevel(UpgradeType.OVERDRIVE); int speed = 1 + upgradeManager.getLevel(UpgradeType.SPEED); int range = 1 + upgradeManager.getLevel(UpgradeType.EFFECT) * 2; int fortune = upgradeManager.getLevel(UpgradeType.FORTUNE); int consumption = this.consumption - (this.consumption * upgradeManager.getLevel(UpgradeType.POWER) / 16) + (this.consumption * upgradeManager.getLevel(UpgradeType.SPEED) / 16); for(int i = 0; i < cycles; i++) { if(power < consumption) { beam = false; break; } power -= consumption; if(targetY <= 0) targetY = yCoord - 2; scan(range); Block block = worldObj.getBlock(targetX, targetY, targetZ); if(block.getMaterial().isLiquid()) { worldObj.setBlockToAir(targetX, targetY, targetZ); buildDam(); continue; } if(beam && canBreak(block, targetX, targetY, targetZ)) { breakProgress += getBreakSpeed(speed); clientBreakProgress = Math.min(breakProgress, 1); if(breakProgress < 1) { worldObj.destroyBlockInWorldPartially(-1, targetX, targetY, targetZ, (int) Math.floor(breakProgress * 10)); } else { breakBlock(fortune); buildDam(); } } } } else { targetY = yCoord - 2; beam = false; } for (DirPos pos : getConPos()) { this.tryFillContainer(pos.getX(), pos.getY(), pos.getZ()); } this.networkPackNT(250); } } private void updateConnections() { this.trySubscribe(worldObj, xCoord, yCoord + 2, zCoord, ForgeDirection.UP); } @Override public void serialize(ByteBuf buf) { super.serialize(buf); buf.writeLong(this.power); buf.writeInt(this.lastTargetX); buf.writeInt(this.lastTargetY); buf.writeInt(this.lastTargetZ); buf.writeInt(this.targetX); buf.writeInt(this.targetY); buf.writeInt(this.targetZ); buf.writeBoolean(this.beam); buf.writeBoolean(this.isOn); buf.writeDouble(this.clientBreakProgress); tank.serialize(buf); buf.writeBoolean(this.redstonePowered); } @Override public void deserialize(ByteBuf buf) { super.deserialize(buf); this.power = buf.readLong(); this.lastTargetX = buf.readInt(); this.lastTargetY = buf.readInt(); this.lastTargetZ = buf.readInt(); this.targetX = buf.readInt(); this.targetY = buf.readInt(); this.targetZ = buf.readInt(); this.beam = buf.readBoolean(); this.isOn = buf.readBoolean(); this.breakProgress = buf.readDouble(); tank.deserialize(buf); this.redstonePowered = buf.readBoolean(); } private void buildDam() { for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { if(worldObj.getBlock(targetX + dir.offsetX, targetY + dir.offsetY, targetZ + dir.offsetZ).getMaterial().isLiquid()) worldObj.setBlock(targetX + dir.offsetX, targetY + dir.offsetY, targetZ + dir.offsetZ, ModBlocks.barricade); } } private void tryFillContainer(int x, int y, int z) { Block b = worldObj.getBlock(x, y, z); if(b != Blocks.chest && b != Blocks.trapped_chest && b != ModBlocks.crate_iron && b != ModBlocks.crate_desh && b != ModBlocks.crate_steel && b != ModBlocks.safe && b != Blocks.hopper) return; IInventory inventory = (IInventory)worldObj.getTileEntity(x, y, z); if(inventory == null) return; for(int i = 9; i <= 29; i++) { if(slots[i] != null) { int prev = slots[i].stackSize; slots[i] = InventoryUtil.tryAddItemToInventory(inventory, 0, inventory.getSizeInventory() - 1, slots[i]); if(slots[i] == null || slots[i].stackSize < prev) return; } } } private void breakBlock(int fortune) { Block b = worldObj.getBlock(targetX, targetY, targetZ); int meta = worldObj.getBlockMetadata(targetX, targetY, targetZ); boolean normal = true; boolean doesBreak = true; if(b == Blocks.lit_redstone_ore) b = Blocks.redstone_ore; ItemStack stack = new ItemStack(b, 1, meta); if(stack != null && stack.getItem() != null) { if(hasCrystallizer()) { CrystallizerRecipe result = CrystallizerRecipes.getOutput(stack, Fluids.PEROXIDE); if(result == null) result = CrystallizerRecipes.getOutput(stack, Fluids.SULFURIC_ACID); if(result != null) { worldObj.spawnEntityInWorld(new EntityItem(worldObj, targetX + 0.5, targetY + 0.5, targetZ + 0.5, result.output.copy())); normal = false; } } else if(hasCentrifuge()) { ItemStack[] result = CentrifugeRecipes.getOutput(stack); if(result != null) { for(ItemStack sta : result) { if(sta != null) { worldObj.spawnEntityInWorld(new EntityItem(worldObj, targetX + 0.5, targetY + 0.5, targetZ + 0.5, sta.copy())); normal = false; } } } } else if(hasShredder()) { ItemStack result = ShredderRecipes.getShredderResult(stack); if(result != null && result.getItem() != ModItems.scrap) { worldObj.spawnEntityInWorld(new EntityItem(worldObj, targetX + 0.5, targetY + 0.5, targetZ + 0.5, result.copy())); normal = false; } } else if(hasSmelter()) { ItemStack result = FurnaceRecipes.smelting().getSmeltingResult(stack); if(result != null) { worldObj.spawnEntityInWorld(new EntityItem(worldObj, targetX + 0.5, targetY + 0.5, targetZ + 0.5, result.copy())); normal = false; } } } if(normal && b instanceof IDrillInteraction) { IDrillInteraction in = (IDrillInteraction) b; ItemStack drop = in.extractResource(worldObj, targetX, targetY, targetZ, meta, this); if(drop != null) { worldObj.spawnEntityInWorld(new EntityItem(worldObj, targetX + 0.5, targetY + 0.5, targetZ + 0.5, drop.copy())); } doesBreak = in.canBreak(worldObj, targetX, targetY, targetZ, meta, this); } if(doesBreak) { if(normal) b.dropBlockAsItem(worldObj, targetX, targetY, targetZ, meta, fortune); worldObj.func_147480_a(targetX, targetY, targetZ, false); } suckDrops(); if(doesScream()) { worldObj.playSoundEffect(targetX + 0.5, targetY + 0.5, targetZ + 0.5, "hbm:block.screm", 2000.0F, 1.0F); } breakProgress = 0; } private static final Set bad = Sets.newHashSet(new Item[] { Item.getItemFromBlock(Blocks.dirt), Item.getItemFromBlock(Blocks.stone), Item.getItemFromBlock(Blocks.cobblestone), Item.getItemFromBlock(Blocks.sand), Item.getItemFromBlock(Blocks.sandstone), Item.getItemFromBlock(Blocks.gravel), Item.getItemFromBlock(ModBlocks.basalt), Item.getItemFromBlock(ModBlocks.stone_gneiss), Items.flint, Items.snowball, Items.wheat_seeds }); //hahahahahahahaha he said "suck" private void suckDrops() { int rangeHor = 3; int rangeVer = 1; boolean nullifier = hasNullifier(); List items = worldObj.getEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getBoundingBox( targetX + 0.5 - rangeHor, targetY + 0.5 - rangeVer, targetZ + 0.5 - rangeHor, targetX + 0.5 + rangeHor, targetY + 0.5 + rangeVer, targetZ + 0.5 + rangeHor )); for(EntityItem item : items) { if(item.isDead) continue; if(nullifier && bad.contains(item.getEntityItem().getItem())) { item.setDead(); item.delayBeforeCanPickup = 60; continue; } if(item.getEntityItem().getItem() == Item.getItemFromBlock(ModBlocks.ore_oil)) { tank.setTankType(Fluids.OIL); //just to be sure tank.setFill(tank.getFill() + 500); if(tank.getFill() > tank.getMaxFill()) tank.setFill(tank.getMaxFill()); item.setDead(); item.delayBeforeCanPickup = 60; continue; } ItemStack stack = InventoryUtil.tryAddItemToInventory(slots, 9, 29, item.getEntityItem().copy()); if(stack == null) { item.setDead(); item.delayBeforeCanPickup = 60; } else { item.setEntityItemStack(stack.copy()); //copy is not necessary but i'm paranoid due to the kerfuffle of the old drill } } List mobs = worldObj.getEntitiesWithinAABB(EntityLivingBase.class, AxisAlignedBB.getBoundingBox( targetX + 0.5 - 1, targetY + 0.5 - 1, targetZ + 0.5 - 1, targetX + 0.5 + 1, targetY + 0.5 + 1, targetZ + 0.5 + 1 )); for(EntityLivingBase mob : mobs) { mob.setFire(5); } } public double getBreakSpeed(int speed) { float hardness = worldObj.getBlock(targetX, targetY, targetZ).getBlockHardness(worldObj, targetX, targetY, targetZ) * 15 / speed; if(hardness == 0) return 1; return 1 / hardness; } public void scan(int range) { for(int x = -range; x <= range; x++) { for(int z = -range; z <= range; z++) { if(worldObj.getBlock(x + xCoord, targetY, z + zCoord).getMaterial().isLiquid()) { continue; } if(canBreak(worldObj.getBlock(x + xCoord, targetY, z + zCoord), x + xCoord, targetY, z + zCoord)) { targetX = x + xCoord; targetZ = z + zCoord; beam = true; return; } } } beam = false; targetY--; } private boolean canBreak(Block block, int x, int y, int z) { return !block.isAir(worldObj, x, y, z) && block.getMaterial() != ModBlocks.materialGas && block.getBlockHardness(worldObj, x, y, z) >= 0 && !block.getMaterial().isLiquid() && block != Blocks.bedrock; } public int getRange() { int range = 1; for(int i = 1; i < 9; i++) { if(slots[i] != null) { if(slots[i].getItem() == ModItems.upgrade_effect_1) range += 2; else if(slots[i].getItem() == ModItems.upgrade_effect_2) range += 4; else if(slots[i].getItem() == ModItems.upgrade_effect_3) range += 6; } } return Math.min(range, 25); } public boolean hasNullifier() { for(int i = 1; i < 9; i++) { if(slots[i] != null) { if(slots[i].getItem() == ModItems.upgrade_nullifier) return true; } } return false; } public boolean hasSmelter() { for(int i = 1; i < 9; i++) { if(slots[i] != null) { if(slots[i].getItem() == ModItems.upgrade_smelter) return true; } } return false; } public boolean hasShredder() { for(int i = 1; i < 9; i++) { if(slots[i] != null) { if(slots[i].getItem() == ModItems.upgrade_shredder) return true; } } return false; } public boolean hasCentrifuge() { for(int i = 1; i < 9; i++) { if(slots[i] != null) { if(slots[i].getItem() == ModItems.upgrade_centrifuge) return true; } } return false; } public boolean hasCrystallizer() { for(int i = 1; i < 9; i++) { if(slots[i] != null) { if(slots[i].getItem() == ModItems.upgrade_crystallizer) return true; } } return false; } public boolean doesScream() { for(int i = 1; i < 9; i++) { if(slots[i] != null) { if(slots[i].getItem() == ModItems.upgrade_screm) return true; } } return false; } public int getConsumption() { return this.consumption; } public int getWidth() { return 1 + getRange() * 2; } public int getPowerScaled(int i) { return (int)((power * i) / maxPower); } public int getProgressScaled(int i) { return (int) (breakProgress * i); } @Override public AxisAlignedBB getRenderBoundingBox() { return TileEntity.INFINITE_EXTENT_AABB; } @Override @SideOnly(Side.CLIENT) public double getMaxRenderDistanceSquared() { return 65536.0D; } @Override public boolean canInsertItem(int i, ItemStack itemStack, int j) { return this.isItemValidForSlot(i, itemStack); } @Override public boolean canExtractItem(int i, ItemStack itemStack, int j) { return i >= 9 && i <= 29; } @Override public int[] getAccessibleSlotsFromSide(int slot) { int[] slots = new int[21]; for(int i = 0; i < 21; i++) { slots[i] = i + 9; } return slots; } @Override public void setInventorySlotContents(int i, ItemStack stack) { super.setInventorySlotContents(i, stack); if(stack != null && i >= 1 && i <= 8 && stack.getItem() instanceof ItemMachineUpgrade) worldObj.playSoundEffect(xCoord + 0.5, yCoord + 1.5, zCoord + 0.5, "hbm:item.upgradePlug", 1.0F, 1.0F); } @Override public void setPower(long i) { power = i; } @Override public long getPower() { return power; } @Override public long getMaxPower() { return maxPower; } @Override public void readFromNBT(NBTTagCompound nbt) { super.readFromNBT(nbt); tank.readFromNBT(nbt, "oil"); isOn = nbt.getBoolean("isOn"); redstonePowered = false; } @Override public void writeToNBT(NBTTagCompound nbt) { super.writeToNBT(nbt); tank.writeToNBT(nbt, "oil"); nbt.setBoolean("isOn", isOn); } @Override public DrillType getDrillTier() { return DrillType.HITECH; } @Override public int getDrillRating() { return 100; } @Override public FluidTank[] getSendingTanks() { return new FluidTank[] { tank }; } @Override public FluidTank[] getAllTanks() { return new FluidTank[] { tank }; } @Override public Container provideContainer(int ID, EntityPlayer player, World world, int x, int y, int z) { return new ContainerMiningLaser(player.inventory, this); } @Override @SideOnly(Side.CLIENT) public Object provideGUI(int ID, EntityPlayer player, World world, int x, int y, int z) { return new GUIMiningLaser(player.inventory, this); } @Override public boolean canProvideInfo(UpgradeType type, int level, boolean extendedInfo) { return type == UpgradeType.SPEED || type == UpgradeType.POWER || type == UpgradeType.OVERDRIVE || type == UpgradeType.EFFECT || type == UpgradeType.FORTUNE; } @Override public void provideInfo(UpgradeType type, int level, List info, boolean extendedInfo) { info.add(IUpgradeInfoProvider.getStandardLabel(ModBlocks.machine_mining_laser)); if(type == UpgradeType.SPEED) { info.add(EnumChatFormatting.GREEN + I18nUtil.resolveKey(this.KEY_DELAY, "-" + (100 - 100 / (level + 1)) + "%")); info.add(EnumChatFormatting.RED + I18nUtil.resolveKey(this.KEY_CONSUMPTION, "+" + (100 * level / 16) + "%")); } if(type == UpgradeType.POWER) { info.add(EnumChatFormatting.GREEN + I18nUtil.resolveKey(this.KEY_CONSUMPTION, "-" + (100 * level / 16) + "%")); } if(type == UpgradeType.EFFECT) { info.add(EnumChatFormatting.GREEN + I18nUtil.resolveKey(this.KEY_RANGE, "+" + (2 * level) + "m")); } if(type == UpgradeType.FORTUNE) { info.add(EnumChatFormatting.GREEN + I18nUtil.resolveKey(this.KEY_FORTUNE, "+" + level)); } if(type == UpgradeType.OVERDRIVE) { info.add((BobMathUtil.getBlink() ? EnumChatFormatting.RED : EnumChatFormatting.DARK_GRAY) + "YES"); } } @Override public HashMap getValidUpgrades() { HashMap upgrades = new HashMap<>(); upgrades.put(UpgradeType.SPEED, 12); upgrades.put(UpgradeType.POWER, 12); upgrades.put(UpgradeType.EFFECT, 12); upgrades.put(UpgradeType.FORTUNE, 3); upgrades.put(UpgradeType.OVERDRIVE, 9); return upgrades; } }