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 }