001 package net.minecraft.src;
002
003 import cpw.mods.fml.common.Side;
004 import cpw.mods.fml.common.asm.SideOnly;
005 import java.util.Random;
006
007 public class BlockRedstoneRepeater extends BlockDirectional
008 {
009 /** The offsets for the two torches in redstone repeater blocks. */
010 public static final double[] repeaterTorchOffset = new double[] { -0.0625D, 0.0625D, 0.1875D, 0.3125D};
011
012 /** The states in which the redstone repeater blocks can be. */
013 private static final int[] repeaterState = new int[] {1, 2, 3, 4};
014
015 /** Tells whether the repeater is powered or not */
016 private final boolean isRepeaterPowered;
017
018 protected BlockRedstoneRepeater(int par1, boolean par2)
019 {
020 super(par1, 6, Material.circuits);
021 this.isRepeaterPowered = par2;
022 this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
023 }
024
025 /**
026 * If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
027 */
028 public boolean renderAsNormalBlock()
029 {
030 return false;
031 }
032
033 /**
034 * Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
035 */
036 public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
037 {
038 return !par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) ? false : super.canPlaceBlockAt(par1World, par2, par3, par4);
039 }
040
041 /**
042 * Can this block stay at this position. Similar to canPlaceBlockAt except gets checked often with plants.
043 */
044 public boolean canBlockStay(World par1World, int par2, int par3, int par4)
045 {
046 return !par1World.doesBlockHaveSolidTopSurface(par2, par3 - 1, par4) ? false : super.canBlockStay(par1World, par2, par3, par4);
047 }
048
049 /**
050 * Ticks the block if it's been scheduled
051 */
052 public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
053 {
054 int var6 = par1World.getBlockMetadata(par2, par3, par4);
055 boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6);
056
057 if (this.isRepeaterPowered && !var7)
058 {
059 par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterIdle.blockID, var6);
060 }
061 else if (!this.isRepeaterPowered)
062 {
063 par1World.setBlockAndMetadataWithNotify(par2, par3, par4, Block.redstoneRepeaterActive.blockID, var6);
064
065 if (!var7)
066 {
067 int var8 = (var6 & 12) >> 2;
068 par1World.scheduleBlockUpdate(par2, par3, par4, Block.redstoneRepeaterActive.blockID, repeaterState[var8] * 2);
069 }
070 }
071 }
072
073 /**
074 * From the specified side and block metadata retrieves the blocks texture. Args: side, metadata
075 */
076 public int getBlockTextureFromSideAndMetadata(int par1, int par2)
077 {
078 return par1 == 0 ? (this.isRepeaterPowered ? 99 : 115) : (par1 == 1 ? (this.isRepeaterPowered ? 147 : 131) : 5);
079 }
080
081 @SideOnly(Side.CLIENT)
082
083 /**
084 * Returns true if the given side of this block type should be rendered, if the adjacent block is at the given
085 * coordinates. Args: blockAccess, x, y, z, side
086 */
087 public boolean shouldSideBeRendered(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
088 {
089 return par5 != 0 && par5 != 1;
090 }
091
092 /**
093 * The type of render function that is called for this block
094 */
095 public int getRenderType()
096 {
097 return 15;
098 }
099
100 /**
101 * Returns the block texture based on the side being looked at. Args: side
102 */
103 public int getBlockTextureFromSide(int par1)
104 {
105 return this.getBlockTextureFromSideAndMetadata(par1, 0);
106 }
107
108 /**
109 * Is this block indirectly powering the block on the specified side
110 */
111 public boolean isIndirectlyPoweringTo(World par1World, int par2, int par3, int par4, int par5)
112 {
113 return this.isPoweringTo(par1World, par2, par3, par4, par5);
114 }
115
116 /**
117 * Is this block powering the block on the specified side
118 */
119 public boolean isPoweringTo(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
120 {
121 if (!this.isRepeaterPowered)
122 {
123 return false;
124 }
125 else
126 {
127 int var6 = getDirection(par1IBlockAccess.getBlockMetadata(par2, par3, par4));
128 return var6 == 0 && par5 == 3 ? true : (var6 == 1 && par5 == 4 ? true : (var6 == 2 && par5 == 2 ? true : var6 == 3 && par5 == 5));
129 }
130 }
131
132 /**
133 * Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
134 * their own) Args: x, y, z, neighbor blockID
135 */
136 public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
137 {
138 if (!this.canBlockStay(par1World, par2, par3, par4))
139 {
140 this.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
141 par1World.setBlockWithNotify(par2, par3, par4, 0);
142 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
143 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
144 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
145 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
146 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
147 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
148 }
149 else
150 {
151 int var6 = par1World.getBlockMetadata(par2, par3, par4);
152 boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6);
153 int var8 = (var6 & 12) >> 2;
154
155 if (this.isRepeaterPowered && !var7 || !this.isRepeaterPowered && var7)
156 {
157 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, repeaterState[var8] * 2);
158 }
159 }
160 }
161
162 private boolean ignoreTick(World par1World, int par2, int par3, int par4, int par5)
163 {
164 int var6 = getDirection(par5);
165
166 switch (var6)
167 {
168 case 0:
169 return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 + 1, 3) || par1World.getBlockId(par2, par3, par4 + 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 + 1) > 0;
170 case 1:
171 return par1World.isBlockIndirectlyProvidingPowerTo(par2 - 1, par3, par4, 4) || par1World.getBlockId(par2 - 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 - 1, par3, par4) > 0;
172 case 2:
173 return par1World.isBlockIndirectlyProvidingPowerTo(par2, par3, par4 - 1, 2) || par1World.getBlockId(par2, par3, par4 - 1) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2, par3, par4 - 1) > 0;
174 case 3:
175 return par1World.isBlockIndirectlyProvidingPowerTo(par2 + 1, par3, par4, 5) || par1World.getBlockId(par2 + 1, par3, par4) == Block.redstoneWire.blockID && par1World.getBlockMetadata(par2 + 1, par3, par4) > 0;
176 default:
177 return false;
178 }
179 }
180
181 /**
182 * Called upon block activation (right click on the block.)
183 */
184 public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
185 {
186 int var10 = par1World.getBlockMetadata(par2, par3, par4);
187 int var11 = (var10 & 12) >> 2;
188 var11 = var11 + 1 << 2 & 12;
189 par1World.setBlockMetadataWithNotify(par2, par3, par4, var11 | var10 & 3);
190 return true;
191 }
192
193 /**
194 * Can this block provide power. Only wire currently seems to have this change based on its state.
195 */
196 public boolean canProvidePower()
197 {
198 return true;
199 }
200
201 /**
202 * Called when the block is placed in the world.
203 */
204 public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLiving par5EntityLiving)
205 {
206 int var6 = ((MathHelper.floor_double((double)(par5EntityLiving.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3) + 2) % 4;
207 par1World.setBlockMetadataWithNotify(par2, par3, par4, var6);
208 boolean var7 = this.ignoreTick(par1World, par2, par3, par4, var6);
209
210 if (var7)
211 {
212 par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, 1);
213 }
214 }
215
216 /**
217 * Called whenever the block is added into the world. Args: world, x, y, z
218 */
219 public void onBlockAdded(World par1World, int par2, int par3, int par4)
220 {
221 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
222 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
223 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
224 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
225 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
226 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
227 }
228
229 /**
230 * Called right before the block is destroyed by a player. Args: world, x, y, z, metaData
231 */
232 public void onBlockDestroyedByPlayer(World par1World, int par2, int par3, int par4, int par5)
233 {
234 if (this.isRepeaterPowered)
235 {
236 par1World.notifyBlocksOfNeighborChange(par2 + 1, par3, par4, this.blockID);
237 par1World.notifyBlocksOfNeighborChange(par2 - 1, par3, par4, this.blockID);
238 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 + 1, this.blockID);
239 par1World.notifyBlocksOfNeighborChange(par2, par3, par4 - 1, this.blockID);
240 par1World.notifyBlocksOfNeighborChange(par2, par3 - 1, par4, this.blockID);
241 par1World.notifyBlocksOfNeighborChange(par2, par3 + 1, par4, this.blockID);
242 }
243
244 super.onBlockDestroyedByPlayer(par1World, par2, par3, par4, par5);
245 }
246
247 /**
248 * Is this block (a) opaque and (b) a full 1m cube? This determines whether or not to render the shared face of two
249 * adjacent blocks and also whether the player can attach torches, redstone wire, etc to this block.
250 */
251 public boolean isOpaqueCube()
252 {
253 return false;
254 }
255
256 /**
257 * Returns the ID of the items to drop on destruction.
258 */
259 public int idDropped(int par1, Random par2Random, int par3)
260 {
261 return Item.redstoneRepeater.shiftedIndex;
262 }
263
264 @SideOnly(Side.CLIENT)
265
266 /**
267 * A randomly called display update to be able to add particles or other items for display
268 */
269 public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
270 {
271 if (this.isRepeaterPowered)
272 {
273 int var6 = par1World.getBlockMetadata(par2, par3, par4);
274 int var7 = getDirection(var6);
275 double var8 = (double)((float)par2 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
276 double var10 = (double)((float)par3 + 0.4F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
277 double var12 = (double)((float)par4 + 0.5F) + (double)(par5Random.nextFloat() - 0.5F) * 0.2D;
278 double var14 = 0.0D;
279 double var16 = 0.0D;
280
281 if (par5Random.nextInt(2) == 0)
282 {
283 switch (var7)
284 {
285 case 0:
286 var16 = -0.3125D;
287 break;
288 case 1:
289 var14 = 0.3125D;
290 break;
291 case 2:
292 var16 = 0.3125D;
293 break;
294 case 3:
295 var14 = -0.3125D;
296 }
297 }
298 else
299 {
300 int var18 = (var6 & 12) >> 2;
301
302 switch (var7)
303 {
304 case 0:
305 var16 = repeaterTorchOffset[var18];
306 break;
307 case 1:
308 var14 = -repeaterTorchOffset[var18];
309 break;
310 case 2:
311 var16 = -repeaterTorchOffset[var18];
312 break;
313 case 3:
314 var14 = repeaterTorchOffset[var18];
315 }
316 }
317
318 par1World.spawnParticle("reddust", var8 + var14, var10, var12 + var16, 0.0D, 0.0D, 0.0D);
319 }
320 }
321
322 @SideOnly(Side.CLIENT)
323
324 /**
325 * only called by clickMiddleMouseButton , and passed to inventory.setCurrentItem (along with isCreative)
326 */
327 public int idPicked(World par1World, int par2, int par3, int par4)
328 {
329 return Item.redstoneRepeater.shiftedIndex;
330 }
331 }