001 package net.minecraft.block; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import java.util.Random; 006 import net.minecraft.block.material.Material; 007 import net.minecraft.creativetab.CreativeTabs; 008 import net.minecraft.dispenser.BehaviorDefaultDispenseItem; 009 import net.minecraft.dispenser.IBehaviorDispenseItem; 010 import net.minecraft.dispenser.IBlockSource; 011 import net.minecraft.dispenser.IPosition; 012 import net.minecraft.dispenser.IRegistry; 013 import net.minecraft.dispenser.PositionImpl; 014 import net.minecraft.dispenser.RegistryDefaulted; 015 import net.minecraft.entity.EntityLiving; 016 import net.minecraft.entity.item.EntityItem; 017 import net.minecraft.entity.player.EntityPlayer; 018 import net.minecraft.item.ItemStack; 019 import net.minecraft.nbt.NBTTagCompound; 020 import net.minecraft.tileentity.TileEntity; 021 import net.minecraft.tileentity.TileEntityDispenser; 022 import net.minecraft.util.EnumFacing; 023 import net.minecraft.util.MathHelper; 024 import net.minecraft.world.IBlockAccess; 025 import net.minecraft.world.World; 026 027 public class BlockDispenser extends BlockContainer 028 { 029 /** Registry for all dispense behaviors. */ 030 public static final IRegistry dispenseBehaviorRegistry = new RegistryDefaulted(new BehaviorDefaultDispenseItem()); 031 private Random random = new Random(); 032 033 protected BlockDispenser(int par1) 034 { 035 super(par1, Material.rock); 036 this.blockIndexInTexture = 45; 037 this.setCreativeTab(CreativeTabs.tabRedstone); 038 } 039 040 /** 041 * How many world ticks before ticking 042 */ 043 public int tickRate() 044 { 045 return 4; 046 } 047 048 /** 049 * Returns the ID of the items to drop on destruction. 050 */ 051 public int idDropped(int par1, Random par2Random, int par3) 052 { 053 return Block.dispenser.blockID; 054 } 055 056 /** 057 * Called whenever the block is added into the world. Args: world, x, y, z 058 */ 059 public void onBlockAdded(World par1World, int par2, int par3, int par4) 060 { 061 super.onBlockAdded(par1World, par2, par3, par4); 062 this.setDispenserDefaultDirection(par1World, par2, par3, par4); 063 } 064 065 /** 066 * sets Dispenser block direction so that the front faces an non-opaque block; chooses west to be direction if all 067 * surrounding blocks are opaque. 068 */ 069 private void setDispenserDefaultDirection(World par1World, int par2, int par3, int par4) 070 { 071 if (!par1World.isRemote) 072 { 073 int var5 = par1World.getBlockId(par2, par3, par4 - 1); 074 int var6 = par1World.getBlockId(par2, par3, par4 + 1); 075 int var7 = par1World.getBlockId(par2 - 1, par3, par4); 076 int var8 = par1World.getBlockId(par2 + 1, par3, par4); 077 byte var9 = 3; 078 079 if (Block.opaqueCubeLookup[var5] && !Block.opaqueCubeLookup[var6]) 080 { 081 var9 = 3; 082 } 083 084 if (Block.opaqueCubeLookup[var6] && !Block.opaqueCubeLookup[var5]) 085 { 086 var9 = 2; 087 } 088 089 if (Block.opaqueCubeLookup[var7] && !Block.opaqueCubeLookup[var8]) 090 { 091 var9 = 5; 092 } 093 094 if (Block.opaqueCubeLookup[var8] && !Block.opaqueCubeLookup[var7]) 095 { 096 var9 = 4; 097 } 098 099 par1World.setBlockMetadataWithNotify(par2, par3, par4, var9); 100 } 101 } 102 103 @SideOnly(Side.CLIENT) 104 105 /** 106 * Retrieves the block texture to use based on the display side. Args: iBlockAccess, x, y, z, side 107 */ 108 public int getBlockTexture(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5) 109 { 110 if (par5 == 1) 111 { 112 return this.blockIndexInTexture + 17; 113 } 114 else if (par5 == 0) 115 { 116 return this.blockIndexInTexture + 17; 117 } 118 else 119 { 120 int var6 = par1IBlockAccess.getBlockMetadata(par2, par3, par4); 121 return par5 == var6 ? this.blockIndexInTexture + 1 : this.blockIndexInTexture; 122 } 123 } 124 125 /** 126 * Returns the block texture based on the side being looked at. Args: side 127 */ 128 public int getBlockTextureFromSide(int par1) 129 { 130 return par1 == 1 ? this.blockIndexInTexture + 17 : (par1 == 0 ? this.blockIndexInTexture + 17 : (par1 == 3 ? this.blockIndexInTexture + 1 : this.blockIndexInTexture)); 131 } 132 133 /** 134 * Called upon block activation (right click on the block.) 135 */ 136 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9) 137 { 138 if (par1World.isRemote) 139 { 140 return true; 141 } 142 else 143 { 144 TileEntityDispenser var10 = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4); 145 146 if (var10 != null) 147 { 148 par5EntityPlayer.displayGUIDispenser(var10); 149 } 150 151 return true; 152 } 153 } 154 155 private void dispense(World par1World, int par2, int par3, int par4) 156 { 157 BlockSourceImpl var5 = new BlockSourceImpl(par1World, par2, par3, par4); 158 TileEntityDispenser var6 = (TileEntityDispenser)var5.func_82619_j(); 159 160 if (var6 != null) 161 { 162 int var7 = var6.getRandomStackFromInventory(); 163 164 if (var7 < 0) 165 { 166 par1World.playAuxSFX(1001, par2, par3, par4, 0); 167 } 168 else 169 { 170 ItemStack var8 = var6.getStackInSlot(var7); 171 IBehaviorDispenseItem var9 = (IBehaviorDispenseItem)dispenseBehaviorRegistry.func_82594_a(var8.getItem()); 172 173 if (var9 != IBehaviorDispenseItem.itemDispenseBehaviorProvider) 174 { 175 ItemStack var10 = var9.dispense(var5, var8); 176 var6.setInventorySlotContents(var7, var10.stackSize == 0 ? null : var10); 177 } 178 } 179 } 180 } 181 182 /** 183 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are 184 * their own) Args: x, y, z, neighbor blockID 185 */ 186 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5) 187 { 188 if (par5 > 0 && Block.blocksList[par5].canProvidePower()) 189 { 190 boolean var6 = par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4); 191 192 if (var6) 193 { 194 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate()); 195 } 196 } 197 } 198 199 /** 200 * Ticks the block if it's been scheduled 201 */ 202 public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random) 203 { 204 if (!par1World.isRemote && (par1World.isBlockIndirectlyGettingPowered(par2, par3, par4) || par1World.isBlockIndirectlyGettingPowered(par2, par3 + 1, par4))) 205 { 206 this.dispense(par1World, par2, par3, par4); 207 } 208 } 209 210 /** 211 * Returns a new instance of a block's tile entity class. Called on placing the block. 212 */ 213 public TileEntity createNewTileEntity(World par1World) 214 { 215 return new TileEntityDispenser(); 216 } 217 218 /** 219 * Called when the block is placed in the world. 220 */ 221 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving) 222 { 223 int var6 = MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3; 224 225 if (var6 == 0) 226 { 227 par1World.setBlockMetadataWithNotify(par2, par3, par4, 2); 228 } 229 230 if (var6 == 1) 231 { 232 par1World.setBlockMetadataWithNotify(par2, par3, par4, 5); 233 } 234 235 if (var6 == 2) 236 { 237 par1World.setBlockMetadataWithNotify(par2, par3, par4, 3); 238 } 239 240 if (var6 == 3) 241 { 242 par1World.setBlockMetadataWithNotify(par2, par3, par4, 4); 243 } 244 } 245 246 /** 247 * ejects contained items into the world, and notifies neighbours of an update, as appropriate 248 */ 249 public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6) 250 { 251 TileEntityDispenser var7 = (TileEntityDispenser)par1World.getBlockTileEntity(par2, par3, par4); 252 253 if (var7 != null) 254 { 255 for (int var8 = 0; var8 < var7.getSizeInventory(); ++var8) 256 { 257 ItemStack var9 = var7.getStackInSlot(var8); 258 259 if (var9 != null) 260 { 261 float var10 = this.random.nextFloat() * 0.8F + 0.1F; 262 float var11 = this.random.nextFloat() * 0.8F + 0.1F; 263 float var12 = this.random.nextFloat() * 0.8F + 0.1F; 264 265 while (var9.stackSize > 0) 266 { 267 int var13 = this.random.nextInt(21) + 10; 268 269 if (var13 > var9.stackSize) 270 { 271 var13 = var9.stackSize; 272 } 273 274 var9.stackSize -= var13; 275 EntityItem var14 = new EntityItem(par1World, (double)((float)par2 + var10), (double)((float)par3 + var11), (double)((float)par4 + var12), new ItemStack(var9.itemID, var13, var9.getItemDamage())); 276 277 if (var9.hasTagCompound()) 278 { 279 var14.func_92014_d().setTagCompound((NBTTagCompound)var9.getTagCompound().copy()); 280 } 281 282 float var15 = 0.05F; 283 var14.motionX = (double)((float)this.random.nextGaussian() * var15); 284 var14.motionY = (double)((float)this.random.nextGaussian() * var15 + 0.2F); 285 var14.motionZ = (double)((float)this.random.nextGaussian() * var15); 286 par1World.spawnEntityInWorld(var14); 287 } 288 } 289 } 290 } 291 292 super.breakBlock(par1World, par2, par3, par4, par5, par6); 293 } 294 295 public static IPosition func_82525_a(IBlockSource par0IBlockSource) 296 { 297 EnumFacing var1 = EnumFacing.func_82600_a(par0IBlockSource.func_82620_h()); 298 double var2 = par0IBlockSource.getX() + 0.7D * (double)var1.func_82601_c(); 299 double var4 = par0IBlockSource.getY(); 300 double var6 = par0IBlockSource.getZ() + 0.7D * (double)var1.func_82599_e(); 301 return new PositionImpl(var2, var4, var6); 302 } 303 }