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 field_94463_c; 036 @SideOnly(Side.CLIENT) 037 protected Icon field_94462_cO; 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 getBlockTextureFromSideAndMetadata(int par1, int par2) 108 { 109 int k = par2 & 7; 110 return par1 == k ? (k != 1 && k != 0 ? this.field_94462_cO : this.field_96473_e) : (k != 1 && k != 0 ? (par1 != 1 && par1 != 0 ? this.field_94336_cN : this.field_94463_c) : this.field_94463_c); 111 } 112 113 @SideOnly(Side.CLIENT) 114 public void func_94332_a(IconRegister par1IconRegister) 115 { 116 this.field_94336_cN = par1IconRegister.func_94245_a("furnace_side"); 117 this.field_94463_c = par1IconRegister.func_94245_a("furnace_top"); 118 this.field_94462_cO = par1IconRegister.func_94245_a("dispenser_front"); 119 this.field_96473_e = par1IconRegister.func_94245_a("dispenser_front_vertical"); 120 } 121 122 /** 123 * Called upon block activation (right click on the block.) 124 */ 125 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) 126 { 127 if (par1World.isRemote) 128 { 129 return true; 130 } 131 else 132 { 133 TileEntityDispenser tileentitydispenser = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4); 134 135 if (tileentitydispenser != null) 136 { 137 par5EntityPlayer.displayGUIDispenser(tileentitydispenser); 138 } 139 140 return true; 141 } 142 } 143 144 protected void dispense(World par1World, int par2, int par3, int par4) 145 { 146 BlockSourceImpl blocksourceimpl = new BlockSourceImpl(par1World, par2, par3, par4); 147 TileEntityDispenser tileentitydispenser = (TileEntityDispenser)blocksourceimpl.func_82619_j(); 148 149 if (tileentitydispenser != null) 150 { 151 int l = tileentitydispenser.getRandomStackFromInventory(); 152 153 if (l < 0) 154 { 155 par1World.playAuxSFX(1001, par2, par3, par4, 0); 156 } 157 else 158 { 159 ItemStack itemstack = tileentitydispenser.getStackInSlot(l); 160 IBehaviorDispenseItem ibehaviordispenseitem = this.func_96472_a(itemstack); 161 162 if (ibehaviordispenseitem != IBehaviorDispenseItem.itemDispenseBehaviorProvider) 163 { 164 ItemStack itemstack1 = ibehaviordispenseitem.dispense(blocksourceimpl, itemstack); 165 tileentitydispenser.setInventorySlotContents(l, itemstack1.stackSize == 0 ? null : itemstack1); 166 } 167 } 168 } 169 } 170 171 protected IBehaviorDispenseItem func_96472_a(ItemStack par1ItemStack) 172 { 173 return (IBehaviorDispenseItem)dispenseBehaviorRegistry.func_82594_a(par1ItemStack.getItem()); 174 } 175 176 /** 177 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 178 * their own) Args: x, y, z, neighbor blockID 179 */ 180 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 181 { 182 boolean flag = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4); 183 int i1 = par1World.getBlockMetadata(par2, par3, par4); 184 boolean flag1 = (i1 & 8) != 0; 185 186 if (flag && !flag1) 187 { 188 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate(par1World)); 189 par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 | 8, 4); 190 } 191 else if (!flag && flag1) 192 { 193 par1World.setBlockMetadataWithNotify(par2, par3, par4, i1 & -9, 4); 194 } 195 } 196 197 /** 198 * Ticks the block if it's been scheduled 199 */ 200 public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random) 201 { 202 if (!par1World.isRemote) 203 { 204 this.dispense(par1World, par2, par3, par4); 205 } 206 } 207 208 /** 209 * Returns a new instance of a block's tile entity class. Called on placing the block. 210 */ 211 public TileEntity createNewTileEntity(World par1World) 212 { 213 return new TileEntityDispenser(); 214 } 215 216 /** 217 * Called when the block is placed in the world. 218 */ 219 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving, ItemStack par6ItemStack) 220 { 221 int l = BlockPistonBase.determineOrientation(par1World, par2, par3, par4, par5EntityLiving); 222 par1World.setBlockMetadataWithNotify(par2, par3, par4, l, 2); 223 224 if (par6ItemStack.hasDisplayName()) 225 { 226 ((TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4)).func_94049_a(par6ItemStack.getDisplayName()); 227 } 228 } 229 230 /** 231 * ejects contained items into the world, and notifies neighbours of an update, as appropriate 232 */ 233 public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6) 234 { 235 TileEntityDispenser tileentitydispenser = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4); 236 237 if (tileentitydispenser != null) 238 { 239 for (int j1 = 0; j1 < tileentitydispenser.getSizeInventory(); ++j1) 240 { 241 ItemStack itemstack = tileentitydispenser.getStackInSlot(j1); 242 243 if (itemstack != null) 244 { 245 float f = this.random.nextFloat() * 0.8F + 0.1F; 246 float f1 = this.random.nextFloat() * 0.8F + 0.1F; 247 float f2 = this.random.nextFloat() * 0.8F + 0.1F; 248 249 while (itemstack.stackSize > 0) 250 { 251 int k1 = this.random.nextInt(21) + 10; 252 253 if (k1 > itemstack.stackSize) 254 { 255 k1 = itemstack.stackSize; 256 } 257 258 itemstack.stackSize -= k1; 259 EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage())); 260 261 if (itemstack.hasTagCompound()) 262 { 263 entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy()); 264 } 265 266 float f3 = 0.05F; 267 entityitem.motionX = (double)((float)this.random.nextGaussian() * f3); 268 entityitem.motionY = (double)((float)this.random.nextGaussian() * f3 + 0.2F); 269 entityitem.motionZ = (double)((float)this.random.nextGaussian() * f3); 270 par1World.spawnEntityInWorld(entityitem); 271 } 272 } 273 } 274 } 275 276 super.breakBlock(par1World, par2, par3, par4, par5, par6); 277 } 278 279 public static IPosition getIPositionFromBlockSource(IBlockSource par0IBlockSource) 280 { 281 EnumFacing enumfacing = func_100009_j_(par0IBlockSource.func_82620_h()); 282 double d0 = par0IBlockSource.getX() + 0.7D * (double)enumfacing.getFrontOffsetX(); 283 double d1 = par0IBlockSource.getY() + 0.7D * (double)enumfacing.func_96559_d(); 284 double d2 = par0IBlockSource.getZ() + 0.7D * (double)enumfacing.getFrontOffsetZ(); 285 return new PositionImpl(d0, d1, d2); 286 } 287 288 public static EnumFacing func_100009_j_(int par0) 289 { 290 return EnumFacing.getFront(par0 & 7); 291 } 292 293 public boolean func_96468_q_() 294 { 295 return true; 296 } 297 298 public int func_94328_b_(World par1World, int par2, int par3, int par4, int par5) 299 { 300 return Container.func_94526_b((IInventory)par1World.getBlockTileEntity(par2, par3, par4)); 301 } 302}