001package net.minecraft.block; 002 003import cpw.mods.fml.relauncher.Side; 004import cpw.mods.fml.relauncher.SideOnly; 005import java.util.Random; 006import net.minecraft.block.material.Material; 007import net.minecraft.client.renderer.texture.IconRegister; 008import net.minecraft.creativetab.CreativeTabs; 009import net.minecraft.dispenser.BehaviorDefaultDispenseItem; 010import net.minecraft.dispenser.IBehaviorDispenseItem; 011import net.minecraft.dispenser.IBlockSource; 012import net.minecraft.dispenser.IPosition; 013import net.minecraft.dispenser.IRegistry; 014import net.minecraft.dispenser.PositionImpl; 015import net.minecraft.dispenser.RegistryDefaulted; 016import net.minecraft.entity.EntityLiving; 017import net.minecraft.entity.item.EntityItem; 018import net.minecraft.entity.player.EntityPlayer; 019import net.minecraft.inventory.Container; 020import net.minecraft.inventory.IInventory; 021import net.minecraft.item.ItemStack; 022import net.minecraft.nbt.NBTTagCompound; 023import net.minecraft.tileentity.TileEntity; 024import net.minecraft.tileentity.TileEntityDispenser; 025import net.minecraft.util.EnumFacing; 026import net.minecraft.util.Icon; 027import net.minecraft.world.World; 028 029public class BlockDispenser extends BlockContainer 030{ 031 /** Registry for all dispense behaviors. */ 032 public static final IRegistry dispenseBehaviorRegistry = new RegistryDefaulted(new BehaviorDefaultDispenseItem()); 033 protected Random random = new Random(); 034 @SideOnly(Side.CLIENT) 035 protected Icon furnaceTopIcon; 036 @SideOnly(Side.CLIENT) 037 protected Icon furnaceFrontIcon; 038 @SideOnly(Side.CLIENT) 039 protected Icon field_96473_e; 040 041 protected BlockDispenser(int par1) 042 { 043 super(par1, Material.rock); 044 this.setCreativeTab(CreativeTabs.tabRedstone); 045 } 046 047 /** 048 * How many world ticks before ticking 049 */ 050 public int tickRate(World par1World) 051 { 052 return 4; 053 } 054 055 /** 056 * Called whenever the block is added into the world. Args: world, x, y, z 057 */ 058 public void onBlockAdded(World par1World, int par2, int par3, int par4) 059 { 060 super.onBlockAdded(par1World, par2, par3, par4); 061 this.setDispenserDefaultDirection(par1World, par2, par3, par4); 062 } 063 064 /** 065 * sets Dispenser block direction so that the front faces an non-opaque block; chooses west to be direction if all 066 * surrounding blocks are opaque. 067 */ 068 private void setDispenserDefaultDirection(World par1World, int par2, int par3, int par4) 069 { 070 if (!par1World.isRemote) 071 { 072 int l = par1World.getBlockId(par2, par3, par4 - 1); 073 int i1 = par1World.getBlockId(par2, par3, par4 + 1); 074 int j1 = par1World.getBlockId(par2 - 1, par3, par4); 075 int k1 = par1World.getBlockId(par2 + 1, par3, par4); 076 byte b0 = 3; 077 078 if (Block.opaqueCubeLookup[l] && !Block.opaqueCubeLookup[i1]) 079 { 080 b0 = 3; 081 } 082 083 if (Block.opaqueCubeLookup[i1] && !Block.opaqueCubeLookup[l]) 084 { 085 b0 = 2; 086 } 087 088 if (Block.opaqueCubeLookup[j1] && !Block.opaqueCubeLookup[k1]) 089 { 090 b0 = 5; 091 } 092 093 if (Block.opaqueCubeLookup[k1] && !Block.opaqueCubeLookup[j1]) 094 { 095 b0 = 4; 096 } 097 098 par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 2); 099 } 100 } 101 102 @SideOnly(Side.CLIENT) 103 104 /** 105 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata 106 */ 107 public Icon getIcon(int par1, int par2) 108 { 109 int k = par2 & 7; 110 return par1 == k ? (k != 1 && k != 0 ? this.furnaceFrontIcon : this.field_96473_e) : (k != 1 && k != 0 ? (par1 != 1 && par1 != 0 ? this.blockIcon : this.furnaceTopIcon) : this.furnaceTopIcon); 111 } 112 113 @SideOnly(Side.CLIENT) 114 115 /** 116 * When this method is called, your block should register all the icons it needs with the given IconRegister. This 117 * is the only chance you get to register icons. 118 */ 119 public void registerIcons(IconRegister par1IconRegister) 120 { 121 this.blockIcon = par1IconRegister.registerIcon("furnace_side"); 122 this.furnaceTopIcon = par1IconRegister.registerIcon("furnace_top"); 123 this.furnaceFrontIcon = par1IconRegister.registerIcon("dispenser_front"); 124 this.field_96473_e = par1IconRegister.registerIcon("dispenser_front_vertical"); 125 } 126 127 /** 128 * Called upon block activation (right click on the block.) 129 */ 130 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) 131 { 132 if (par1World.isRemote) 133 { 134 return true; 135 } 136 else 137 { 138 TileEntityDispenser tileentitydispenser = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4); 139 140 if (tileentitydispenser != null) 141 { 142 par5EntityPlayer.displayGUIDispenser(tileentitydispenser); 143 } 144 145 return true; 146 } 147 } 148 149 protected void dispense(World par1World, int par2, int par3, int par4) 150 { 151 BlockSourceImpl blocksourceimpl = new BlockSourceImpl(par1World, par2, par3, par4); 152 TileEntityDispenser tileentitydispenser = (TileEntityDispenser)blocksourceimpl.getBlockTileEntity(); 153 154 if (tileentitydispenser != null) 155 { 156 int l = tileentitydispenser.getRandomStackFromInventory(); 157 158 if (l < 0) 159 { 160 par1World.playAuxSFX(1001, par2, par3, par4, 0); 161 } 162 else 163 { 164 ItemStack itemstack = tileentitydispenser.getStackInSlot(l); 165 IBehaviorDispenseItem ibehaviordispenseitem = this.getBehaviorForItemStack(itemstack); 166 167 if (ibehaviordispenseitem != IBehaviorDispenseItem.itemDispenseBehaviorProvider) 168 { 169 ItemStack itemstack1 = ibehaviordispenseitem.dispense(blocksourceimpl, itemstack); 170 tileentitydispenser.setInventorySlotContents(l, itemstack1.stackSize == 0 ? null : itemstack1); 171 } 172 } 173 } 174 } 175 176 /** 177 * Returns the behavior for the given ItemStack. 178 */ 179 protected IBehaviorDispenseItem getBehaviorForItemStack(ItemStack par1ItemStack) 180 { 181 return (IBehaviorDispenseItem)dispenseBehaviorRegistry.func_82594_a(par1ItemStack.getItem()); 182 } 183 184 /** 185 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 186 * their own) Args: x, y, z, neighbor blockID 187 */ 188 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 189 { 190 boolean flag = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4); 191 int i1 = par1World.getBlockMetadata(par2, par3, par4); 192 boolean flag1 = (i1 & 8) != 0; 193 194 if (flag && !flag1) 195 { 196 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate(par1World)); 197 par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 | 8, 4); 198 } 199 else if (!flag && flag1) 200 { 201 par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 & -9, 4); 202 } 203 } 204 205 /** 206 * Ticks the block if it's been scheduled 207 */ 208 public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random) 209 { 210 if (!par1World.isRemote) 211 { 212 this.dispense(par1World, par2, par3, par4); 213 } 214 } 215 216 /** 217 * Returns a new instance of a block's tile entity class. Called on placing the block. 218 */ 219 public TileEntity createNewTileEntity(World par1World) 220 { 221 return new TileEntityDispenser(); 222 } 223 224 /** 225 * Called when the block is placed in the world. 226 */ 227 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack) 228 { 229 int l = BlockPistonBase.determineOrientation(par1World, par2, par3, par4, par5EntityLiving); 230 par1World.setBlockMetadataWithNotify(par2, par3, par4, l, 2); 231 232 if (par6ItemStack.hasDisplayName()) 233 { 234 ((TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4)).func_94049_a(par6ItemStack.getDisplayName()); 235 } 236 } 237 238 /** 239 * ejects contained items into the world, and notifies neighbours of an update, as appropriate 240 */ 241 public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6) 242 { 243 TileEntityDispenser tileentitydispenser = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4); 244 245 if (tileentitydispenser != null) 246 { 247 for (int j1 = 0; j1 < tileentitydispenser.getSizeInventory(); ++j1) 248 { 249 ItemStack itemstack = tileentitydispenser.getStackInSlot(j1); 250 251 if (itemstack != null) 252 { 253 float f = this.random.nextFloat() * 0.8F + 0.1F; 254 float f1 = this.random.nextFloat() * 0.8F + 0.1F; 255 float f2 = this.random.nextFloat() * 0.8F + 0.1F; 256 257 while (itemstack.stackSize > 0) 258 { 259 int k1 = this.random.nextInt(21) + 10; 260 261 if (k1 > itemstack.stackSize) 262 { 263 k1 = itemstack.stackSize; 264 } 265 266 itemstack.stackSize -= k1; 267 EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage())); 268 269 if (itemstack.hasTagCompound()) 270 { 271 entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy()); 272 } 273 274 float f3 = 0.05F; 275 entityitem.motionX = (double)((float)this.random.nextGaussian() * f3); 276 entityitem.motionY = (double)((float)this.random.nextGaussian() * f3 + 0.2F); 277 entityitem.motionZ = (double)((float)this.random.nextGaussian() * f3); 278 par1World.spawnEntityInWorld(entityitem); 279 } 280 } 281 } 282 283 par1World.func_96440_m(par2, par3, par4, par5); 284 } 285 286 super.breakBlock(par1World, par2, par3, par4, par5, par6); 287 } 288 289 public static IPosition getIPositionFromBlockSource(IBlockSource par0IBlockSource) 290 { 291 EnumFacing enumfacing = getFacing(par0IBlockSource.getBlockMetadata()); 292 double d0 = par0IBlockSource.getX() + 0.7D * (double)enumfacing.getFrontOffsetX(); 293 double d1 = par0IBlockSource.getY() + 0.7D * (double)enumfacing.getFrontOffsetY(); 294 double d2 = par0IBlockSource.getZ() + 0.7D * (double)enumfacing.getFrontOffsetZ(); 295 return new PositionImpl(d0, d1, d2); 296 } 297 298 public static EnumFacing getFacing(int par0) 299 { 300 return EnumFacing.getFront(par0 & 7); 301 } 302 303 /** 304 * If this returns true, then comparators facing away from this block will use the value from 305 * getComparatorInputOverride instead of the actual redstone signal strength. 306 */ 307 public boolean hasComparatorInputOverride() 308 { 309 return true; 310 } 311 312 /** 313 * If hasComparatorInputOverride returns true, the return value from this is used instead of the redstone signal 314 * strength when this block inputs to a comparator. 315 */ 316 public int getComparatorInputOverride(World par1World, int par2, int par3, int par4, int par5) 317 { 318 return Container.func_94526_b((IInventory)par1World.getBlockTileEntity(par2, par3, par4)); 319 } 320}